From dcfda1eb28ddcd3018d14d629dbb3ac80566ff98 Mon Sep 17 00:00:00 2001 From: Josh Larson Date: Mon, 9 Jan 2017 02:09:50 -0600 Subject: [PATCH] Added wait for client to acknowledge, for sending final packets --- src/com/projectswg/ClientConnection.java | 12 +++ src/com/projectswg/ClientReceiver.java | 13 +++ src/com/projectswg/ClientSender.java | 4 + src/com/projectswg/Connections.java | 7 ++ src/com/projectswg/control/Assert.java | 101 ++++++++++++++++++ src/com/projectswg/control/IntentManager.java | 4 +- .../projectswg/networking/NetInterceptor.java | 1 - .../networking/soe/Acknowledge.java | 5 +- 8 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 src/com/projectswg/control/Assert.java diff --git a/src/com/projectswg/ClientConnection.java b/src/com/projectswg/ClientConnection.java index afc81cf..dfedfef 100644 --- a/src/com/projectswg/ClientConnection.java +++ b/src/com/projectswg/ClientConnection.java @@ -6,6 +6,8 @@ import com.projectswg.control.Manager; import com.projectswg.networking.NetInterceptor; import com.projectswg.networking.Packet; import com.projectswg.networking.NetInterceptor.InterceptorProperties; +import com.projectswg.networking.soe.Disconnect; +import com.projectswg.networking.soe.Disconnect.DisconnectReason; public class ClientConnection extends Manager { @@ -36,6 +38,16 @@ public class ClientConnection extends Manager { return true; } + public void disconnect(DisconnectReason reason) { + sender.send(new Disconnect(sender.getConnectionId(), reason)); + } + + public void waitForClientAcknowledge() throws InterruptedException { + while (sender.getTransmittedSequence()-1 > receiver.getAckSequence()) { + Thread.sleep(1); + } + } + public void hardReset() { sender.hardReset(); receiver.hardReset(); diff --git a/src/com/projectswg/ClientReceiver.java b/src/com/projectswg/ClientReceiver.java index a87b06d..436b742 100644 --- a/src/com/projectswg/ClientReceiver.java +++ b/src/com/projectswg/ClientReceiver.java @@ -55,6 +55,7 @@ public class ClientReceiver extends Service { private ClientSender sender; private ClientConnectionStatus status; private short rxSequence; + private short ackSequence; private int port; private boolean zone; @@ -66,6 +67,8 @@ public class ClientReceiver extends Service { this.stateIntentChain = new IntentChain(); this.timeout = timeout; this.status = ClientConnectionStatus.DISCONNECTED; + this.rxSequence = -1; + this.ackSequence = -1; } @Override @@ -120,6 +123,8 @@ public class ClientReceiver extends Service { onDataChannel((DataChannelA) p); else if (p instanceof Fragmented) onFragmented((Fragmented) p); + else if (p instanceof Acknowledge) + onAcknowledge((Acknowledge) p); } } @@ -127,6 +132,10 @@ public class ClientReceiver extends Service { this.sender = sender; } + public short getAckSequence() { + return ackSequence; + } + public void reset() { rxSequence = -1; } @@ -301,6 +310,10 @@ public class ClientReceiver extends Service { process(combined); } + private void onAcknowledge(Acknowledge ack) { + this.ackSequence = ack.getSequence(); + } + private void onSWGPacket(byte [] data) { data = interceptor.interceptClient(data); recvIntentChain.broadcastAfter(new ClientToServerPacketIntent(data), getIntentManager()); diff --git a/src/com/projectswg/ClientSender.java b/src/com/projectswg/ClientSender.java index f953d17..9d82201 100644 --- a/src/com/projectswg/ClientSender.java +++ b/src/com/projectswg/ClientSender.java @@ -102,6 +102,10 @@ public class ClientSender extends Service { return super.stop(); } + public short getTransmittedSequence() { + return packager.getSequence(); + } + @Override public void onIntentReceived(Intent i) { if (i instanceof ServerToClientPacketIntent) { diff --git a/src/com/projectswg/Connections.java b/src/com/projectswg/Connections.java index f64ebe1..729f4d5 100644 --- a/src/com/projectswg/Connections.java +++ b/src/com/projectswg/Connections.java @@ -13,6 +13,7 @@ import com.projectswg.intents.ClientToServerPacketIntent; import com.projectswg.intents.ServerConnectionChangedIntent; import com.projectswg.intents.ServerToClientPacketIntent; import com.projectswg.networking.NetInterceptor.InterceptorProperties; +import com.projectswg.networking.soe.Disconnect.DisconnectReason; import com.projectswg.resources.ClientConnectionStatus; import com.projectswg.resources.ServerConnectionStatus; import com.projectswg.services.PacketRecordingService; @@ -140,6 +141,12 @@ public class Connections extends Manager { error += "\nInstalled Version: " + VERSION; client.send(new ErrorMessage("Network", error, false)); } + try { + client.waitForClientAcknowledge(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + client.disconnect(DisconnectReason.OTHER_SIDE_TERMINATED); client.hardReset(); } } diff --git a/src/com/projectswg/control/Assert.java b/src/com/projectswg/control/Assert.java new file mode 100644 index 0000000..6a48039 --- /dev/null +++ b/src/com/projectswg/control/Assert.java @@ -0,0 +1,101 @@ +/*********************************************************************************** +* Copyright (c) 2015 /// Project SWG /// www.projectswg.com * +* * +* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * +* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * +* Our goal is to create an emulator which will provide a server for players to * +* continue playing a game similar to the one they used to play. We are basing * +* it on the final publish of the game prior to end-game events. * +* * +* This file is part of Holocore. * +* * +* -------------------------------------------------------------------------------- * +* * +* Holocore 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. * +* * +* Holocore 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 Holocore. If not, see . * +* * +***********************************************************************************/ +package com.projectswg.control; + +import resources.server_info.Log; + +public class Assert { + + private static volatile AssertLevel level = AssertLevel.ASSERT; + + public static void setLevel(AssertLevel level) { + Assert.level = level; + } + + public static boolean debug() { + return level != AssertLevel.IGNORE; + } + + public static void notNull(Object o) { + if (debug() && o == null) + handle(new NullPointerException()); + } + + public static void isNull(Object o) { + if (debug() && o != null) + handle(new AssertionException()); + } + + public static void test(boolean expr) { + if (debug() && !expr) + handle(new AssertionException()); + } + + public static void fail() { + if (debug()) + handle(new AssertionException()); + } + + private static void handle(RuntimeException e) { + AssertLevel level = Assert.level; + switch (level) { + case WARN: + warn(e); + break; + case ASSERT: + throw e; + default: + break; + } + } + + private static void warn(Exception e) { + StackTraceElement [] elements = e.getStackTrace(); + if (elements.length <= 1) + Log.e("Assert", e); + else + Log.e(elements[elements.length-2].getClassName(), e); + } + + private static class AssertionException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public AssertionException() { + super(""); + } + + } + + public enum AssertLevel { + IGNORE, + WARN, + ASSERT + } + +} diff --git a/src/com/projectswg/control/IntentManager.java b/src/com/projectswg/control/IntentManager.java index 50fa969..9259d73 100644 --- a/src/com/projectswg/control/IntentManager.java +++ b/src/com/projectswg/control/IntentManager.java @@ -52,7 +52,6 @@ public class IntentManager { public IntentManager() { intentRegistrations = new HashMap>(); intentQueue = new IntentQueue(); - initialize(); broadcastRunnable = () -> { Intent i; synchronized (intentQueue) { @@ -82,8 +81,7 @@ public class IntentManager { protected void broadcastIntent(Intent i) { if (i == null) throw new NullPointerException("Intent cannot be null!"); - if (!initialized) - return; + Assert.test(initialized); synchronized (intentQueue) { intentQueue.add(i); } diff --git a/src/com/projectswg/networking/NetInterceptor.java b/src/com/projectswg/networking/NetInterceptor.java index cf77a4a..69df27b 100644 --- a/src/com/projectswg/networking/NetInterceptor.java +++ b/src/com/projectswg/networking/NetInterceptor.java @@ -67,7 +67,6 @@ public class NetInterceptor { g.setAddress("127.0.0.1"); g.setZonePort((short) properties.getPort()); g.setPingPort((short) properties.getPort()); - g.setPopulation(-1); } return cluster.encode().array(); } diff --git a/src/com/projectswg/networking/soe/Acknowledge.java b/src/com/projectswg/networking/soe/Acknowledge.java index a9d1dad..7de1659 100644 --- a/src/com/projectswg/networking/soe/Acknowledge.java +++ b/src/com/projectswg/networking/soe/Acknowledge.java @@ -29,6 +29,8 @@ package com.projectswg.networking.soe; import java.nio.ByteBuffer; +import resources.control.Assert; + import com.projectswg.networking.Packet; public class Acknowledge extends Packet { @@ -48,8 +50,7 @@ public class Acknowledge extends Packet { } public void decode(ByteBuffer data) { - if (data.array().length < 4) - return; + Assert.test(data.array().length == 4); data.position(2); sequence = getNetShort(data); }