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();