diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java index c0e2149..4463a43 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java @@ -151,6 +151,8 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { } else if (packet.getBody() instanceof PacketBody2Command) { SimpleCommand command = ((PacketBody2Command) packet.getBody()).parse(); + Ts3Debugging.debug(command.build()); + if (command.getName().equalsIgnoreCase("initivexpand2")) { // 3.2.2 initivexpand2 (Client <- Server) @@ -160,9 +162,9 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { throw new IllegalArgumentException("ot constant != 1: " + command.get("ot").getValue()); byte[] license = Base64.getDecoder().decode(command.get("l").getValue()); - byte[] licsense_validation = !command.has("tvd") ? + /*byte[] licsense_validation = !command.has("tvd") && command.get("tvd").getValue() != null ? null : - Base64.getDecoder().decode(command.get("tvd").getValue()); + Base64.getDecoder().decode(command.get("tvd").getValue());*/ byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega @@ -187,29 +189,19 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { Ts3Debugging.debug("Sending clientek..."); - PacketBody2Command clientek = new PacketBody2Command(ProtocolRole.CLIENT); - clientek.setText( + getClient().sendCommand( new SimpleCommand( "clientek", ProtocolRole.CLIENT, new CommandSingleParameter("ek", Base64.getEncoder().encodeToString(keyPair.getKey())), new CommandSingleParameter("proof", Base64.getEncoder().encodeToString(signature)) - ).build() + ) ); - Ts3Debugging.debug(clientek.getText()); - - getClient().writePacket(clientek); - - getClient().setSecureParameters( - Ts3Crypt.cryptoInit2(license, alphaBytes, omega, proof, beta, keyPair.getValue()) - ); + getClient().setSecureParameters(Ts3Crypt.cryptoInit2(license, alphaBytes, beta, keyPair.getValue())); Ts3Debugging.debug("Sending clientinit..."); - PacketBody2Command clientinit = new PacketBody2Command(ProtocolRole.CLIENT); - - clientinit.setText( - new SimpleCommand( + getClient().sendCommand(new SimpleCommand( "clientinit", ProtocolRole.CLIENT, new CommandSingleParameter("client_nickname", "test"), @@ -235,12 +227,8 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { "hwid", "+LyYqbDqOvJJpN5pdAbF8/v5kZ0=" ) - ).build() + ) ); - - Ts3Debugging.debug(clientinit.getText()); - - getClient().writePacket(clientinit); } } } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java index c2f18f6..040429f 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java @@ -5,6 +5,7 @@ import com.github.manevolent.ts3j.command.response.CommandResponse; import com.github.manevolent.ts3j.identity.Identity; import com.github.manevolent.ts3j.protocol.NetworkPacket; import com.github.manevolent.ts3j.protocol.Packet; +import com.github.manevolent.ts3j.protocol.ProtocolRole; import com.github.manevolent.ts3j.protocol.SocketRole; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.header.ClientPacketHeader; @@ -36,9 +37,9 @@ public abstract class AbstractTeamspeakClientSocket private final Object connectionStateLock = new Object(); private final LinkedBlockingDeque readQueue = new LinkedBlockingDeque<>(65536); - private final Map reassemblyQueue = new LinkedHashMap<>(); - private final Map clientOptions = new LinkedHashMap<>(); - private final Map sendQueue = new LinkedHashMap<>(); + private final Map reassemblyQueue = new ConcurrentHashMap<>(); + private final Map clientOptions = new ConcurrentHashMap<>(); + private final Map sendQueue = new ConcurrentHashMap<>(); private Identity identity = null; private ClientConnectionState connectionState = null; @@ -153,12 +154,12 @@ public abstract class AbstractTeamspeakClientSocket } /** - * Sends a command to the remote server. + * Sends a command to the remote. * @param command Command to send. * @return Command response object to track command response. * @throws IOException */ - public CommandResponse sendCommand(Command command) throws IOException { + public CommandResponse sendCommand(Command command) throws IOException, TimeoutException { if (command.willExpectResponse() && !isConnected()) throw new IOException("not connected"); @@ -175,9 +176,12 @@ public abstract class AbstractTeamspeakClientSocket response.setDispatchedTime(System.currentTimeMillis()); + writePacket(new PacketBody2Command(ProtocolRole.CLIENT, command)); + return response; } + @Override public void writePacket(PacketBody body) throws IOException, TimeoutException { PacketHeader header; @@ -316,7 +320,7 @@ public abstract class AbstractTeamspeakClientSocket // Find if the packet must be acknowledged and create a promise for that action boolean willAcknowledge = packet.getHeader().getType().getAcknolwedgedBy() != null; - PacketResponse response; + final PacketResponse response; if (willAcknowledge) sendQueue.put( @@ -342,15 +346,14 @@ public abstract class AbstractTeamspeakClientSocket if (getState() == ClientConnectionState.DISCONNECTED) throw new IllegalStateException("no longer connected"); - response.getFuture().get(1000L, TimeUnit.MILLISECONDS); + // Wait one cycle for an ACK + response.waitForAcknowledgement(1000); break; } catch (TimeoutException e) { response.resend(); } catch (CancellationException e) { throw e; - } catch (InterruptedException e) { - - } catch (ExecutionException e) { + } catch (Exception e) { throw new RuntimeException(e); } } @@ -456,9 +459,11 @@ public abstract class AbstractTeamspeakClientSocket // Find if the packet is itself an acknowledgement switch (packet.getHeader().getType()) { case ACK: - int packetId = packet.getHeader().getPacketId(); + int packetId = ((PacketBody6Ack)packet.getBody()).getPacketId(); PacketResponse response = sendQueue.get(packetId); - if (response != null) response.getFuture().complete(packet); + if (response != null) { + response.acknowledge(packet); + } break; case ACK_LOW: break; @@ -578,9 +583,9 @@ public abstract class AbstractTeamspeakClientSocket private class PacketResponse { private final NetworkPacket sentPacket; - private final CompletableFuture future = new CompletableFuture<>(); + private final CompletableFuture future = new CompletableFuture<>(); private long lastSent = 0L; - private int tries, maxTries; + private int tries = 1, maxTries; private boolean willResend; public PacketResponse(NetworkPacket sentPacket,int maxTries) { @@ -596,10 +601,23 @@ public abstract class AbstractTeamspeakClientSocket public void resend() throws IOException { AbstractTeamspeakClientSocket.this.writeNetworkPacket(sentPacket); - + setLastSent(System.currentTimeMillis()); tries ++; } + public boolean waitForAcknowledgement() + throws ExecutionException, InterruptedException { + Packet acknowledgement = future.get(); + return acknowledgement != null; + } + + public boolean waitForAcknowledgement(long millis) + throws TimeoutException, ExecutionException, InterruptedException { + Packet acknowledgement = future.get(millis, TimeUnit.MILLISECONDS); + + return acknowledgement != null; + } + public boolean isWillResend() { return willResend; } @@ -616,8 +634,8 @@ public abstract class AbstractTeamspeakClientSocket return lastSent; } - public CompletableFuture getFuture() { - return future; + public void acknowledge(Packet p) { + future.complete(p); } public void setLastSent(long lastSent) { diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java index 01901c5..17372a5 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java @@ -102,7 +102,7 @@ public class LocalTeamspeakClientSocket extends AbstractTeamspeakClientSocket { setGenerationId(0); setOption("client.hostname", remote.getHostString()); - setOption("client.password", password); + //setOption("client.password", password); socket.connect(remote); diff --git a/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java b/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java index a8e66ae..9772c8d 100644 --- a/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java +++ b/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java @@ -56,7 +56,6 @@ public final class Ts3Crypt { } public static Ts3Crypt.SecureChannelParameters cryptoInit2(byte[] license, byte[] alpha, - byte[] omega, byte[] proof, byte[] beta, byte[] privateKey) { // 3.2.2.2 Parsing the license List licenses = License.readLicenses(ByteBuffer.wrap(license)); diff --git a/src/test/java/com/github/manevolent/ts3j/CryptoInit2Test.java b/src/test/java/com/github/manevolent/ts3j/CryptoInit2Test.java index 0b3d58e..be90ada 100644 --- a/src/test/java/com/github/manevolent/ts3j/CryptoInit2Test.java +++ b/src/test/java/com/github/manevolent/ts3j/CryptoInit2Test.java @@ -15,13 +15,11 @@ public class CryptoInit2Test extends TestCase { public void testParser() throws Exception { byte[] licenseBytes = hexStringToByteArray("0100358541498A24ACD30157918B8F50955C0DAE970AB65372CBE407415FCF3E029B02084D15E00AA793600700000020416E6F6E796D6F7573000047D9E4DC25AA2E90ACD4DB5FA61C8FED369B346D84C2CA2FCCCA86F73AFEF092200A77C8810A787141"); byte[] alpha = hexStringToByteArray("9500A5DB3B50ACECAB81"); - byte[] omega = hexStringToByteArray("304B03020700020120022025D13CF0C5A17A467961B04418E015941D6C6558DA6AEC79CFFDDA1DEF8AB55202200F3B3F0D3A4F1C5C02AD1F9A3A5114AC58E89905792FBB83AD4FFE7F82ACAADA"); - byte[] proof = hexStringToByteArray("3046022100F4B921DDB2C9737D9AB100BA251D11216DF1601C62AF17150E6FC29A2C6EEC0F022100FC8948E595BBD895A2FDFE0EB22A5241655BD47591F8D2733035CF76A72245AD"); byte[] beta = hexStringToByteArray("EAFFC9A8BC996B25C8AA700264E99E372ECCDEB1C121D6EC0F4D49FB46CEEBA4E3C724B3070FD70CB03D7BC08129205690ECE228CA7C"); byte[] privateKey = hexStringToByteArray("102E591ABA4508129E812FF3437E2DDD3CA1F1EC341117CA3514CC347A7C2A77"); Ts3Crypt.SecureChannelParameters result = - Ts3Crypt.cryptoInit2(licenseBytes, alpha, omega, proof, beta, privateKey); + Ts3Crypt.cryptoInit2(licenseBytes, alpha, beta, privateKey); assertEquals(Ts3Debugging.getHex(result.getIvStruct()), "E4082A92F71C96A947452F5582EF2879B2051ED2D3F2C6B0643CF5A266EE6B5180573C2F5F3F1C4AC579188366F16AE0EADC3AAF860805D8F2A831E9E49F4513"); assertEquals(Ts3Debugging.getHex(result.getFakeSignature()), "54F2B4D661E0F9AB"); diff --git a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java index 4e18262..08f2e3f 100644 --- a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java @@ -29,7 +29,7 @@ public class ServerConnectionTest { client.setIdentity(localIdentity); client.connect(new InetSocketAddress( - "voice.teamspeak.com", + "ts.teamlixo.net", 9987), null, 10000L