Reconnection works now

This commit is contained in:
Manevolent
2018-08-13 09:48:30 -04:00
parent 89c483d3b9
commit ca869089cf
3 changed files with 100 additions and 60 deletions
@@ -26,6 +26,7 @@ import com.github.manevolent.ts3j.util.Ts3Debugging;
import com.github.manevolent.ts3j.util.Pair; import com.github.manevolent.ts3j.util.Pair;
import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.InvalidCipherTextException;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
@@ -225,6 +226,8 @@ public abstract class AbstractTeamspeakClientSocket
for (PacketKind kind : PacketKind.values()) { for (PacketKind kind : PacketKind.values()) {
packetStatistics.put(kind, new PacketStatistics()); packetStatistics.put(kind, new PacketStatistics());
} }
setTransformation(new InitPacketTransformation());
} }
public ClientConnectionState getState() { public ClientConnectionState getState() {
@@ -762,7 +765,7 @@ public abstract class AbstractTeamspeakClientSocket
} }
} }
throw new IllegalStateException("no longer reading"); throw new EOFException();
} }
/** /**
@@ -900,6 +903,8 @@ public abstract class AbstractTeamspeakClientSocket
while (isReading()) { while (isReading()) {
try { try {
readQueue.put(readPacket()); readQueue.put(readPacket());
} catch (EOFException e) {
break;
} catch (Throwable e) { } catch (Throwable e) {
if (e instanceof InterruptedException) { if (e instanceof InterruptedException) {
Thread.yield(); Thread.yield();
@@ -912,6 +917,7 @@ public abstract class AbstractTeamspeakClientSocket
} }
try { try {
if (getState() != ClientConnectionState.DISCONNECTED)
setState(ClientConnectionState.DISCONNECTED); setState(ClientConnectionState.DISCONNECTED);
} catch (Throwable e1) { } catch (Throwable e1) {
exceptionHandler.accept(e1); exceptionHandler.accept(e1);
@@ -24,6 +24,7 @@ import com.github.manevolent.ts3j.util.HighPrecisionRecurrentTask;
import com.github.manevolent.ts3j.util.Ts3Debugging; import com.github.manevolent.ts3j.util.Ts3Debugging;
import com.github.manevolent.ts3j.util.Pair; import com.github.manevolent.ts3j.util.Pair;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -37,15 +38,7 @@ public class LocalTeamspeakClientSocket
extends AbstractTeamspeakClientSocket extends AbstractTeamspeakClientSocket
implements CommandProcessor { implements CommandProcessor {
private final DatagramSocket socket; private DatagramSocket socket;
{
try {
socket = new DatagramSocket();
} catch (SocketException e) {
throw new RuntimeException(e);
}
}
private final DatagramPacket packet = new DatagramPacket(new byte[500], 500); private final DatagramPacket packet = new DatagramPacket(new byte[500], 500);
@@ -53,6 +46,7 @@ public class LocalTeamspeakClientSocket
private final ExecutorService commandExecutionService = Executors.newCachedThreadPool(); private final ExecutorService commandExecutionService = Executors.newCachedThreadPool();
private final Object commandSendLock = new Object(); private final Object commandSendLock = new Object();
private volatile InetSocketAddress remote;
private Microphone microphone; private Microphone microphone;
private Thread microphoneThread; private Thread microphoneThread;
@@ -161,9 +155,23 @@ public class LocalTeamspeakClientSocket
protected NetworkPacket readNetworkPacket(int timeout) throws protected NetworkPacket readNetworkPacket(int timeout) throws
IOException, IOException,
SocketTimeoutException { SocketTimeoutException {
DatagramSocket socket = this.socket;
InetSocketAddress remote = this.remote;
while (socket.isBound()) {
socket.setSoTimeout(timeout); socket.setSoTimeout(timeout);
try {
socket.receive(packet); socket.receive(packet);
} catch (SocketException ex) {
if (socket.isClosed()) throw new EOFException();
else throw ex;
}
if (remote == null || getState() == ClientConnectionState.DISCONNECTED)
break;
else if (!packet.getAddress().equals(remote.getAddress()) || packet.getPort() != remote.getPort())
continue;
PacketHeader header; PacketHeader header;
@@ -191,12 +199,25 @@ public class LocalTeamspeakClientSocket
); );
} }
throw new IOException("disconnected");
}
@Override @Override
protected void writeNetworkPacket(NetworkPacket packet) throws IOException { protected void writeNetworkPacket(NetworkPacket packet) throws IOException {
InetSocketAddress remote = this.remote;
ClientConnectionState state = this.getState();
if (state == ClientConnectionState.DISCONNECTED)
throw new IllegalStateException(state.name());
else if (remote == null)
throw new IOException(new NullPointerException("remote"));
Ts3Debugging.debug("[NETWORK] WRITE id=" + packet.getHeader().getPacketId() + " len=" + Ts3Debugging.debug("[NETWORK] WRITE id=" + packet.getHeader().getPacketId() + " len=" +
packet.getDatagram().getLength() packet.getDatagram().getLength()
+ " to " + + " to " +
socket.getRemoteSocketAddress()); remote.toString());
packet.getDatagram().setSocketAddress(remote);
socket.send(packet.getDatagram()); socket.send(packet.getDatagram());
} }
@@ -227,6 +248,8 @@ public class LocalTeamspeakClientSocket
} }
serverId = null; serverId = null;
remote = null;
} }
/** /**
@@ -239,15 +262,22 @@ public class LocalTeamspeakClientSocket
public void connect(InetSocketAddress remote, String password, long timeout) public void connect(InetSocketAddress remote, String password, long timeout)
throws IOException, TimeoutException { throws IOException, TimeoutException {
try { try {
Ts3Debugging.debug("Connecting to " + remote + "...");
ClientConnectionState connectionState = getState(); ClientConnectionState connectionState = getState();
if (connectionState != ClientConnectionState.DISCONNECTED) if (connectionState != ClientConnectionState.DISCONNECTED)
throw new IllegalStateException(connectionState.name()); throw new IllegalStateException(connectionState.name());
Ts3Debugging.debug("Connecting to " + remote + "...");
setClientId(0); setClientId(0);
if (remote.isUnresolved())
remote = new InetSocketAddress(remote.getAddress().getHostAddress(), remote.getPort());
if (socket != null) socket.close();
socket = new DatagramSocket();
this.remote = remote;
serverId = null; serverId = null;
awaitingCommands.clear(); awaitingCommands.clear();
acceptingReturnCode = 0; acceptingReturnCode = 0;
@@ -256,8 +286,6 @@ public class LocalTeamspeakClientSocket
if (password != null) setOption("client.password", password); if (password != null) setOption("client.password", password);
socket.connect(remote);
setState(ClientConnectionState.CONNECTING); setState(ClientConnectionState.CONNECTING);
waitForState(ClientConnectionState.CONNECTED, timeout); waitForState(ClientConnectionState.CONNECTED, timeout);
@@ -282,7 +310,7 @@ public class LocalTeamspeakClientSocket
@Override @Override
protected boolean isReading() { protected boolean isReading() {
return socket.isConnected(); return super.isReading();
} }
@Override @Override
@@ -931,6 +959,7 @@ public class LocalTeamspeakClientSocket
throws throws
IOException, TimeoutException, IOException, TimeoutException,
ExecutionException, InterruptedException { ExecutionException, InterruptedException {
try {
switch (getState()) { switch (getState()) {
case CONNECTING: case CONNECTING:
case RETRIEVING_DATA: case RETRIEVING_DATA:
@@ -941,8 +970,13 @@ public class LocalTeamspeakClientSocket
new SingleCommand("clientdisconnect", ProtocolRole.CLIENT)) new SingleCommand("clientdisconnect", ProtocolRole.CLIENT))
); );
waitForState(ClientConnectionState.DISCONNECTED, 30000L);
break; break;
} }
} finally {
setState(ClientConnectionState.DISCONNECTED);
}
} }
} }
@@ -17,8 +17,9 @@ import static org.junit.Assert.assertEquals;
public class ServerConnectionTest { public class ServerConnectionTest {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
while (true) {
try { LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
Ts3Debugging.setEnabled(true); Ts3Debugging.setEnabled(true);
LocalIdentity identity = LocalIdentity.load( LocalIdentity identity = LocalIdentity.load(
@@ -26,9 +27,8 @@ public class ServerConnectionTest {
); );
identity.improveSecurity(10); identity.improveSecurity(10);
while (true) {
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket(); try {
client.setIdentity(identity); client.setIdentity(identity);
client.setNickname("Hello from Java"); client.setNickname("Hello from Java");