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,7 +917,8 @@ public abstract class AbstractTeamspeakClientSocket
} }
try { try {
setState(ClientConnectionState.DISCONNECTED); if (getState() != 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,42 +155,69 @@ 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;
socket.setSoTimeout(timeout); while (socket.isBound()) {
socket.receive(packet); socket.setSoTimeout(timeout);
PacketHeader header; try {
socket.receive(packet);
} catch (SocketException ex) {
if (socket.isClosed()) throw new EOFException();
else throw ex;
}
try { if (remote == null || getState() == ClientConnectionState.DISCONNECTED)
header = getRole().getIn().getHeaderClass().newInstance(); break;
} catch (ReflectiveOperationException e) { else if (!packet.getAddress().equals(remote.getAddress()) || packet.getPort() != remote.getPort())
throw new RuntimeException(e); continue;
PacketHeader header;
try {
header = getRole().getIn().getHeaderClass().newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
ByteBuffer buffer = ByteBuffer
.wrap(packet.getData(), packet.getOffset(), packet.getLength())
.order(ByteOrder.BIG_ENDIAN);
header.read(buffer);
Ts3Debugging.debug("[NETWORK] READ" +
" id=" + header.getPacketId() +
" len=" + packet.getLength() +
" from " + packet.getSocketAddress());
return new NetworkPacket(
packet,
header,
buffer
);
} }
ByteBuffer buffer = ByteBuffer throw new IOException("disconnected");
.wrap(packet.getData(), packet.getOffset(), packet.getLength())
.order(ByteOrder.BIG_ENDIAN);
header.read(buffer);
Ts3Debugging.debug("[NETWORK] READ" +
" id=" + header.getPacketId() +
" len=" + packet.getLength() +
" from " + packet.getSocketAddress());
return new NetworkPacket(
packet,
header,
buffer
);
} }
@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,17 +959,23 @@ public class LocalTeamspeakClientSocket
throws throws
IOException, TimeoutException, IOException, TimeoutException,
ExecutionException, InterruptedException { ExecutionException, InterruptedException {
switch (getState()) { try {
case CONNECTING: switch (getState()) {
case RETRIEVING_DATA: case CONNECTING:
waitForState(ClientConnectionState.CONNECTED, 10000L); case RETRIEVING_DATA:
case CONNECTED: waitForState(ClientConnectionState.CONNECTED, 10000L);
writePacket(new PacketBody2Command( case CONNECTED:
ProtocolRole.CLIENT, writePacket(new PacketBody2Command(
new SingleCommand("clientdisconnect", ProtocolRole.CLIENT)) ProtocolRole.CLIENT,
); new SingleCommand("clientdisconnect", ProtocolRole.CLIENT))
);
break; waitForState(ClientConnectionState.DISCONNECTED, 30000L);
break;
}
} finally {
setState(ClientConnectionState.DISCONNECTED);
} }
} }
@@ -17,18 +17,18 @@ 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 {
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
Ts3Debugging.setEnabled(true);
LocalIdentity identity = LocalIdentity.load(
new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU="))
);
identity.improveSecurity(10);
while (true) { while (true) {
try { try {
Ts3Debugging.setEnabled(true);
LocalIdentity identity = LocalIdentity.load(
new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU="))
);
identity.improveSecurity(10);
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
client.setIdentity(identity); client.setIdentity(identity);
client.setNickname("Hello from Java"); client.setNickname("Hello from Java");