mirror of
https://bitbucket.org/projectswg/forwarder.git
synced 2026-07-13 21:01:08 -04:00
Improved UDP code to improve performance and reduce bandwidth
This commit is contained in:
@@ -23,6 +23,7 @@ public class ClientConnection {
|
||||
interceptor = new NetInterceptor();
|
||||
sender = new ClientSender(interceptor, loginPort, zonePort);
|
||||
receiver = new ClientReceiver(interceptor);
|
||||
sender.setClientReceiver(receiver);
|
||||
receiver.setClientSender(sender);
|
||||
}
|
||||
|
||||
@@ -34,10 +35,12 @@ public class ClientConnection {
|
||||
sender.setZoneCallback((packet) -> receiver.onPacket(true, packet));
|
||||
receiver.setReceiverCallback(new ClientReceiverCallback() {
|
||||
public void onPacket(byte[] data) { ClientConnection.this.onPacket(data); }
|
||||
public void onUdpRecv(boolean zone, byte[] data) { ClientConnection.this.onUdpRecv(zone, data); }
|
||||
public void onDisconnected() { ClientConnection.this.onDisconnected(); }
|
||||
public void onConnected() { ClientConnection.this.onConnected(); }
|
||||
public void onConnectionChanged(ConnectionState state) { ClientConnection.this.onConnectionStateChanged(state); }
|
||||
});
|
||||
sender.setSenderCallback((zone, data) -> onUdpSent(zone, data));
|
||||
pinger = Executors.newSingleThreadScheduledExecutor();
|
||||
pinger.scheduleAtFixedRate(()->ping(), 0, 1000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
@@ -63,6 +66,16 @@ public class ClientConnection {
|
||||
callback.onPacket(data);
|
||||
}
|
||||
|
||||
private void onUdpSent(boolean zone, byte [] data) {
|
||||
if (callback != null)
|
||||
callback.onUdpSent(zone, data);
|
||||
}
|
||||
|
||||
private void onUdpRecv(boolean zone, byte [] data) {
|
||||
if (callback != null)
|
||||
callback.onUdpRecv(zone, data);
|
||||
}
|
||||
|
||||
private void onDisconnected() {
|
||||
connected = false;
|
||||
if (callback != null)
|
||||
@@ -105,6 +118,8 @@ public class ClientConnection {
|
||||
void onConnected();
|
||||
void onDisconnected();
|
||||
void onPacket(byte [] data);
|
||||
void onUdpSent(boolean zone, byte [] data);
|
||||
void onUdpRecv(boolean zone, byte [] data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@ public class ClientReceiver {
|
||||
if (zone && packet.getData().length == 4) { // Ping
|
||||
sender.sendRaw(packet.getPort(), packet.getAddress(), packet.getData());
|
||||
lastPacket.set(System.nanoTime());
|
||||
if (callback != null)
|
||||
callback.onUdpRecv(zone, packet.getData());
|
||||
return;
|
||||
}
|
||||
ByteBuffer data = ByteBuffer.wrap(packet.getData()).order(ByteOrder.BIG_ENDIAN);
|
||||
@@ -89,12 +91,17 @@ public class ClientReceiver {
|
||||
sender.setPort(packet.getPort());
|
||||
lastPacket.set(System.nanoTime());
|
||||
process(data);
|
||||
if (callback != null)
|
||||
callback.onUdpRecv(zone, data.array());
|
||||
} else {
|
||||
if (packet.getPort() != port || port == 0)
|
||||
return;
|
||||
lastPacket.set(System.nanoTime());
|
||||
executor.submit(() -> {
|
||||
process(ByteBuffer.wrap(Encryption.decode(data.array(), 0)).order(ByteOrder.BIG_ENDIAN));
|
||||
ByteBuffer decoded = ByteBuffer.wrap(Encryption.decode(data.array(), 0)).order(ByteOrder.BIG_ENDIAN);
|
||||
process(decoded);
|
||||
if (callback != null)
|
||||
callback.onUdpRecv(zone, decoded.array());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -203,10 +210,11 @@ public class ClientReceiver {
|
||||
}
|
||||
|
||||
private void onOutOfOrder(OutOfOrder ooo) {
|
||||
|
||||
System.out.println("OOO " + ooo.getSequence());
|
||||
}
|
||||
|
||||
private void onAcknowledge(Acknowledge ack) {
|
||||
System.out.println("ACK " + ack.getSequence());
|
||||
sender.onAcknowledge(ack.getSequence());
|
||||
}
|
||||
|
||||
@@ -221,6 +229,7 @@ public class ClientReceiver {
|
||||
void onDisconnected();
|
||||
void onConnectionChanged(ConnectionState state);
|
||||
void onPacket(byte [] data);
|
||||
void onUdpRecv(boolean zone, byte [] data);
|
||||
}
|
||||
|
||||
public enum ConnectionState {
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.projectswg.networking.soe.Disconnect.DisconnectReason;
|
||||
public class ClientSender {
|
||||
|
||||
private static final InetAddress ADDR = InetAddress.getLoopbackAddress();
|
||||
private static final int MAX_PACKET_SIZE = 496;
|
||||
|
||||
private final NetInterceptor interceptor;
|
||||
private UDPServer loginServer;
|
||||
@@ -33,6 +32,8 @@ public class ClientSender {
|
||||
private Queue<SequencedOutbound> sentPackets;
|
||||
private Queue<byte []> inboundQueue;
|
||||
private ExecutorService executor;
|
||||
private ClientSenderCallback callback;
|
||||
private ClientReceiver receiver;
|
||||
private short txSequence;
|
||||
private int connectionId;
|
||||
private int port;
|
||||
@@ -73,6 +74,10 @@ public class ClientSender {
|
||||
zoneServer.close();
|
||||
}
|
||||
|
||||
public void setClientReceiver(ClientReceiver receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
public void setLoginCallback(UDPCallback callback) {
|
||||
loginServer.setCallback(callback);
|
||||
}
|
||||
@@ -81,6 +86,10 @@ public class ClientSender {
|
||||
zoneServer.setCallback(callback);
|
||||
}
|
||||
|
||||
public void setSenderCallback(ClientSenderCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public int getZonePort() {
|
||||
return zoneServer.getPort();
|
||||
}
|
||||
@@ -147,6 +156,8 @@ public class ClientSender {
|
||||
zoneServer.send(port, addr, data);
|
||||
else
|
||||
loginServer.send(port, addr, data);
|
||||
if (callback != null)
|
||||
callback.onUdpSent(zone, data);
|
||||
}
|
||||
|
||||
public void send(Packet packet) {
|
||||
@@ -167,49 +178,24 @@ public class ClientSender {
|
||||
|
||||
private void outboundRunnable() {
|
||||
final InetAddress addr = InetAddress.getLoopbackAddress();
|
||||
double time = 0;
|
||||
long lastBurst = 0;
|
||||
double timeSinceBurst = 0;
|
||||
while (true) {
|
||||
synchronized (sentPackets) {
|
||||
int sent = 0;
|
||||
for (SequencedOutbound packet : sentPackets) {
|
||||
sendRaw(port, addr, packet.getData());
|
||||
Thread.yield();
|
||||
if (++sent >= 500)
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void inboundRunnable() {
|
||||
byte [] data;
|
||||
Queue<byte []> outbound = new ArrayBlockingQueue<>(32, true);
|
||||
int size = 0;
|
||||
while (true) {
|
||||
size = 6;
|
||||
synchronized (inboundQueue) {
|
||||
while (!inboundQueue.isEmpty()) {
|
||||
data = interceptor.interceptServer(inboundQueue.poll());
|
||||
if ((size + data.length > MAX_PACKET_SIZE-7 && !outbound.isEmpty()) || outbound.size() == 32) {
|
||||
createOutboundPacket(outbound, size);
|
||||
size = 6;
|
||||
time = receiver.getTimeSinceLastPacket();
|
||||
timeSinceBurst = (System.nanoTime() - lastBurst) / 1E6;
|
||||
if (time <= timeSinceBurst || (time >= 100 && timeSinceBurst >= 500)) {
|
||||
synchronized (sentPackets) {
|
||||
int sent = 0;
|
||||
for (SequencedOutbound packet : sentPackets) {
|
||||
sendRaw(port, addr, packet.getData());
|
||||
Thread.yield();
|
||||
if (++sent >= 500)
|
||||
break;
|
||||
}
|
||||
outbound.add(data);
|
||||
size += data.length + 1 + (data.length >= 0xFF ? 2 : 0);
|
||||
if (size > MAX_PACKET_SIZE-4) {
|
||||
createOutboundPacket(outbound, size);
|
||||
size = 6;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
lastBurst = System.nanoTime();
|
||||
}
|
||||
if (!outbound.isEmpty())
|
||||
createOutboundPacket(outbound, size);
|
||||
size = 0;
|
||||
try {
|
||||
Thread.sleep(25);
|
||||
} catch (InterruptedException e) {
|
||||
@@ -218,8 +204,48 @@ public class ClientSender {
|
||||
}
|
||||
}
|
||||
|
||||
private void inboundRunnable() {
|
||||
final int dataHeaderSize = 8;
|
||||
byte [] data;
|
||||
Queue<byte []> outbound = new ArrayBlockingQueue<>(8, true);
|
||||
int size = 0;
|
||||
while (true) {
|
||||
size = dataHeaderSize;
|
||||
synchronized (inboundQueue) {
|
||||
while (!inboundQueue.isEmpty()) {
|
||||
data = interceptor.interceptServer(inboundQueue.poll());
|
||||
if ((size + getPacketLength(data) >= 496 && !outbound.isEmpty()) || outbound.size() == 8) {
|
||||
createOutboundPacket(outbound, size);
|
||||
size = dataHeaderSize;
|
||||
}
|
||||
outbound.add(data);
|
||||
size += getPacketLength(data);
|
||||
if (size >= 496) {
|
||||
createOutboundPacket(outbound, size);
|
||||
size = dataHeaderSize;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
if (!outbound.isEmpty())
|
||||
createOutboundPacket(outbound, size);
|
||||
try {
|
||||
Thread.sleep(25);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getPacketLength(byte [] data) {
|
||||
if (data.length >= 255)
|
||||
return data.length + 3;
|
||||
else
|
||||
return data.length + 1;
|
||||
}
|
||||
|
||||
private void createOutboundPacket(Queue<byte []> outbound, int size) {
|
||||
if (size <= MAX_PACKET_SIZE-4) { // Fits into single data packet
|
||||
if (size <= 496) { // Fits into single data packet
|
||||
DataChannelA channel = new DataChannelA();
|
||||
channel.setSequence(txSequence++);
|
||||
while (!outbound.isEmpty())
|
||||
@@ -227,7 +253,7 @@ public class ClientSender {
|
||||
send(channel);
|
||||
} else { // Fragmented
|
||||
while (!outbound.isEmpty()) {
|
||||
Fragmented [] frags = Fragmented.encode(ByteBuffer.wrap(outbound.poll()), txSequence, MAX_PACKET_SIZE);
|
||||
Fragmented [] frags = Fragmented.encode(ByteBuffer.wrap(outbound.poll()), txSequence);
|
||||
txSequence += frags.length;
|
||||
for (Fragmented frag : frags) {
|
||||
send(frag);
|
||||
@@ -236,6 +262,10 @@ public class ClientSender {
|
||||
}
|
||||
}
|
||||
|
||||
public interface ClientSenderCallback {
|
||||
void onUdpSent(boolean zone, byte [] data);
|
||||
}
|
||||
|
||||
private static class SequencedOutbound implements SequencedPacket {
|
||||
|
||||
private short sequence;
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.projectswg;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.projectswg.ClientConnection.ClientCallback;
|
||||
import com.projectswg.ServerConnection.ServerCallback;
|
||||
|
||||
public class Connections {
|
||||
|
||||
private final ServerConnection server;
|
||||
private final ClientConnection client;
|
||||
private final AtomicLong tcpRecv;
|
||||
private final AtomicLong tcpSent;
|
||||
private final AtomicLong udpRecv;
|
||||
private final AtomicLong udpSent;
|
||||
private ConnectionCallback callback;
|
||||
private InetAddress addr;
|
||||
private int port;
|
||||
|
||||
public Connections() {
|
||||
server = new ServerConnection();
|
||||
client = new ClientConnection(44453, 44463);
|
||||
tcpRecv = new AtomicLong(0);
|
||||
tcpSent = new AtomicLong(0);
|
||||
udpRecv = new AtomicLong(0);
|
||||
udpSent = new AtomicLong(0);
|
||||
addr = ServerConnection.DEFAULT_ADDR;
|
||||
port = ServerConnection.DEFAULT_PORT;
|
||||
callback = null;
|
||||
setCallbacks();
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
client.start();
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
server.stop();
|
||||
client.stop();
|
||||
}
|
||||
|
||||
public void setCallback(ConnectionCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setRemote(InetAddress addr, int port) {
|
||||
if (this.addr.equals(addr) && this.port == port)
|
||||
return;
|
||||
terminate();
|
||||
server.setRemoteAddress(addr, port);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public long getTcpRecv() {
|
||||
return tcpRecv.get();
|
||||
}
|
||||
|
||||
public long getTcpSent() {
|
||||
return tcpSent.get();
|
||||
}
|
||||
|
||||
public long getUdpRecv() {
|
||||
return udpRecv.get();
|
||||
}
|
||||
|
||||
public long getUdpSent() {
|
||||
return udpSent.get();
|
||||
}
|
||||
|
||||
private void setCallbacks() {
|
||||
client.setCallback(new ClientCallback() {
|
||||
public void onPacket(byte[] data) { onDataSentTcp(data); }
|
||||
public void onUdpSent(boolean zone, byte[] data) { onDataSentUdp(data); }
|
||||
public void onUdpRecv(boolean zone, byte[] data) { onDataRecvUdp(data); }
|
||||
public void onDisconnected() { onClientDisconnected(); }
|
||||
public void onConnected() { onClientConnected(); }
|
||||
});
|
||||
server.setCallback(new ServerCallback() {
|
||||
public void onData(byte[] data) { onDataRecvTcp(data); }
|
||||
public void onConnected() { onServerConnected(); }
|
||||
public void onDisconnected() { onServerDisconnected(); }
|
||||
});
|
||||
}
|
||||
|
||||
private void onServerConnected() {
|
||||
if (callback != null)
|
||||
callback.onServerConnected();
|
||||
}
|
||||
|
||||
private void onServerDisconnected() {
|
||||
if (callback != null)
|
||||
callback.onServerDisconnected();
|
||||
}
|
||||
|
||||
private void onClientConnected() {
|
||||
server.start();
|
||||
if (callback != null)
|
||||
callback.onClientConnected();
|
||||
}
|
||||
|
||||
private void onClientDisconnected() {
|
||||
server.stop();
|
||||
if (callback != null)
|
||||
callback.onClientDisconnected();
|
||||
}
|
||||
|
||||
private void onDataRecvTcp(byte [] data) {
|
||||
tcpRecv.addAndGet(data.length);
|
||||
client.send(data);
|
||||
if (callback != null)
|
||||
callback.onDataRecvTcp(data);
|
||||
}
|
||||
|
||||
private void onDataSentTcp(byte [] data) {
|
||||
tcpSent.addAndGet(data.length);
|
||||
server.forward(data);
|
||||
if (callback != null)
|
||||
callback.onDataSentTcp(data);
|
||||
}
|
||||
|
||||
private void onDataRecvUdp(byte [] data) {
|
||||
udpRecv.addAndGet(data.length);
|
||||
if (callback != null)
|
||||
callback.onDataRecvUdp(data);
|
||||
}
|
||||
|
||||
private void onDataSentUdp(byte [] data) {
|
||||
udpSent.addAndGet(data.length);
|
||||
if (callback != null)
|
||||
callback.onDataSentUdp(data);
|
||||
}
|
||||
|
||||
public interface ConnectionCallback {
|
||||
void onServerConnected();
|
||||
void onServerDisconnected();
|
||||
void onClientConnected();
|
||||
void onClientDisconnected();
|
||||
void onDataRecvTcp(byte [] data);
|
||||
void onDataSentTcp(byte [] data);
|
||||
void onDataRecvUdp(byte [] data);
|
||||
void onDataSentUdp(byte [] data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,145 +2,186 @@ package com.projectswg;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
import com.projectswg.ClientConnection.ClientCallback;
|
||||
import com.projectswg.ServerConnection.ServerCallback;
|
||||
import com.projectswg.Connections.ConnectionCallback;
|
||||
|
||||
public class Forwarder extends Application {
|
||||
public class Forwarder extends Application implements ConnectionCallback {
|
||||
|
||||
private static final String [] DATA_NAMES = new String[]{"B", "KB", "MB", "GB", "TB"};
|
||||
private static final String SERVER_CONN_STRING = "Server Connection: %s";
|
||||
private static final String CLIENT_CONN_STRING = "Client Connection: %s";
|
||||
private static final String SERVER_RX_STRING = "TCP Recv: %s";
|
||||
private static final String SERVER_TX_STRING = "TCP Sent: %s";
|
||||
|
||||
private final ServerConnection server;
|
||||
private final ClientConnection client;
|
||||
private final AtomicLong receivedBytes;
|
||||
private final AtomicLong transmittedBytes;
|
||||
private final Connections connections;
|
||||
private final TextField serverIpField;
|
||||
private final TextField serverPortField;
|
||||
private final Button serverSetButton;
|
||||
private final Text serverConnectionText;
|
||||
private final Text clientConnectionText;
|
||||
private final Text serverReceivedText;
|
||||
private final Text serverTransmittedText;
|
||||
private final Text serverRxText;
|
||||
private final Text serverTxText;
|
||||
private final Text clientRxText;
|
||||
private final Text clientTxText;
|
||||
|
||||
public static void main(String [] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
public Forwarder() {
|
||||
receivedBytes = new AtomicLong(0);
|
||||
transmittedBytes = new AtomicLong(0);
|
||||
connections = new Connections();
|
||||
serverIpField = new TextField(ServerConnection.DEFAULT_ADDR.getHostAddress());
|
||||
serverPortField = new TextField(Integer.toString(ServerConnection.DEFAULT_PORT));
|
||||
serverConnectionText = new Text(String.format(SERVER_CONN_STRING, getConnectionStatus(false)));
|
||||
clientConnectionText = new Text(String.format(CLIENT_CONN_STRING, getConnectionStatus(false)));
|
||||
serverReceivedText = new Text(String.format(SERVER_RX_STRING, getByteName(receivedBytes.get())));
|
||||
serverTransmittedText = new Text(String.format(SERVER_TX_STRING, getByteName(transmittedBytes.get())));
|
||||
serverSetButton = new Button("Set");
|
||||
serverConnectionText = new Text(getConnectionStatus(false));
|
||||
clientConnectionText = new Text(getConnectionStatus(false));
|
||||
serverRxText = new Text(getByteName(connections.getTcpRecv()));
|
||||
serverTxText = new Text(getByteName(connections.getTcpSent()));
|
||||
clientRxText = new Text(getByteName(connections.getUdpRecv()));
|
||||
clientTxText = new Text(getByteName(connections.getUdpSent()));
|
||||
updateConnection(serverConnectionText, false);
|
||||
updateConnection(clientConnectionText, false);
|
||||
updateServerButton();
|
||||
EventHandler<KeyEvent> handler = new EventHandler<KeyEvent>() {
|
||||
@Override
|
||||
public void handle(KeyEvent event) {
|
||||
if (event.getCode() == KeyCode.ENTER)
|
||||
updateServerIp();
|
||||
else
|
||||
updateServerButton();
|
||||
}
|
||||
};
|
||||
serverIpField.setOnKeyPressed(handler);
|
||||
serverPortField.setOnKeyPressed(handler);
|
||||
server = new ServerConnection();
|
||||
client = new ClientConnection(44453, 44463);
|
||||
client.setCallback(new ClientCallback() {
|
||||
@Override
|
||||
public void onPacket(byte[] data) {
|
||||
transmittedBytes.addAndGet(data.length);
|
||||
server.forward(data);
|
||||
Platform.runLater(() -> serverTransmittedText.setText(String.format(SERVER_TX_STRING, getByteName(transmittedBytes.get()))));
|
||||
}
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
Platform.runLater(() -> clientConnectionText.setText(String.format(CLIENT_CONN_STRING, getConnectionStatus(false))));
|
||||
server.stop();
|
||||
}
|
||||
@Override
|
||||
public void onConnected() {
|
||||
Platform.runLater(() -> clientConnectionText.setText(String.format(CLIENT_CONN_STRING, getConnectionStatus(true))));
|
||||
server.start();
|
||||
}
|
||||
});
|
||||
server.setCallback(new ServerCallback() {
|
||||
@Override
|
||||
public void onData(byte[] data) {
|
||||
receivedBytes.addAndGet(data.length);
|
||||
client.send(data);
|
||||
Platform.runLater(() -> serverReceivedText.setText(String.format(SERVER_RX_STRING, getByteName(receivedBytes.get()))));
|
||||
}
|
||||
@Override
|
||||
public void onConnected() {
|
||||
Platform.runLater(() -> serverConnectionText.setText(String.format(SERVER_CONN_STRING, getConnectionStatus(true))));
|
||||
}
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
Platform.runLater(() -> serverConnectionText.setText(String.format(SERVER_CONN_STRING, getConnectionStatus(false))));
|
||||
serverIpField.setOnKeyTyped(handler);
|
||||
serverPortField.setOnKeyTyped(handler);
|
||||
serverSetButton.setOnAction(new EventHandler<ActionEvent>(){
|
||||
public void handle(ActionEvent event) {
|
||||
updateServerIp();
|
||||
}
|
||||
});
|
||||
connections.setCallback(this);
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
client.start();
|
||||
@Override
|
||||
public void onServerConnected() {
|
||||
Platform.runLater(() -> updateConnection(serverConnectionText, true));
|
||||
}
|
||||
|
||||
private void terminate() {
|
||||
server.stop();
|
||||
client.stop();
|
||||
@Override
|
||||
public void onServerDisconnected() {
|
||||
Platform.runLater(() -> updateConnection(serverConnectionText, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientConnected() {
|
||||
Platform.runLater(() -> updateConnection(clientConnectionText, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientDisconnected() {
|
||||
Platform.runLater(() -> updateConnection(clientConnectionText, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataRecvTcp(byte[] data) {
|
||||
Platform.runLater(() -> serverRxText.setText(getByteName(connections.getTcpRecv())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataSentTcp(byte[] data) {
|
||||
Platform.runLater(() -> serverTxText.setText(getByteName(connections.getTcpSent())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataRecvUdp(byte[] data) {
|
||||
Platform.runLater(() -> clientRxText.setText(getByteName(connections.getUdpRecv())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataSentUdp(byte[] data) {
|
||||
Platform.runLater(() -> clientTxText.setText(getByteName(connections.getUdpSent())));
|
||||
}
|
||||
|
||||
private void updateConnection(Text t, boolean status) {
|
||||
t.setText(getConnectionStatus(status));
|
||||
t.setFill(status ? Color.GREEN : Color.RED);
|
||||
}
|
||||
|
||||
private void updateServerIp() {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(serverIpField.getText());
|
||||
int port = Integer.parseInt(serverPortField.getText());
|
||||
terminate();
|
||||
server.setRemoteAddress(addr, port);
|
||||
initialize();
|
||||
connections.setRemote(addr, port);
|
||||
updateServerButton();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Unknown IP: " + serverIpField.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Invalid Port: " + serverPortField.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateServerButton() {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(serverIpField.getText());
|
||||
int port = Integer.parseInt(serverPortField.getText());
|
||||
if (!addr.equals(connections.getAddress()) || port != connections.getPort())
|
||||
serverSetButton.setDisable(false);
|
||||
else
|
||||
serverSetButton.setDisable(true);
|
||||
} catch (UnknownHostException | NumberFormatException e) {
|
||||
serverSetButton.setDisable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
initialize();
|
||||
connections.initialize();
|
||||
GridPane root = new GridPane();
|
||||
root.add(serverIpField, 0, 0);
|
||||
root.add(serverPortField, 1, 0);
|
||||
root.add(serverConnectionText, 0, 1);
|
||||
root.add(clientConnectionText, 0, 2);
|
||||
root.add(serverReceivedText, 0, 3);
|
||||
root.add(serverTransmittedText, 0, 4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ColumnConstraints cc = new ColumnConstraints();
|
||||
cc.setPercentWidth(25);
|
||||
root.getColumnConstraints().add(cc);
|
||||
}
|
||||
root.add(serverIpField, 0, 0, 2, 1);
|
||||
root.add(serverPortField, 2, 0, 1, 1);
|
||||
root.add(serverSetButton, 3, 0, 1, 1);
|
||||
root.add(new Text("Server Connection:"), 0, 1, 2, 1);
|
||||
root.add(serverConnectionText, 2, 1, 2, 1);
|
||||
root.add(new Text("Client Connection:"), 0, 2, 2, 1);
|
||||
root.add(clientConnectionText, 2, 2, 2, 1);
|
||||
root.add(new Text("Sent"), 1, 3, 1, 1);
|
||||
root.add(new Text("Recv"), 2, 3, 1, 1);
|
||||
root.add(new Text("TCP"), 0, 4, 1, 1);
|
||||
root.add(serverTxText, 1, 4, 1, 1);
|
||||
root.add(serverRxText, 2, 4, 1, 1);
|
||||
root.add(new Text("UDP"), 0, 5, 1, 1);
|
||||
root.add(clientTxText, 1, 5, 1, 1);
|
||||
root.add(clientRxText, 2, 5, 1, 1);
|
||||
Scene scene = new Scene(root, 300, 160);
|
||||
scene.setRoot(root);
|
||||
primaryStage.setTitle("Holocore Forwarder");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinWidth(scene.getWidth());
|
||||
primaryStage.setMinHeight(scene.getHeight());
|
||||
primaryStage.setMaxWidth(scene.getWidth());
|
||||
primaryStage.setMaxHeight(scene.getHeight());
|
||||
root.setOnMouseClicked((event) -> root.requestFocus());
|
||||
root.requestFocus();
|
||||
primaryStage.show();
|
||||
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
|
||||
public void handle(WindowEvent we) {
|
||||
terminate();
|
||||
connections.terminate();
|
||||
primaryStage.close();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -71,12 +71,12 @@ public class Fragmented extends Packet implements SequencedPacket {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Fragmented [] encode(int startSequence, int maxSize) {
|
||||
public Fragmented [] encode(int startSequence) {
|
||||
packet.position(0);
|
||||
int ord = 0;
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((packet.remaining()+4)/(maxSize-7.0))];
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((packet.remaining()+4)/489.0)];
|
||||
while (packet.remaining() > 0) {
|
||||
packets[ord] = createSegment(startSequence++, ord++, maxSize, packet);
|
||||
packets[ord] = createSegment(startSequence++, ord++, packet);
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
@@ -108,19 +108,19 @@ public class Fragmented extends Packet implements SequencedPacket {
|
||||
public short getSequence() { return sequence; }
|
||||
public int getDatLength() { return length; }
|
||||
|
||||
public static final Fragmented [] encode(ByteBuffer data, int startSequence, int maxSize) {
|
||||
public static final Fragmented [] encode(ByteBuffer data, int startSequence) {
|
||||
data.position(0);
|
||||
int ord = 0;
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((data.remaining()+4)/(maxSize-7.0))];
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((data.remaining()+4)/489.0)];
|
||||
while (data.remaining() > 0) {
|
||||
packets[ord] = createSegment(startSequence++, ord++, maxSize, data);
|
||||
packets[ord] = createSegment(startSequence++, ord++, data);
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
private static final Fragmented createSegment(int startSequence, int ord, int maxSize, ByteBuffer packet) {
|
||||
private static final Fragmented createSegment(int startSequence, int ord, ByteBuffer packet) {
|
||||
int header = (ord == 0) ? 8 : 4;
|
||||
ByteBuffer data = ByteBuffer.allocate(Math.min(packet.remaining()+header, maxSize-3));
|
||||
ByteBuffer data = ByteBuffer.allocate(Math.min(packet.remaining()+header, 493));
|
||||
|
||||
addNetShort(data, 0x0D);
|
||||
addNetShort(data, startSequence);
|
||||
|
||||
Reference in New Issue
Block a user