Initial commit.

This commit is contained in:
Captain ALM 2022-06-14 04:23:04 +01:00
commit a97b32c9d4
Signed by: alfred
GPG Key ID: 4E4ADD02609997B1
25 changed files with 1890 additions and 0 deletions

30
.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Built files
out/
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,10 @@
<component name="ArtifactManager">
<artifact type="jar" build-on-make="true" name="calmnettest:jar">
<output-path>$PROJECT_DIR$/out/artifacts/calmnettest_jar</output-path>
<root id="archive" name="calmnettest.jar">
<element id="module-output" name="calmnettest" />
<element id="library" level="application" name="calmnetlib" />
<element id="library" level="application" name="calmstdcrypt" />
</root>
</artifact>
</component>

1
.idea/description.html Normal file
View File

@ -0,0 +1 @@
<html>Simple <b>Java</b> application that includes a class with <code>main()</code> method</html>

7
.idea/discord.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

6
.idea/encodings.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

12
.idea/misc.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="ProjectKey">
<option name="state" value="project://e2804f05-5315-4fc6-a121-c522a6c26470" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/calmnettest.iml" filepath="$PROJECT_DIR$/calmnettest.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,3 @@
<template>
<input-field default="com.company">IJ_BASE_PACKAGE</input-field>
</template>

124
.idea/uiDesigner.xml Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

29
LICENSE Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2022, Captain ALM
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Captain ALM Network Library Tester (Java)
This is the tester for the [calmnetlib](https://code.mrmelon54.xyz/alfred/calmnetlib) java library.
There is a keystore file with the password keystore containing a self-signed localhost certificate for testing.
This application targets Java 8.
(C) Captain ALM 2022 - Under the BSD 3-Clause License

13
calmnettest.iml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="calmstdcrypt" level="application" />
<orderEntry type="library" name="calmnetlib" level="application" />
</component>
</module>

BIN
keystore.jks Normal file

Binary file not shown.

3
src/META-INF/MANIFEST.MF Normal file
View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.captainalm.test.calmnet.Main

View File

@ -0,0 +1,66 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.packet.IPacket;
import com.captainalm.lib.calmnet.packet.PacketException;
import com.captainalm.lib.calmnet.packet.PacketProtocolInformation;
/**
* This class provides the acknowledgement packet.
*
* @author Captain ALM
*/
public class AKNPacket implements IPacket {
private static final PacketProtocolInformation protocol = new PacketProtocolInformation((byte) 1, (byte) 3);
/**
* Gets if the packet is valid.
*
* @return Is the packet valid?
*/
@Override
public boolean isValid() {
return true;
}
/**
* Gets the protocol information.
*
* @return The protocol information.
*/
@Override
public PacketProtocolInformation getProtocol() {
return protocol;
}
/**
* Gets the protocol information statically.
*
* @return The protocol information.
*/
public static PacketProtocolInformation getTheProtocol() {
return protocol;
}
/**
* Saves the packet payload to a byte array.
*
* @return The packet payload data.
* @throws PacketException An Exception has occurred.
*/
@Override
public byte[] savePayload() throws PacketException {
return new byte[0];
}
/**
* Loads the packet payload from save data.
*
* @param packetData The packet payload data.
* @throws NullPointerException The new store data is null.
* @throws PacketException An Exception has occurred.
*/
@Override
public void loadPayload(byte[] packetData) throws PacketException {
if (packetData == null) throw new NullPointerException("packetData is null");
}
}

View File

@ -0,0 +1,141 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.packet.IPacket;
import com.captainalm.lib.calmnet.packet.PacketException;
import com.captainalm.lib.calmnet.packet.PacketProtocolInformation;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Provides the data packet to store a byte array that can be backed to a file.
*
* @author Captain ALM
*/
public class DataPacket implements IPacket {
private static final PacketProtocolInformation protocol = new PacketProtocolInformation((byte) 1, (byte) 1);
protected File backingFile;
protected byte[] backedData;
protected final Object slock = new Object();
/**
* Constructs a new DataPacket with initial data.
*
* @param dataIn The data to initially use.
*/
public DataPacket(byte[] dataIn) {
backedData = dataIn;
}
/**
* Constructs a new DataPacket backed by a specified {@link Path}.
*
* @param path The path to back to.
*/
public DataPacket(Path path) {
if (path != null) backingFile = path.toFile();
}
/**
* Gets the backing file.
*
* @return The backing file or null.
*/
public File getBackingFile() {
return backingFile;
}
/**
* Gets if the packet is valid.
*
* @return Is the packet valid?
*/
@Override
public boolean isValid() {
synchronized (slock) {
return (backingFile == null) || (backedData != null);
}
}
/**
* Gets the protocol information.
*
* @return The protocol information.
*/
@Override
public PacketProtocolInformation getProtocol() {
return protocol;
}
/**
* Gets the protocol information statically.
*
* @return The protocol information.
*/
public static PacketProtocolInformation getTheProtocol() {
return protocol;
}
/**
* Unloads the stored data.
*/
public void unload() {
synchronized (slock) {
backedData = null;
}
}
/**
* Saves the packet payload to a byte array.
*
* @return The packet payload data.
* @throws PacketException An Exception has occurred.
*/
@Override
public byte[] savePayload() throws PacketException {
synchronized (slock) {
return internalSavePayload();
}
}
protected byte[] internalSavePayload() throws PacketException {
if (backedData == null && backingFile != null) {
try {
backedData = Files.readAllBytes(backingFile.toPath());
} catch (IOException | SecurityException e) {
throw new PacketException(e);
}
}
if (backedData == null) throw new PacketException("no data");
return backedData;
}
/**
* Loads the packet payload from save data.
*
* @param packetData The packet payload data.
* @throws NullPointerException The new store data is null.
* @throws PacketException An Exception has occurred.
*/
@Override
public void loadPayload(byte[] packetData) throws PacketException {
if (packetData == null) throw new NullPointerException("dataIn is null");
synchronized (slock) {
internalLoadPayload(packetData);
}
}
protected void internalLoadPayload(byte[] packetData) throws PacketException {
backedData = packetData;
if (backingFile != null) {
try {
Files.write(backingFile.toPath(), backedData);
} catch (IOException | SecurityException | UnsupportedOperationException e) {
throw new PacketException(e);
}
}
}
}

View File

@ -0,0 +1,458 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.SSLUtilities;
import com.captainalm.lib.calmnet.SSLUtilityException;
import com.captainalm.lib.calmnet.packet.IPacket;
import com.captainalm.lib.calmnet.packet.PacketException;
import com.captainalm.lib.calmnet.packet.core.NetworkSSLUpgradePacket;
import com.captainalm.utils.Console;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.Queue;
public final class Main {
private static NetworkRuntime runtime;
private static Thread recvThread;
private static boolean akned = false;
private final static Queue<DataPacket> packetQueue = new LinkedList<>();
private static SSLContext sslContext;
private static boolean isClient;
private static String sslHost;
private static int sendLoopsRemainingSetting;
private static int sendLoopWaitTime;
private static final Object slock = new Object();
public static void main(String[] args) {
header();
help();
boolean shouldExecuting = true;
while (shouldExecuting) {
char opt = Console.readCharacter();
switch (opt) {
case '0':
case 'h':
help();
break;
case '1':
case 'i':
info();
break;
case '2':
case 's':
start();
break;
case '3':
case 'd':
stop();
break;
case '4':
case 'm':
message();
break;
case '5':
case 'f':
send();
break;
case '6':
case 'p':
process();
break;
case '7':
case 'x':
sslSetup();
break;
case '8':
case 'u':
upgrade();
break;
case '9':
case 'a':
header();
break;
default:
shouldExecuting = false;
}
}
System.exit(0);
}
private static void start() {
if (runtime != null && runtime.isProcessing()) return;
Console.writeLine("Socket Setup:");
Console.writeLine("IP Address:");
InetAddress address = null;
try {
address = InetAddress.getByName(Console.readString());
Console.writeLine("Done ! ; Setting To: " + address.getHostAddress());
} catch (UnknownHostException e) {
Console.writeLine("Ignored! ; Setting To: null");
}
Console.writeLine("Port:");
Integer port = Console.readInt();
if (port == null || port < 0 || port > 65535) {
port = 0;
Console.writeLine("Ignored! ; Setting To: 0");
}
Console.writeLine("Use Fragmentation (Y/OTHER):");
char fopt = Console.readCharacter();
boolean fragmentation = (fopt == 'Y' || fopt == 'y');
boolean fverifyp = false;
if (fragmentation) {
Console.writeLine("Verify Fragment Payloads (Y/OTHER)");
fopt = Console.readCharacter();
fverifyp = (fopt == 'Y' || fopt == 'y');
}
Console.writeLine("Select Socket Mode:");
Console.writeLine("0) TCP Listen");
Console.writeLine("1) TCP Client");
Console.writeLine("2) UDP Listen");
Console.writeLine("3) UDP Client");
Console.writeLine("4) UDP Broadcast");
Console.writeLine("5) UDP Loopback Client");
Console.writeLine("6) UDP Loopback Broadcast");
Console.writeLine("7) SSL TCP Listen");
Console.writeLine("8) SSL TCP Client");
Console.writeLine("OTHER) Cancel");
char opt = Console.readCharacter();
Console.writeLine("Starting Socket...");
runtime = null;
switch (opt) {
case '0':
sendLoopsRemainingSetting = 1;
sendLoopWaitTime = 50;
try (ServerSocket serverSocket = new ServerSocket(port, 1, address)) {
Socket socket = serverSocket.accept();
runtime = new NetworkRuntime(socket, fragmentation, fverifyp);
isClient = false;
} catch (IOException e) {
e.printStackTrace();
}
break;
case '1':
sendLoopsRemainingSetting = 1;
sendLoopWaitTime = 50;
try {
Socket socket = new Socket(address, port);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp);
isClient = true;
} catch (IOException e) {
e.printStackTrace();
}
break;
case '2':
requestSendSettings();
try {
DatagramSocket socket = new DatagramSocket(port, address);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp, null, -1);
isClient = false;
} catch (SocketException e) {
e.printStackTrace();
}
break;
case '3':
requestSendSettings();
try {
DatagramSocket socket = new DatagramSocket();
runtime = new NetworkRuntime(socket, fragmentation, fverifyp, address, port);
isClient = true;
} catch (SocketException e) {
e.printStackTrace();
}
break;
case '4':
requestSendSettings();
try {
MulticastSocket socket = new MulticastSocket(port);
if (!socket.getLoopbackMode()) socket.setLoopbackMode(true);
socket.joinGroup(address);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp, address, port);
isClient = false;
} catch (IOException e) {
e.printStackTrace();
}
break;
case '5':
requestSendSettings();
try {
DatagramSocket socket = new DatagramSocket(port, address);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp, address, port);
isClient = true;
} catch (SocketException e) {
e.printStackTrace();
}
break;
case '6':
requestSendSettings();
try {
MulticastSocket socket = new MulticastSocket(port);
if (socket.getLoopbackMode()) socket.setLoopbackMode(false);
socket.joinGroup(address);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp, address, port);
isClient = false;
} catch (IOException e) {
e.printStackTrace();
}
break;
case '7':
sendLoopsRemainingSetting = 1;
sendLoopWaitTime = 50;
if (sslContext == null) break;
try (SSLServerSocket serverSocket = SSLUtilities.getSSLServerSocket(sslContext, port, 1, address)) {
Socket socket = serverSocket.accept();
runtime = new NetworkRuntime(socket, fragmentation, fverifyp);
isClient = false;
} catch (IOException | SSLUtilityException e) {
e.printStackTrace();
}
break;
case '8':
sendLoopsRemainingSetting = 1;
sendLoopWaitTime = 50;
if (sslContext == null) break;
try {
Socket socket = SSLUtilities.getSSLClientSocket(sslContext, sslHost, port);
runtime = new NetworkRuntime(socket, fragmentation, fverifyp);
isClient = true;
} catch (SSLUtilityException e) {
e.printStackTrace();
}
break;
}
if (runtime == null) {
Console.writeLine("!FAILED TO START!");
} else {
while (runtime.notReadyToSend()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
createAndStartRecvThread();
Console.writeLine("Socket Started.");
}
}
private static void requestSendSettings() {
Console.writeLine("Enter number of send retries:");
Integer num = Console.readInt();
if (num == null || num < 0) num = 0;
Console.writeLine("Send Retires set to: " + num);
sendLoopsRemainingSetting = num + 1;
Console.writeLine("Enter timeout before send retry (Milliseconds) :");
num = Console.readInt();
if (num == null || num < 50) num = 50;
Console.writeLine("Retry Send Timeout set to: " + num);
sendLoopWaitTime = num;
}
private static void createAndStartRecvThread() {
recvThread = new Thread(() -> {
PacketType nextType = null;
Path nextPath = null;
while (runtime != null && runtime.isProcessing()) {
IPacket packet;
while ((packet = runtime.receiveLastPacket()) != null) {
if (!packet.isValid()) continue;
if (packet instanceof TypePacket && nextType == null) {
nextType = ((TypePacket) packet).type;
runtime.sendPacket(new AKNPacket(), false);
}
if (packet instanceof DataPacket && nextType == PacketType.Message) {
nextType = null;
synchronized (slock) {
packetQueue.add((DataPacket) packet);
}
runtime.sendPacket(new AKNPacket(), false);
}
if (packet instanceof DataPacket && nextType == PacketType.Name) {
nextType = null;
try {
nextPath = new File(new String(packet.savePayload(), StandardCharsets.UTF_8)).toPath();
} catch (PacketException e) {
e.printStackTrace();
}
runtime.sendPacket(new AKNPacket(), false);
}
if (packet instanceof StreamedDataPacket && nextType == PacketType.Data && nextPath != null) {
nextType = null;
try (FileOutputStream outputStream = new FileOutputStream(nextPath.toFile())) {
((StreamedDataPacket) packet).readData(outputStream);
synchronized (slock) {
DataPacket p = new DataPacket(("Received File: " + nextPath.toAbsolutePath()).getBytes(StandardCharsets.UTF_8));
packetQueue.add(p);
}
} catch (IOException | PacketException e) {
e.printStackTrace();
} finally {
nextPath = null;
}
}
if (packet instanceof NetworkSSLUpgradePacket && sslContext != null) {
if (((NetworkSSLUpgradePacket) packet).isAcknowledgement()) {
runtime.sslUpgrade(sslContext, sslHost, isClient);
} else {
runtime.sendPacket(new NetworkSSLUpgradePacket(true), true);
runtime.sslUpgrade(sslContext, sslHost, isClient);
}
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}, "main_recv_thread");
recvThread.start();
}
private static void stop() {
if (runtime == null || !runtime.isProcessing()) return;
Console.writeLine("Socket Stopping...");
runtime.stopProcessing();
try {
recvThread.join();
} catch (InterruptedException e) {
}
runtime = null;
isClient = false;
Console.writeLine("Socket Stopped.");
}
private static boolean waitForAKN(IPacket packet) {
if (packet instanceof AKNPacket && packet.isValid()) {
akned = true;
return false;
}
return true;
}
private static void doAKNWait(IPacket packet) {
akned = false;
runtime.setPacketReceiveCallback(Main::waitForAKN);
int i = 0;
while (!akned) {
runtime.sendPacket(packet, false);
try {
Thread.sleep(sendLoopWaitTime);
} catch (InterruptedException e) {
}
if (++i >= sendLoopsRemainingSetting) akned = true;
}
runtime.setPacketReceiveCallback(null);
}
private static void message() {
if (runtime == null || !runtime.isProcessing()) return;
Console.writeLine("Message To Send:");
String message = Console.readString();
doAKNWait(new TypePacket(PacketType.Message));
DataPacket packet = new DataPacket(message.getBytes(StandardCharsets.UTF_8));
doAKNWait(packet);
Console.writeLine("!Message Sent!");
}
private static void send() {
if (runtime == null || !runtime.isProcessing()) return;
Console.writeLine("Path of File To Send:");
File file = new File(Console.readString());
if (file.exists()) {
doAKNWait(new TypePacket(PacketType.Name));
DataPacket packet = new DataPacket(file.getName().getBytes(StandardCharsets.UTF_8));
doAKNWait(packet);
Console.writeLine("!Name Sent!");
doAKNWait(new TypePacket(PacketType.Data));
packet = new StreamedDataPacket(file.toPath(), true);
doAKNWait(packet);
Console.writeLine("!File Sent!");
} else {
Console.writeLine("!File does not Exist!");
}
}
private static void process() {
Console.writeLine("Received Messages:");
synchronized (slock) {
int i = 1;
while (packetQueue.size() > 0) {
DataPacket packet = packetQueue.poll();
Console.writeLine("Message ("+ i++ +"):");
try {
Console.writeLine(new String(packet.savePayload(), StandardCharsets.UTF_8));
} catch (PacketException e) {
e.printStackTrace();
}
}
}
}
private static void sslSetup() {
if (runtime != null && runtime.isSSLUpgraded()) return;
Console.writeLine("SSL Setup:");
Console.writeLine("SSL Host Name (Enter empty to set to null):");
sslHost = Console.readString();
if (sslHost.equals("")) sslHost = null;
Console.writeLine("SSL Keystore Path:");
String kpath = Console.readString();
Console.writeLine("SSL Keystore Password:");
String kpass = Console.readString();
if (kpass.equals("")) kpass = "changeit";
try {
sslContext = SSLUtilities.getSSLContext(null, SSLUtilities.loadKeyStore(null, new File(kpath), kpass), kpass.toCharArray());
Console.writeLine("SSL Setup Complete!");
} catch (SSLUtilityException e) {
e.printStackTrace();
Console.writeLine("SSL Setup Failed!");
}
}
private static void upgrade() {
if (runtime == null || !runtime.isProcessing() || sslContext == null) return;
Console.writeLine("Upgrading Connection to SSL...");
runtime.sendPacket(new NetworkSSLUpgradePacket(false), true);
}
private static void info() {
Console.writeLine("INFORMATION:");
Console.writeLine("Local Socket: " + ((runtime != null && runtime.isProcessing()) ? runtime.getLocalAddress() + ":" + runtime.getLocalPort() : ":"));
Console.writeLine("Remote Socket: " + ((runtime != null && runtime.isProcessing()) ? runtime.getTargetAddress() + ":" + runtime.getTargetPort() : ":"));
Console.writeLine("Is Active: " + ((runtime != null && runtime.isProcessing()) ? "Yes" : "No"));
Console.writeLine("Number Of Packets To Process: " + (((runtime == null) ? 0 : runtime.numberOfQueuedReceivedPackets()) + packetQueue.size()));
Console.writeLine("SSL Upgrade Status: " + ((runtime != null && runtime.isSSLUpgraded()) ? "Upgraded" : "Not Upgraded"));
Console.writeLine("SSL Host Name: " + ((sslHost == null) ? "<null>" : sslHost));
Console.writeLine("SSL Context Status: " + ((sslContext == null) ? "Unavailable" : "Available"));
}
private static void header() {
Console.writeLine("C-ALM Net Test (C) Captain ALM 2022");
Console.writeLine("Under The BSD 3-Clause License");
}
private static void help() {
Console.writeLine("HELP:");
Console.writeLine("KEY) Action");
Console.writeLine("0/h) This Help Message");
Console.writeLine("1/i) Information State");
Console.writeLine("2/s) Start Connection");
Console.writeLine("3/d) Stop Connection");
Console.writeLine("4/m) Send Message");
Console.writeLine("5/f) Send File");
Console.writeLine("6/p) Process Incoming Packets");
Console.writeLine("7/x) SSL Settings");
Console.writeLine("8/u) SSL Upgrade");
Console.writeLine("9/a) Show the About Header");
Console.writeLine("OTHER) Quit");
}
}

View File

@ -0,0 +1,71 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.packet.*;
import java.nio.file.Path;
/**
* This class creates packets.
*
* @author Captain ALM
*/
public final class MyPacketFactory extends CALMNETPacketFactory {
private Path targetPath;
/**
* Constructs a new Instance of CALMNETPacketFactory with the specified {@link PacketLoader}.
*
* @param loader The packet loader to use.
* @throws NullPointerException loader is null.
*/
public MyPacketFactory(PacketLoader loader) {
super(true ,loader);
}
/**
* Constructs a new Instance of CALMNETPacketFactory with the specified {@link PacketLoader} and {@link IPacketFactory}.
*
* @param loader The packet loader to use.
* @param factory The packet factory to use or null (null signifies to use the same instance).
* @throws NullPointerException loader is null.
*/
public MyPacketFactory(PacketLoader loader, IPacketFactory factory) {
super(true ,loader, factory);
}
/**
* Constructs a {@link IPacket} of the protocol specified by the passed {@link PacketProtocolInformation} instance.
*
* @param information The protocol information to use.
* @return The constructed packet or null.
* @throws NullPointerException The information is null.
*/
@Override
public IPacket getPacket(PacketProtocolInformation information) {
if (information == null) throw new NullPointerException("information is null");
if (information.equals(AKNPacket.getTheProtocol())) return new AKNPacket();
if (information.equals(TypePacket.getTheProtocol())) return new TypePacket(null);
if (information.equals(DataPacket.getTheProtocol())) return (streamPreferred) ? new StreamedDataPacket(targetPath, true) : new DataPacket(targetPath);
return super.getPacket(information);
}
/**
* Gets the target path for {@link DataPacket}s.
*
* @return The target path or null.
*/
public Path getTargetPath() {
return targetPath;
}
/**
* Sets the target path for {@link DataPacket}s.
*
* @param path The target path or null.
*/
public void setTargetPath(Path path) {
targetPath = path;
}
}

View File

@ -0,0 +1,449 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.SSLUtilities;
import com.captainalm.lib.calmnet.SSLUtilityException;
import com.captainalm.lib.calmnet.packet.*;
import com.captainalm.lib.calmnet.packet.core.NetworkSSLUpgradePacket;
import com.captainalm.lib.calmnet.packet.fragment.FragmentAllocationPacket;
import com.captainalm.lib.calmnet.packet.fragment.FragmentPIDPacket;
import com.captainalm.lib.calmnet.packet.fragment.FragmentSendStopPacket;
import com.captainalm.lib.calmnet.stream.NetworkInputStream;
import com.captainalm.lib.calmnet.stream.NetworkOutputStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.function.Function;
/**
* This class is the network runtime class.
*
* @author Captain ALM
*/
public final class NetworkRuntime {
public final MyPacketFactory factory = new MyPacketFactory(new PacketLoader());
private NetworkInputStream inputStream;
private NetworkOutputStream outputStream;
private FragmentReceiver fragmentReceiver;
private final HashMap<Integer, LocalDateTime> fragmentRMM = new HashMap<>();
private FragmentSender fragmentSender;
private final HashMap<Integer, LocalDateTime> fragmentSMM = new HashMap<>();
private boolean processing = true;
private InetAddress targetAddress;
private int targetPort = -1;
private final Queue<IPacket> packetQueue = new LinkedList<>();
private Function<IPacket, Boolean> packetReceiveCallback;
private final Object slock = new Object();
private final Object slocksend = new Object();
private final Object slockfmon = new Object();
private final Object slockupg = new Object();
/**
* Constructs a new NetworkRuntime with the specified parameters.
*
* @param socketIn The socket to use.
* @param useFragmentation If fragmentation should be used.
* @param verifyFragmentPayloads If a fragment payload should be verified.
*/
public NetworkRuntime(Socket socketIn, boolean useFragmentation, boolean verifyFragmentPayloads) {
inputStream = new NetworkInputStream(socketIn);
outputStream = new NetworkOutputStream(socketIn);
init(useFragmentation, verifyFragmentPayloads);
}
/**
* Constructs a new NetworkRuntime with the specified parameters.
*
* @param socketIn The datagram socket to use.
* @param useFragmentation If fragmentation should be used.
* @param verifyFragmentPayloads If a fragment payload should be verified.
* @param address The target address (Can be null).
* @param port The target port.
*/
public NetworkRuntime(DatagramSocket socketIn, boolean useFragmentation, boolean verifyFragmentPayloads, InetAddress address, int port) {
inputStream = new NetworkInputStream(socketIn);
outputStream = new NetworkOutputStream(socketIn);
targetAddress = address;
targetPort = port;
if (address != null && port >= 0) {
try {
outputStream.setDatagramTarget(address, port);
} catch (IOException e) {
}
}
try {
outputStream.setDatagramBufferSize(65535);
} catch (IOException e) {
}
init(useFragmentation, verifyFragmentPayloads);
}
private void init(boolean useFragmentation, boolean verifyFragmentPayloads) {
fragmentReceiver = (useFragmentation) ? new FragmentReceiver(factory.getPacketLoader(), factory) : null;
if (fragmentReceiver != null) fragmentReceiver.setResponseVerification(verifyFragmentPayloads);
fragmentSender = (useFragmentation) ? new FragmentSender(factory.getPacketLoader()) : null;
if (fragmentSender != null) fragmentSender.setResponseVerification(verifyFragmentPayloads);
receiveThread.start();
if (useFragmentation) {
fragmentMonitorThread.start();
fragmentFinishRecvMonitorThread.start();
fragmentFinishSendMonitorThread.start();
fragmentReceiveThread.start();
fragmentSendThread.start();
}
}
private final Thread receiveThread = new Thread(() -> {
while (processing) {
try {
IPacket packet = factory.getPacketLoader().readStreamedPacket(inputStream, factory, null);
if (packet == null) continue;
if (inputStream.getDatagramSocket() != null && (targetAddress == null || targetPort < 0)) {
targetAddress = inputStream.getAddress();
targetPort = inputStream.getPort();
if (targetAddress != null && targetPort >= 0) {
try {
outputStream.setDatagramTarget(targetAddress, targetPort);
} catch (IOException e) {
}
}
}
if (fragmentReceiver != null) {
updateMState(fragmentRMM, packet);
fragmentReceiver.receivePacket(packet);
}
if (fragmentSender != null) {
updateMState(fragmentSMM, packet);
fragmentSender.receivePacket(packet);
}
synchronized (slock) {
if (packetReceiveCallback == null || packetReceiveCallback.apply(packet)) packetQueue.add(packet);
}
if (packet.isValid() && packet instanceof NetworkSSLUpgradePacket) {
synchronized (slockupg) {
int timeout = 4;
while (!isSSLUpgraded() && inputStream.getDatagramSocket() == null && timeout-- > 0) slockupg.wait();
}
}
synchronized (slocksend) {
slocksend.notifyAll();
}
} catch (PacketException | IOException e) {
e.printStackTrace();
stopProcessing();
} catch (InterruptedException e) {
}
}
}, "recv_thread");
private final Thread fragmentReceiveThread = new Thread(() -> {
while (processing) {
try {
IPacket packet = fragmentReceiver.receivePacket();
if (packet == null) continue;
synchronized (slock) {
if (packetReceiveCallback == null || packetReceiveCallback.apply(packet)) packetQueue.add(packet);
}
} catch (InterruptedException e) {
}
}
}, "frag_recv_thread");
private final Thread fragmentSendThread = new Thread(() -> {
while (processing) {
try {
synchronized (slocksend) {
slocksend.wait();
IPacket[] packets = fragmentSender.sendPacket();
for (IPacket c : packets) if (c != null) {
updateMState(fragmentSMM, c);
factory.getPacketLoader().writePacket(outputStream, c, true);
}
packets = fragmentReceiver.sendPacket();
for (IPacket c : packets) if (c != null) {
updateMState(fragmentRMM, c);
factory.getPacketLoader().writePacket(outputStream, c, true);
}
}
} catch (PacketException | IOException e) {
e.printStackTrace();
stopProcessing();
} catch (InterruptedException e) {
}
}
}, "frag_send_thread");
private final Thread fragmentMonitorThread = new Thread(() -> {
while (processing) {
int id = -1;
synchronized (slockfmon) {
for (int c : fragmentRMM.keySet()) {
if (!fragmentRMM.get(c).plusSeconds(29).isAfter(LocalDateTime.now())) {
fragmentRMM.remove(id);
fragmentReceiver.deletePacketFromRegistry(c);
}
}
for (int c : fragmentSMM.keySet()) {
if (!fragmentSMM.get(c).plusSeconds(29).isAfter(LocalDateTime.now())) {
fragmentSMM.remove(id);
fragmentSender.deletePacketFromRegistry(c);
}
}
}
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
}
}
}, "frag_mntr_thread");
private final Thread fragmentFinishRecvMonitorThread = new Thread(() -> {
while (processing) {
int id = -1;
try {
while ((id = fragmentReceiver.getLastIDFinished()) != -1) synchronized (slockfmon) {
fragmentRMM.remove(id);
}
} catch (InterruptedException e) {
}
}
}, "frag_fin_recv_mntr_thread");
private final Thread fragmentFinishSendMonitorThread = new Thread(() -> {
while (processing) {
int id = -1;
try {
while ((id = fragmentSender.getLastIDFinished()) != -1) synchronized (slockfmon) {
fragmentSMM.remove(id);
}
} catch (InterruptedException e) {
}
}
}, "frag_fin_send_mntr_thread");
private void updateMState(HashMap<Integer, LocalDateTime> mm, IPacket packet) {
if (packet == null || !packet.isValid()) return;
synchronized (slockfmon) {
if (packet instanceof FragmentAllocationPacket) {
mm.put(((FragmentAllocationPacket) packet).getPacketID(), LocalDateTime.now());
} else if (packet instanceof FragmentPIDPacket && !(packet instanceof FragmentSendStopPacket)) {
if (mm.containsKey(((FragmentPIDPacket) packet).getPacketID()))
mm.put(((FragmentPIDPacket) packet).getPacketID(), LocalDateTime.now());
}
}
}
/**
* Gets the current remote endpoint address or null.
*
* @return The remote address or null.
*/
public InetAddress getTargetAddress() {
if (!processing) return null;
return (targetAddress == null) ? inputStream.getAddress() : targetAddress;
}
/**
* Gets the current target port or -1.
*
* @return The target port or -1.
*/
public int getTargetPort() {
if (!processing) return -1;
return (targetPort < 0) ? inputStream.getPort() : targetPort;
}
/**
* Gets the current remote endpoint address or null.
*
* @return The remote address or null.
*/
public InetAddress getLocalAddress() {
if (!processing) return null;
return inputStream.getLocalAddress();
}
/**
* Gets the current local port or -1.
*
* @return The local port or -1.
*/
public int getLocalPort() {
if (!processing) return -1;
return inputStream.getLocalPort();
}
/**
* Performs an SSL Upgrade on a TCP Connection.
*
* @param context The SSL Context to use.
* @param host The host to check the remote certificate using (Set to null on server).
* @param isClientSide If the caller is directly connected (Not using an accepted socket).
*/
public void sslUpgrade(SSLContext context, String host, boolean isClientSide) {
if (!processing || inputStream.getSocket() == null || inputStream.getSocket() instanceof SSLSocket) return;
synchronized (slock) {
synchronized (slocksend) {
synchronized (slockupg) {
Socket original = inputStream.getSocket();
try {
inputStream.setSocket(SSLUtilities.upgradeClientSocketToSSL(context, inputStream.getSocket(), host, inputStream.getPort(), true, isClientSide));
outputStream.setSocket(inputStream.getSocket());
} catch (SSLUtilityException | IOException e) {
e.printStackTrace();
try {
inputStream.setSocket(original);
outputStream.setSocket(original);
} catch (IOException ex) {
}
}
slockupg.notifyAll();
}
}
}
}
/**
* Is the runtime SSL Upgraded.
*
* @return If the runtime is upgraded.
*/
public boolean isSSLUpgraded() {
if (!processing) return false;
return inputStream.getSocket() instanceof SSLSocket;
}
/**
* Sends a packet.
*
* @param packet The packet to send.
* @param forceNormalSend Forces a normal send operation without fragmentation.
*/
public void sendPacket(IPacket packet, boolean forceNormalSend) {
if (packet == null || notReadyToSend()) return;
synchronized (slocksend) {
if (fragmentSender == null || forceNormalSend) {
try {
factory.getPacketLoader().writePacket(outputStream, packet, true);
slocksend.notifyAll();
} catch (IOException | PacketException e) {
e.printStackTrace();
stopProcessing();
}
} else {
fragmentSender.sendPacket(packet);
slocksend.notifyAll();
}
}
}
/**
* Receives the last packet.
*
* @return Receives the last packet.
*/
public IPacket receiveLastPacket() {
if (!processing) return null;
synchronized (slock) {
return packetQueue.poll();
}
}
/**
* Gets the number of queued received packets.
*
* @return The number of queued received packets.
*/
public int numberOfQueuedReceivedPackets() {
synchronized (slock) {
return packetQueue.size();
}
}
/**
* Gets the packet receive callback.
* The return value of the passed function is whether to add the packet to the receive queue.
*
* @return The packet receive callback.
*/
public Function<IPacket, Boolean> getPacketReceiveCallback() {
return packetReceiveCallback;
}
/**
* Sets the packet receive callback.
* The return value of the passed function is whether to add the packet to the receive queue.
*
* @param callback The new packet receive callback.
*/
public void setPacketReceiveCallback(Function<IPacket, Boolean> callback) {
synchronized (slock) {
packetReceiveCallback = callback;
}
}
/**
* Is the runtime not ready to send.
*
* @return Cannot send.
*/
public boolean notReadyToSend() {
return !processing || ((outputStream.getSocket() == null) && (outputStream.getDatagramSocket() == null || targetAddress == null || targetPort < 0));
}
/**
* Gets if the runtime is processing.
*
* @return Is the runtime processing.
*/
public boolean isProcessing() {
return processing;
}
/**
* Stops processing.
*/
public void stopProcessing() {
if (processing) {
processing = false;
if (Thread.currentThread() != fragmentSendThread && fragmentSendThread.isAlive()) fragmentSendThread.interrupt();
if (Thread.currentThread() != fragmentReceiveThread && fragmentReceiveThread.isAlive()) fragmentReceiveThread.interrupt();
if (Thread.currentThread() != fragmentMonitorThread && fragmentMonitorThread.isAlive()) fragmentMonitorThread.interrupt();
if (Thread.currentThread() != fragmentFinishRecvMonitorThread && fragmentFinishRecvMonitorThread.isAlive()) fragmentFinishRecvMonitorThread.interrupt();
if (Thread.currentThread() != fragmentFinishSendMonitorThread && fragmentFinishSendMonitorThread.isAlive()) fragmentFinishSendMonitorThread.interrupt();
try {
inputStream.close();
} catch (IOException e) {
}
inputStream = null;
try {
outputStream.close();
} catch (IOException e) {
}
outputStream = null;
if (fragmentSender != null) {
fragmentSender.clearLastIDFinished();
fragmentSender.clearRegistry();
fragmentSender.clearWaitingPackets();
fragmentSender = null;
fragmentSMM.clear();
}
if (fragmentReceiver != null) {
fragmentReceiver.clearLastIDFinished();
fragmentReceiver.clearRegistry();
fragmentReceiver.clearWaitingPackets();
fragmentReceiver = null;
fragmentRMM.clear();
}
}
}
}

View File

@ -0,0 +1,44 @@
package com.captainalm.test.calmnet;
/**
* Provides a type of packet.
*
* @author Captain ALM
*/
public enum PacketType {
Message(0),
Name(1),
Data(2);
int value;
PacketType(int i) {
value = i;
}
/**
* Gets the integer value of the packet type.
*
* @return The integer value of the packet type.
*/
public int getValue() {
return value;
}
/**
* Gets the packet type given the integer value.
*
* @param i The integer value.
* @return The packet type or null.
*/
public static PacketType getPacketType(int i) {
switch (i) {
case 0:
return Message;
case 1:
return Name;
case 2:
return Data;
default:
return null;
}
}
}

View File

@ -0,0 +1,152 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.packet.IStreamedPacket;
import com.captainalm.lib.calmnet.packet.PacketException;
import com.captainalm.lib.calmnet.stream.LengthClampedInputStream;
import java.io.*;
import java.nio.file.Path;
/**
* Provides the data packet to store a byte array that can be backed to a file that is stream stored.
*
* @author Captain ALM
*/
public class StreamedDataPacket extends DataPacket implements IStreamedPacket {
protected static final int transferBufferSize = 2048;
protected boolean passThroughStream = false;
/**
* Constructs a new StreamedDataPacket with initial data.
*
* @param dataIn The data to initially use.
*/
public StreamedDataPacket(byte[] dataIn) {
super(dataIn);
}
/**
* Constructs a new stream data packet backed by a specified {@link Path}.
*
* @param path The path to back to.
* @param passThroughStream If the backing array should not be used.
*/
public StreamedDataPacket(Path path, boolean passThroughStream) {
super(path);
this.passThroughStream = passThroughStream;
}
/**
* Gets whether the backing array is not used when using {@link IStreamedPacket} methods.
* The backing array is always used when the store is not file backed.
*
* @return If the backing array is not used.
*/
public boolean isStreamPassedThrough() {
return passThroughStream;
}
/**
* Sets whether the backing array is not used when using {@link IStreamedPacket} methods.
* The backing array is always used when the store is not file backed.
*
* @param passThroughStream If the backing array should not be used.
*/
public void setStreamPassedThrough(boolean passThroughStream) {
synchronized (slock) {
this.passThroughStream = passThroughStream;
}
}
/**
* Gets if the packet is valid.
*
* @return Is the packet valid?
*/
@Override
public boolean isValid() {
boolean toret = super.isValid();
synchronized (slock) {
return toret || passThroughStream;
}
}
/**
* Reads payload data to an {@link OutputStream}.
*
* @param outputStream The output stream to read data to.
* @throws NullPointerException outputStream is null.
* @throws IOException An IO Exception has occurred.
* @throws PacketException An Exception has occurred.
*/
@Override
public void readData(OutputStream outputStream) throws IOException, PacketException {
synchronized (slock) {
if (passThroughStream && backingFile != null) {
try (InputStream streamIn = new FileInputStream(backingFile)) {
int length;
byte[] transferBuffer = new byte[transferBufferSize];
while ((length = streamIn.read(transferBuffer)) != -1)
outputStream.write(transferBuffer, 0, length);
} catch (SecurityException e) {
throw new PacketException(e);
}
} else {
outputStream.write(internalSavePayload());
}
}
}
/**
* Writes payload data from an {@link InputStream}.
*
* @param inputStream The input stream to write data from.
* @param size The size of the input payload in bytes.
* @throws NullPointerException inputStream is null.
* @throws IllegalArgumentException size is less than 0.
* @throws IOException An IO Exception has occurred.
* @throws PacketException An Exception has occurred.
*/
@Override
public void writeData(InputStream inputStream, int size) throws IOException, PacketException {
synchronized (slock) {
if (passThroughStream && backingFile != null) {
try (OutputStream streamOut = new FileOutputStream(backingFile); LengthClampedInputStream linputStream = new LengthClampedInputStream(inputStream, size)) {
int length;
byte[] transferBuffer = new byte[transferBufferSize];
while ((length = linputStream.read(transferBuffer)) != -1)
streamOut.write(transferBuffer, 0, length);
} catch (SecurityException e) {
throw new PacketException(e);
}
} else {
byte[] dataIn = new byte[size];
int offset = 0;
int slen;
while (offset < size) if ((slen = inputStream.read(dataIn, offset, size - offset)) != -1) offset += slen; else throw new IOException("inputStream end of stream");
internalLoadPayload(dataIn);
}
}
}
/**
* Gets the size of the output data.
*
* @return The size of the output data in bytes.
* @throws PacketException An Exception has occurred.
*/
@Override
public int getSize() throws PacketException {
synchronized (slock) {
if (passThroughStream) {
try {
return Math.toIntExact(backingFile.length());
} catch (ArithmeticException | SecurityException e){
throw new PacketException(e);
}
} else {
if (backedData == null) return 0; else return backedData.length;
}
}
}
}

View File

@ -0,0 +1,83 @@
package com.captainalm.test.calmnet;
import com.captainalm.lib.calmnet.packet.IPacket;
import com.captainalm.lib.calmnet.packet.PacketException;
import com.captainalm.lib.calmnet.packet.PacketProtocolInformation;
/**
* This packet provides the ability to send {@link PacketType}s.
*
* @author Captain ALM
*/
public class TypePacket implements IPacket {
private static final PacketProtocolInformation protocol = new PacketProtocolInformation((byte) 1, (byte) 2);
/**
* This field holds the {@link PacketType} (Can be null).
*/
public PacketType type;
/**
* Constructs a new instance of type packet using the specified {@link PacketType}.
*
* @param packetType The packet type or null.
*/
public TypePacket(PacketType packetType) {
type = packetType;
}
/**
* Gets if the packet is valid.
*
* @return Is the packet valid?
*/
@Override
public boolean isValid() {
return (type != null);
}
/**
* Gets the protocol information.
*
* @return The protocol information.
*/
@Override
public PacketProtocolInformation getProtocol() {
return protocol;
}
/**
* Gets the protocol information statically.
*
* @return The protocol information.
*/
public static PacketProtocolInformation getTheProtocol() {
return protocol;
}
/**
* Saves the packet payload to a byte array.
*
* @return The packet payload data.
* @throws PacketException An Exception has occurred.
*/
@Override
public byte[] savePayload() throws PacketException {
if (type == null) throw new PacketException("no data");
return new byte[] {(byte) type.getValue()};
}
/**
* Loads the packet payload from save data.
*
* @param packetData The packet payload data.
* @throws NullPointerException The new store data is null.
* @throws PacketException An Exception has occurred.
*/
@Override
public void loadPayload(byte[] packetData) throws PacketException {
if (packetData == null) throw new NullPointerException("packetData is null");
if (packetData.length != 1) throw new PacketException("packetData length is not 1");
type = PacketType.getPacketType(packetData[0]);
}
}

View File

@ -0,0 +1,84 @@
package com.captainalm.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Provides a console wrapper for standard stream.
*
* @author Captain ALM
*/
public class Console {
/**
* Writes to {@link System#out}.
*
* @param dataOut The string to write.
*/
public static void write(String dataOut) {
System.out.print(dataOut);
}
/**
* Writes to {@link System#out} terminated by a new line.
*
* @param dataOut The string to write.
*/
public static void writeLine(String dataOut) {
System.out.println(dataOut);
}
/**
* Reads a string from {@link System#in} terminated by a new line.
*
* @return The read string.
*/
public static String readString() {
if (System.console() != null) return System.console().readLine(); else {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = "";
try {
line = reader.readLine();
} catch (IOException e) {
}
return line;
}
}
/**
* Reads a character from {@link System#in}.
*
* @return The read character.
*/
public static char readCharacter() {
char[] chars = readString().toCharArray();
return (chars.length > 0) ? chars[0] : (char) 0;
}
/**
* Reads an integer from {@link System#in} terminated by a new line.
*
* @return The integer or null.
*/
public static Integer readInt() {
try {
return Integer.parseInt(readString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Reads a long from {@link System#in} terminated by a new line.
*
* @return The long or null.
*/
public static Long readLong() {
try {
return Long.parseLong(readString());
} catch (NumberFormatException e) {
return null;
}
}
}

View File

@ -0,0 +1,79 @@
package com.captainalm.utils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Provides the ability to output an object with all its fields.
*
* @author Captain ALM
*/
public class ObjectToString {
/**
* Gets the string representation of the passed object with its non-static fields.
*
* @param objectIn The object to output.
* @return The string representation.
*/
public static String toStringAllNonStatic(Object objectIn) {
if (objectIn == null) return "null";
StringBuilder b = new StringBuilder(objectIn + " [");
for (Field f : objectIn.getClass().getFields())
{
if (!Modifier.isStatic(f.getModifiers()))
{
try
{
Object obj = f.get(objectIn);
b.append(f.getName()).append("=").append((obj == null) ? "null" : obj.toString()).append(" ");
} catch (IllegalAccessException e) {}
}
}
b.append(']');
return b.toString();
}
/**
* Gets the string representation of the passed object with its non-static getters.
*
* @param objectIn The object to output.
* @return The string representation.
*/
public static String toStringAllNonStaticGetters(Object objectIn) {
StringBuilder b = new StringBuilder(objectIn + " [");
for (Method m : objectIn.getClass().getMethods())
{
if (!Modifier.isStatic(m.getModifiers()) && m.getReturnType() != void.class && m.getParameterCount() == 0) {
try
{
Object obj = m.invoke(objectIn);
b.append(m.getName()).append("()=").append((obj == null) ? "null" : obj.toString()).append(" ");
} catch (IllegalAccessException | InvocationTargetException e) {}
}
}
b.append(']');
return b.toString();
}
/**
* Gets the string representation of the passed object with its non-static getters that return integers or booleans.
*
* @param objectIn The object to output.
* @return The string representation.
*/
public static String toStringAllNonStaticIntBoolGetters(Object objectIn) {
StringBuilder b = new StringBuilder(objectIn + " [");
for (Method m : objectIn.getClass().getMethods())
{
if (!Modifier.isStatic(m.getModifiers()) && (m.getReturnType() == int.class || m.getReturnType() == Integer.class || m.getReturnType() == boolean.class || m.getReturnType() == Boolean.class) && m.getParameterCount() == 0) {
try
{
Object obj = m.invoke(objectIn);
b.append(m.getName()).append("()=").append((obj == null) ? "null" : obj.toString()).append(" ");
} catch (IllegalAccessException | InvocationTargetException e) {}
}
}
b.append(']');
return b.toString();
}
}