diff --git a/src/main/java/com/projectswg/forwarder/Forwarder.java b/src/main/java/com/projectswg/forwarder/Forwarder.java
index c3a2905..dc3ea8f 100644
--- a/src/main/java/com/projectswg/forwarder/Forwarder.java
+++ b/src/main/java/com/projectswg/forwarder/Forwarder.java
@@ -128,6 +128,8 @@ public class Forwarder {
private String password = null;
private int loginPort = 0;
private int zonePort = 0;
+ private int outboundTunerMaxSend = 100;
+ private int outboundTunerInterval = 20;
private ForwarderData() { }
@@ -151,6 +153,14 @@ public class Forwarder {
return zonePort;
}
+ public int getOutboundTunerMaxSend() {
+ return outboundTunerMaxSend;
+ }
+
+ public int getOutboundTunerInterval() {
+ return outboundTunerInterval;
+ }
+
public void setAddress(InetSocketAddress address) {
this.address = address;
}
@@ -170,6 +180,15 @@ public class Forwarder {
public void setZonePort(int zonePort) {
this.zonePort = zonePort;
}
+
+ public void setOutboundTunerMaxSend(int outboundTunerMaxSend) {
+ this.outboundTunerMaxSend = outboundTunerMaxSend;
+ }
+
+ public void setOutboundTunerInterval(int outboundTunerInterval) {
+ this.outboundTunerInterval = outboundTunerInterval;
+ }
+
}
}
diff --git a/src/main/java/com/projectswg/forwarder/intents/client/SonyPacketInboundIntent.java b/src/main/java/com/projectswg/forwarder/intents/client/SonyPacketInboundIntent.java
index 9ddd1c7..8ff1456 100644
--- a/src/main/java/com/projectswg/forwarder/intents/client/SonyPacketInboundIntent.java
+++ b/src/main/java/com/projectswg/forwarder/intents/client/SonyPacketInboundIntent.java
@@ -1,17 +1,25 @@
package com.projectswg.forwarder.intents.client;
+import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import com.projectswg.forwarder.resources.networking.packets.Packet;
import me.joshlarson.jlcommon.control.Intent;
import org.jetbrains.annotations.NotNull;
public class SonyPacketInboundIntent extends Intent {
+ private final ProtocolStack stack;
private final Packet packet;
- public SonyPacketInboundIntent(@NotNull Packet packet) {
+ public SonyPacketInboundIntent(@NotNull ProtocolStack stack, @NotNull Packet packet) {
+ this.stack = stack;
this.packet = packet;
}
+ @NotNull
+ public ProtocolStack getStack() {
+ return stack;
+ }
+
@NotNull
public Packet getPacket() {
return packet;
diff --git a/src/main/java/com/projectswg/forwarder/intents/client/StackCreatedIntent.java b/src/main/java/com/projectswg/forwarder/intents/client/StackCreatedIntent.java
new file mode 100644
index 0000000..b287491
--- /dev/null
+++ b/src/main/java/com/projectswg/forwarder/intents/client/StackCreatedIntent.java
@@ -0,0 +1,40 @@
+/***********************************************************************************
+ * Copyright (C) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * This file is part of the ProjectSWG Launcher. *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with this program. If not, see . *
+ * *
+ ***********************************************************************************/
+
+package com.projectswg.forwarder.intents.client;
+
+import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
+import me.joshlarson.jlcommon.control.Intent;
+import org.jetbrains.annotations.Nullable;
+
+public class StackCreatedIntent extends Intent {
+
+ private final ProtocolStack stack;
+
+ public StackCreatedIntent(ProtocolStack stack) {
+ this.stack = stack;
+ }
+
+ @Nullable
+ public ProtocolStack getStack() {
+ return stack;
+ }
+
+}
diff --git a/src/main/java/com/projectswg/forwarder/intents/client/StackDestroyedIntent.java b/src/main/java/com/projectswg/forwarder/intents/client/StackDestroyedIntent.java
new file mode 100644
index 0000000..ed894af
--- /dev/null
+++ b/src/main/java/com/projectswg/forwarder/intents/client/StackDestroyedIntent.java
@@ -0,0 +1,40 @@
+/***********************************************************************************
+ * Copyright (C) 2018 /// Project SWG /// www.projectswg.com *
+ * *
+ * This file is part of the ProjectSWG Launcher. *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU Affero General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Affero General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Affero General Public License *
+ * along with this program. If not, see . *
+ * *
+ ***********************************************************************************/
+
+package com.projectswg.forwarder.intents.client;
+
+import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
+import me.joshlarson.jlcommon.control.Intent;
+import org.jetbrains.annotations.Nullable;
+
+public class StackDestroyedIntent extends Intent {
+
+ private final ProtocolStack stack;
+
+ public StackDestroyedIntent(ProtocolStack stack) {
+ this.stack = stack;
+ }
+
+ @Nullable
+ public ProtocolStack getStack() {
+ return stack;
+ }
+
+}
diff --git a/src/main/java/com/projectswg/forwarder/intents/client/UpdateStackIntent.java b/src/main/java/com/projectswg/forwarder/intents/client/UpdateStackIntent.java
deleted file mode 100644
index 2bb468d..0000000
--- a/src/main/java/com/projectswg/forwarder/intents/client/UpdateStackIntent.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.projectswg.forwarder.intents.client;
-
-import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
-import me.joshlarson.jlcommon.control.Intent;
-import org.jetbrains.annotations.Nullable;
-
-public class UpdateStackIntent extends Intent {
-
- private final ProtocolStack stack;
-
- public UpdateStackIntent(ProtocolStack stack) {
- this.stack = stack;
- }
-
- @Nullable
- public ProtocolStack getStack() {
- return stack;
- }
-
-}
diff --git a/src/main/java/com/projectswg/forwarder/resources/client/state/OutboundDataTuner.java b/src/main/java/com/projectswg/forwarder/resources/client/state/OutboundDataTuner.java
deleted file mode 100644
index 0449b65..0000000
--- a/src/main/java/com/projectswg/forwarder/resources/client/state/OutboundDataTuner.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.projectswg.forwarder.resources.client.state;
-
-import me.joshlarson.jlcommon.log.Log;
-
-public class OutboundDataTuner {
-
- private long start;
- private int maxSend;
- private int outOfOrders;
-
- public OutboundDataTuner() {
- reset();
- }
-
- public int getMaxSend() {
- return maxSend;
- }
-
- public void markStart() {
- reset();
- start = System.nanoTime();
- }
-
- public void markEnd() {
- long time = System.nanoTime() - start;
- Log.d("Max Send=%d Time to Zone=%.0fms OOO=%d", maxSend, time/1E6, outOfOrders);
- reset();
- }
-
- public void markOOO() {
- outOfOrders++;
- maxSend -= 2;
- capMaxSend();
- }
-
- public void markAck() {
- maxSend += 2;
- capMaxSend();
- }
-
- public void markLag() {
- maxSend -= 50;
- capMaxSend();
- }
-
- private void reset() {
- start = 0;
- outOfOrders = 0;
- maxSend = 200;
- }
-
- private void capMaxSend() {
- if (maxSend < 100)
- maxSend = 100;
- else if (maxSend > 5000)
- maxSend = 5000;
- }
-
-}
diff --git a/src/main/java/com/projectswg/forwarder/services/client/ClientInboundDataService.java b/src/main/java/com/projectswg/forwarder/services/client/ClientInboundDataService.java
index e2ae627..eb7ebc2 100644
--- a/src/main/java/com/projectswg/forwarder/services/client/ClientInboundDataService.java
+++ b/src/main/java/com/projectswg/forwarder/services/client/ClientInboundDataService.java
@@ -4,7 +4,6 @@ import com.projectswg.common.network.packets.PacketType;
import com.projectswg.common.network.packets.swg.zone.HeartBeat;
import com.projectswg.forwarder.intents.client.DataPacketInboundIntent;
import com.projectswg.forwarder.intents.client.SonyPacketInboundIntent;
-import com.projectswg.forwarder.intents.client.UpdateStackIntent;
import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import com.projectswg.forwarder.resources.networking.packets.*;
import me.joshlarson.jlcommon.control.IntentChain;
@@ -16,30 +15,20 @@ import me.joshlarson.jlcommon.log.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.concurrent.atomic.AtomicReference;
public class ClientInboundDataService extends Service {
private final IntentMultiplexer multiplexer;
- private final AtomicReference stack;
private final IntentChain intentChain;
public ClientInboundDataService() {
this.multiplexer = new IntentMultiplexer(this, ProtocolStack.class, Packet.class);
- this.stack = new AtomicReference<>(null);
this.intentChain = new IntentChain();
}
@IntentHandler
private void handleSonyPacketInboundIntent(SonyPacketInboundIntent spii) {
- ProtocolStack stack = this.stack.get();
- assert stack != null : "stack is null";
- multiplexer.call(stack, spii.getPacket());
- }
-
- @IntentHandler
- private void handleUpdateStackIntent(UpdateStackIntent sci) {
- stack.set(sci.getStack());
+ multiplexer.call(spii.getStack(), spii.getPacket());
}
@Multiplexer
diff --git a/src/main/java/com/projectswg/forwarder/services/client/ClientOutboundDataService.java b/src/main/java/com/projectswg/forwarder/services/client/ClientOutboundDataService.java
index 1083347..e0f487f 100644
--- a/src/main/java/com/projectswg/forwarder/services/client/ClientOutboundDataService.java
+++ b/src/main/java/com/projectswg/forwarder/services/client/ClientOutboundDataService.java
@@ -3,8 +3,10 @@ package com.projectswg.forwarder.services.client;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.packets.PacketType;
import com.projectswg.common.network.packets.swg.zone.HeartBeat;
+import com.projectswg.forwarder.Forwarder.ForwarderData;
import com.projectswg.forwarder.intents.client.*;
-import com.projectswg.forwarder.resources.client.state.OutboundDataTuner;
+import com.projectswg.forwarder.intents.control.StartForwarderIntent;
+import com.projectswg.forwarder.resources.networking.ClientServer;
import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import com.projectswg.forwarder.resources.networking.data.SequencedOutbound;
import com.projectswg.forwarder.resources.networking.packets.Acknowledge;
@@ -20,39 +22,51 @@ import me.joshlarson.jlcommon.log.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
public class ClientOutboundDataService extends Service {
- private static final int TIMER_DELAY = 20;
-
private final IntentMultiplexer multiplexer;
- private final AtomicReference stack;
+ private final Set activeStacks;
private final ScheduledThreadPool timerThread;
- private final OutboundDataTuner tuner;
private final Object outboundMutex;
+ private ForwarderData data;
+
public ClientOutboundDataService() {
this.multiplexer = new IntentMultiplexer(this, ProtocolStack.class, Packet.class);
- this.stack = new AtomicReference<>(null);
+ this.activeStacks = ConcurrentHashMap.newKeySet();
this.timerThread = new ScheduledThreadPool(2, 5, "outbound-sender-%d");
- this.tuner = new OutboundDataTuner();
this.outboundMutex = new Object();
+ this.data = null;
+ }
+
+ @Override
+ public boolean terminate() {
+ timerThread.stop();
+ return timerThread.awaitTermination(1000);
+ }
+
+ @IntentHandler
+ private void handleStartForwarderIntent(StartForwarderIntent sfi) {
+ data = sfi.getData();
}
@IntentHandler
private void handleSonyPacketInboundIntent(SonyPacketInboundIntent spii) {
- ProtocolStack stack = this.stack.get();
- assert stack != null : "stack is null";
- multiplexer.call(stack, spii.getPacket());
+ multiplexer.call(spii.getStack(), spii.getPacket());
}
@IntentHandler
private void handleClientConnectedIntent(ClientConnectedIntent cci) {
if (timerThread.isRunning())
return;
+ int interval = data.getOutboundTunerInterval();
+ if (interval <= 0)
+ interval = 20;
timerThread.start();
- timerThread.executeWithFixedDelay(TIMER_DELAY, TIMER_DELAY, this::timerCallback);
+ timerThread.executeWithFixedDelay(interval, interval, this::timerCallback);
timerThread.executeWithFixedRate(0, 5000, this::clearSentBit);
}
@@ -65,55 +79,63 @@ public class ClientOutboundDataService extends Service {
}
@IntentHandler
- private void handleUpdateStackIntent(UpdateStackIntent sci) {
- stack.set(sci.getStack());
+ private void handleStackCreatedIntent(StackCreatedIntent sci) {
+ activeStacks.add(sci.getStack());
}
@IntentHandler
- private void handleDataPacketInboundIntent(DataPacketInboundIntent dpii) {
- ProtocolStack stack = this.stack.get();
- if (stack == null)
- return;
- PacketType type = PacketType.fromCrc(ByteBuffer.wrap(dpii.getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(2));
- switch (type) {
- case LAG_REQUEST:
- tuner.markLag();
- break;
- }
+ private void handleStackDestroyedIntent(StackDestroyedIntent sdi) {
+ activeStacks.remove(sdi.getStack());
}
@IntentHandler
private void handleDataPacketOutboundIntent(DataPacketOutboundIntent dpoi) {
- ProtocolStack stack = this.stack.get();
- if (stack == null)
- return;
PacketType type = PacketType.fromCrc(ByteBuffer.wrap(dpoi.getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(2));
+ ClientServer filterServer = ClientServer.ZONE;
switch (type) {
- case CMD_START_SCENE:
- tuner.markStart();
+ case ERROR_MESSAGE:
+ case SERVER_ID:
+ case SERVER_NOW_EPOCH_TIME:
+ filterServer = null;
break;
- case CMD_SCENE_READY:
- tuner.markEnd();
+ case LOGIN_CLUSTER_STATUS:
+ case LOGIN_CLIENT_TOKEN:
+ case LOGIN_INCORRECT_CLIENT_ID:
+ case LOGIN_ENUM_CLUSTER:
+ case ENUMERATE_CHARACTER_ID:
+ case CHARACTER_CREATION_DISABLED:
+ filterServer = ClientServer.LOGIN;
break;
case HEART_BEAT_MESSAGE: {
HeartBeat heartbeat = new HeartBeat();
heartbeat.decode(NetBuffer.wrap(dpoi.getData()));
if (heartbeat.getPayload().length > 0) {
- stack.sendPing(heartbeat.getPayload());
+ for (ProtocolStack stack : activeStacks)
+ stack.sendPing(heartbeat.getPayload());
return;
}
break;
}
}
synchronized (outboundMutex) {
- stack.addOutbound(dpoi.getData());
+ if (filterServer == null) {
+ Log.d("Sending %d bytes to %s", dpoi.getData().length, activeStacks);
+ for (ProtocolStack stack : activeStacks)
+ stack.addOutbound(dpoi.getData());
+ } else {
+ final ClientServer finalFilterServer = filterServer;
+ ProtocolStack stack = activeStacks.stream().filter(s -> s.getServer() == finalFilterServer).findFirst().orElse(null);
+ if (stack != null) {
+ Log.d("Sending %d bytes to %s", dpoi.getData().length, stack);
+ stack.addOutbound(dpoi.getData());
+ }
+ }
}
}
@Multiplexer
private void handleAcknowledgement(ProtocolStack stack, Acknowledge ack) {
Log.t("Acknowledged: %d. Min Sequence: %d", ack.getSequence(), stack.getFirstUnacknowledgedOutbound());
- tuner.markAck();
synchronized (outboundMutex) {
stack.clearAcknowledgedOutbound(ack.getSequence());
for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
@@ -124,7 +146,6 @@ public class ClientOutboundDataService extends Service {
@Multiplexer
private void handleOutOfOrder(ProtocolStack stack, OutOfOrder ooo) {
- tuner.markOOO();
synchronized (outboundMutex) {
for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
if (outbound.getSequence() > ooo.getSequence())
@@ -135,38 +156,38 @@ public class ClientOutboundDataService extends Service {
}
private void clearSentBit() {
- ProtocolStack stack = this.stack.get();
- if (stack == null)
- return;
synchronized (outboundMutex) {
- for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
- outbound.setSent(false);
+ for (ProtocolStack stack : activeStacks) {
+ for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
+ outbound.setSent(false);
+ }
}
}
}
private void timerCallback() {
- ProtocolStack stack = this.stack.get();
- if (stack == null)
- return;
- int maxSend = tuner.getMaxSend();
+ int maxSend = data.getOutboundTunerMaxSend();
+ if (maxSend <= 0)
+ maxSend = 100;
synchronized (outboundMutex) {
- stack.fillOutboundPackagedBuffer(maxSend);
- int sent = 0;
- int runStart = Integer.MIN_VALUE;
- int runEnd = 0;
- for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
- runEnd = outbound.getSequence();
- if (runStart == Integer.MIN_VALUE) {
- runStart = runEnd;
+ for (ProtocolStack stack : activeStacks) {
+ stack.fillOutboundPackagedBuffer(maxSend);
+ int sent = 0;
+ int runStart = Integer.MIN_VALUE;
+ int runEnd = 0;
+ for (SequencedOutbound outbound : stack.getOutboundPackagedBuffer()) {
+ runEnd = outbound.getSequence();
+ if (runStart == Integer.MIN_VALUE) {
+ runStart = runEnd;
+ }
+ stack.send(outbound.getData());
+ Delay.sleepMicro(50);
+ if (sent++ >= maxSend)
+ break;
}
- stack.send(outbound.getData());
- Delay.sleepMicro(50);
- if (sent++ >= maxSend)
- break;
+ if (runStart != Integer.MIN_VALUE)
+ Log.t("Sending to %s: %d - %d", stack.getSource(), runStart, runEnd);
}
- if (runStart != Integer.MIN_VALUE)
- Log.t("Sending to %s: %d - %d", stack.getSource(), runStart, runEnd);
}
}
diff --git a/src/main/java/com/projectswg/forwarder/services/client/ClientProtocolService.java b/src/main/java/com/projectswg/forwarder/services/client/ClientProtocolService.java
index bbf6b41..ad077a3 100644
--- a/src/main/java/com/projectswg/forwarder/services/client/ClientProtocolService.java
+++ b/src/main/java/com/projectswg/forwarder/services/client/ClientProtocolService.java
@@ -1,7 +1,6 @@
package com.projectswg.forwarder.services.client;
import com.projectswg.forwarder.intents.client.SonyPacketInboundIntent;
-import com.projectswg.forwarder.intents.client.UpdateStackIntent;
import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import com.projectswg.forwarder.resources.networking.packets.ClientNetworkStatusUpdate;
import com.projectswg.forwarder.resources.networking.packets.KeepAlive;
@@ -12,30 +11,19 @@ import me.joshlarson.jlcommon.control.IntentMultiplexer;
import me.joshlarson.jlcommon.control.IntentMultiplexer.Multiplexer;
import me.joshlarson.jlcommon.control.Service;
-import java.util.concurrent.atomic.AtomicReference;
-
public class ClientProtocolService extends Service {
private static final int GALACTIC_BASE_TIME = 1323043200;
- private final AtomicReference stack;
private final IntentMultiplexer multiplexer;
public ClientProtocolService() {
- this.stack = new AtomicReference<>(null);
this.multiplexer = new IntentMultiplexer(this, ProtocolStack.class, Packet.class);
}
@IntentHandler
private void handleSonyPacketInboundIntent(SonyPacketInboundIntent spii) {
- ProtocolStack stack = this.stack.get();
- assert stack != null : "stack is null";
- multiplexer.call(stack, spii.getPacket());
- }
-
- @IntentHandler
- private void handleUpdateStackIntent(UpdateStackIntent sci) {
- stack.set(sci.getStack());
+ multiplexer.call(spii.getStack(), spii.getPacket());
}
@Multiplexer
diff --git a/src/main/java/com/projectswg/forwarder/services/client/ClientServerService.java b/src/main/java/com/projectswg/forwarder/services/client/ClientServerService.java
index 9c81b16..55c64a7 100644
--- a/src/main/java/com/projectswg/forwarder/services/client/ClientServerService.java
+++ b/src/main/java/com/projectswg/forwarder/services/client/ClientServerService.java
@@ -1,15 +1,14 @@
package com.projectswg.forwarder.services.client;
import com.projectswg.forwarder.Forwarder.ForwarderData;
-import com.projectswg.forwarder.intents.client.ClientConnectedIntent;
-import com.projectswg.forwarder.intents.client.ClientDisconnectedIntent;
-import com.projectswg.forwarder.intents.client.SonyPacketInboundIntent;
-import com.projectswg.forwarder.intents.client.UpdateStackIntent;
+import com.projectswg.forwarder.intents.client.*;
import com.projectswg.forwarder.intents.control.StartForwarderIntent;
import com.projectswg.forwarder.intents.control.StopForwarderIntent;
+import com.projectswg.forwarder.intents.server.ServerDisconnectedIntent;
import com.projectswg.forwarder.resources.networking.ClientServer;
import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import com.projectswg.forwarder.resources.networking.packets.*;
+import com.projectswg.forwarder.resources.networking.packets.Disconnect.DisconnectReason;
import me.joshlarson.jlcommon.control.IntentChain;
import me.joshlarson.jlcommon.control.IntentHandler;
import me.joshlarson.jlcommon.control.Service;
@@ -19,12 +18,13 @@ import me.joshlarson.jlcommon.utilities.ByteUtilities;
import java.net.*;
import java.nio.ByteBuffer;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.EnumMap;
+import java.util.Map;
public class ClientServerService extends Service {
private final IntentChain intentChain;
- private final AtomicReference stack;
+ private final Map stacks;
private ForwarderData data;
private UDPServer loginServer;
@@ -32,7 +32,7 @@ public class ClientServerService extends Service {
public ClientServerService() {
this.intentChain = new IntentChain();
- this.stack = new AtomicReference<>(null);
+ this.stacks = new EnumMap<>(ClientServer.class);
this.data = null;
this.loginServer = null;
this.zoneServer = null;
@@ -45,7 +45,8 @@ public class ClientServerService extends Service {
@Override
public boolean stop() {
- setStack(null);
+ closeConnection(ClientServer.LOGIN);
+ closeConnection(ClientServer.ZONE);
return true;
}
@@ -92,6 +93,12 @@ public class ClientServerService extends Service {
Log.i("Closed the login and zone udp servers");
}
+ @IntentHandler
+ private void handleServerDisconnectedIntent(ServerDisconnectedIntent sdi) {
+ closeConnection(ClientServer.LOGIN);
+ closeConnection(ClientServer.ZONE);
+ }
+
private void customizeUdpServer(DatagramSocket socket) {
try {
socket.setReuseAddress(false);
@@ -137,37 +144,73 @@ public class ClientServerService extends Service {
}
private void broadcast(InetSocketAddress source, ClientServer server, Packet parsed) {
- ProtocolStack stack = this.stack.get();
- if (parsed instanceof SessionRequest) {
- if (stack != null && stack.getServer() == ClientServer.ZONE)
- return;
- stack = new ProtocolStack(source, server, (remote, data) -> send(remote, server, data));
- stack.setConnectionId(((SessionRequest) parsed).getConnectionId());
- setStack(stack);
- stack.send(new SessionResponse(((SessionRequest) parsed).getConnectionId(), 0, (byte) 0, (byte) 0, (byte) 0, 496));
- }
- if (stack != null && parsed instanceof PingPacket) {
- stack.setPingSource(source);
- } else if (stack == null || !stack.getSource().equals(source) || stack.getServer() != server) {
+ ProtocolStack stack = process(source, server, parsed);
+ if (stack == null) {
Log.t("[%s]@%s DROPPED %s", source, server, parsed);
return;
}
Log.t("[%s]@%s sent: %s", source, server, parsed);
- intentChain.broadcastAfter(getIntentManager(), new SonyPacketInboundIntent(parsed));
- if (parsed instanceof Disconnect) {
- Log.d("Received client disconnect with id %d and reason %s", ((Disconnect) parsed).getConnectionId(), ((Disconnect) parsed).getReason());
- setStack(null);
- }
+ intentChain.broadcastAfter(getIntentManager(), new SonyPacketInboundIntent(stack, parsed));
}
- private void setStack(ProtocolStack stack) {
- Log.d("Updating stack: %s", stack);
- ProtocolStack oldStack = this.stack.getAndSet(stack);
- if (oldStack != null && stack == null)
- intentChain.broadcastAfter(getIntentManager(), new ClientDisconnectedIntent());
- if (stack != null && stack.getServer() == ClientServer.LOGIN)
+ private ProtocolStack process(InetSocketAddress source, ClientServer server, Packet parsed) {
+ if (parsed instanceof SessionRequest)
+ return onSessionRequest(source, server, (SessionRequest) parsed);
+ if (parsed instanceof Disconnect)
+ return onDisconnect(source, server, (Disconnect) parsed);
+
+ ProtocolStack stack = stacks.get(server);
+ if (stack == null)
+ return null;
+
+ if (parsed instanceof PingPacket) {
+ stack.setPingSource(source);
+ } else if (!stack.getSource().equals(source) || stack.getServer() != server) {
+ return null;
+ }
+
+ return stack;
+ }
+
+ private ProtocolStack onSessionRequest(InetSocketAddress source, ClientServer server, SessionRequest request) {
+ ProtocolStack stack = new ProtocolStack(source, server, (remote, data) -> send(remote, server, data));
+ stack.setConnectionId(request.getConnectionId());
+
+ openConnection(server, stack);
+ return stack;
+ }
+
+ private ProtocolStack onDisconnect(InetSocketAddress source, ClientServer server, Disconnect disconnect) {
+ // Sets the current stack to null if it matches the Disconnect packet
+ ProtocolStack stack = stacks.get(server);
+ if (stack != null && stack.getSource().equals(source) && stack.getConnectionId() == disconnect.getConnectionId()) {
+ closeConnection(server);
+ } else {
+ send(source, server, new Disconnect(disconnect.getConnectionId(), DisconnectReason.APPLICATION).encode().array());
+ }
+ return stack;
+ }
+
+ private void openConnection(ClientServer server, ProtocolStack stack) {
+ closeConnection(server);
+ if (server == ClientServer.LOGIN) {
+ closeConnection(ClientServer.ZONE);
intentChain.broadcastAfter(getIntentManager(), new ClientConnectedIntent());
- intentChain.broadcastAfter(getIntentManager(), new UpdateStackIntent(stack));
+ }
+ stacks.put(server, stack);
+
+ stack.send(new SessionResponse(stack.getConnectionId(), 0, (byte) 0, (byte) 0, (byte) 0, 496));
+ intentChain.broadcastAfter(getIntentManager(), new StackCreatedIntent(stack));
+ }
+
+ private void closeConnection(ClientServer server) {
+ ProtocolStack stack = stacks.remove(server);
+ if (stack == null)
+ return;
+ stack.send(new Disconnect(stack.getConnectionId(), DisconnectReason.APPLICATION));
+ intentChain.broadcastAfter(getIntentManager(), new StackDestroyedIntent(stack));
+ if (stacks.isEmpty())
+ intentChain.broadcastAfter(getIntentManager(), new ClientDisconnectedIntent());
}
private static Packet parse(byte [] rawData) {
diff --git a/src/main/java/com/projectswg/forwarder/services/crash/IntentRecordingService.java b/src/main/java/com/projectswg/forwarder/services/crash/IntentRecordingService.java
index c8e3f1c..ede798e 100644
--- a/src/main/java/com/projectswg/forwarder/services/crash/IntentRecordingService.java
+++ b/src/main/java/com/projectswg/forwarder/services/crash/IntentRecordingService.java
@@ -3,13 +3,11 @@ package com.projectswg.forwarder.services.crash;
import com.projectswg.forwarder.Forwarder.ForwarderData;
import com.projectswg.forwarder.intents.client.ClientConnectedIntent;
import com.projectswg.forwarder.intents.client.ClientDisconnectedIntent;
-import com.projectswg.forwarder.intents.client.UpdateStackIntent;
import com.projectswg.forwarder.intents.control.ClientCrashedIntent;
import com.projectswg.forwarder.intents.control.StartForwarderIntent;
import com.projectswg.forwarder.intents.control.StopForwarderIntent;
import com.projectswg.forwarder.intents.server.ServerConnectedIntent;
import com.projectswg.forwarder.intents.server.ServerDisconnectedIntent;
-import com.projectswg.forwarder.resources.networking.data.ProtocolStack;
import me.joshlarson.jlcommon.control.Intent;
import me.joshlarson.jlcommon.control.IntentHandler;
import me.joshlarson.jlcommon.control.Service;
@@ -80,15 +78,6 @@ public class IntentRecordingService extends Service {
log(cdi, "");
}
- @IntentHandler
- private void handleUpdateStackIntent(UpdateStackIntent usi) {
- ProtocolStack stack = usi.getStack();
- if (stack == null)
- log(usi, "Stack='null'");
- else
- log(usi, "Server='%s' Source='%s' ConnectionId='%d'", stack.getServer(), stack.getSource(), stack.getConnectionId());
- }
-
@IntentHandler
private void handleStartForwarderIntent(StartForwarderIntent sfi) {
this.data = sfi.getData();