diff --git a/LICENSE b/LICENSE index 8b28719..0ccad99 100644 --- a/LICENSE +++ b/LICENSE @@ -127,7 +127,7 @@ Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system +(kernel, generationWindowSize system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. diff --git a/src/main/java/Punisher/NaCl/Internal/Sha512.java b/src/main/java/Punisher/NaCl/Internal/Sha512.java index de6d40f..18a3ac6 100644 --- a/src/main/java/Punisher/NaCl/Internal/Sha512.java +++ b/src/main/java/Punisher/NaCl/Internal/Sha512.java @@ -29,9 +29,9 @@ public class Sha512 if (offset < 0) throw new Exception("offset"); if (count < 0) - throw new Exception("count"); + throw new Exception("put"); if (data.length - offset < count) - throw new Exception("Requires offset + count <= data.Length"); + throw new Exception("Requires offset + put <= data.Length"); Array16 block = new Array16(); int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); diff --git a/src/main/java/com/github/manevolent/ts3j/api/FileTransfer.java b/src/main/java/com/github/manevolent/ts3j/api/FileTransfer.java index 58f48a1..198d421 100644 --- a/src/main/java/com/github/manevolent/ts3j/api/FileTransfer.java +++ b/src/main/java/com/github/manevolent/ts3j/api/FileTransfer.java @@ -155,7 +155,7 @@ public class FileTransfer extends Wrapper { /** * Returns how many milliseconds have elapsed since the file transfer was first announced to - * the server. This value will count up even if the file transfer has not yet been started, + * the server. This value will put up even if the file transfer has not yet been started, * but will stop if the transfer has been paused or is complete. * * @return the transfer runtime in milliseconds diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/RingQueue.java b/src/main/java/com/github/manevolent/ts3j/protocol/RingQueue.java deleted file mode 100644 index 4b669e4..0000000 --- a/src/main/java/com/github/manevolent/ts3j/protocol/RingQueue.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.github.manevolent.ts3j.protocol; - -public class RingQueue { - private static final int - NOT_SET = 0x00, - SET = 0x01, - OUT_OF_WINDOW = 0x00, - IN_WINDOW = 0x10; - - private boolean[] ringBufferSet; - - private final int initialBufferSize = 16; - private int currentStart, currentLength; - - private int mappedBaseOffset; - private final int mappedMod; - private int generation; - - private final int maxBufferSize; - - public RingQueue(int maxBufferSize, int mod) { - if (maxBufferSize == -1) - { - this.maxBufferSize = (mod / 2) - 1; - } - else - { - if (maxBufferSize >= mod) - throw new IllegalArgumentException("Modulo must be bigger than buffer size"); - - this.maxBufferSize = maxBufferSize; - } - - int setBufferSize = Math.min(initialBufferSize, maxBufferSize); - ringBufferSet = new boolean[setBufferSize]; - mappedMod = mod; - - clear(); - } - - private void bufferSet(int index) { - bufferExtend(index); - int local = indexToLocal(index); - int newLength = local - currentStart + 1 + (local >= currentStart ? 0 : ringBufferSet.length); - currentLength = Math.max(currentLength, newLength); - ringBufferSet[local] = true; - } - - private boolean stateGet(int index) { - bufferExtend(index); - int local = indexToLocal(index); - return ringBufferSet[local]; - } - - private void bufferPop() { - ringBufferSet[currentStart] = false; - - currentStart = (currentStart + 1) % ringBufferSet.length; - currentLength --; - } - - private void bufferExtend(int index) { - if (index < ringBufferSet.length) - return; - if (index >= maxBufferSize) - throw new IllegalArgumentException("the index does not fit into the maximal buffer size"); - int extendto = index < ringBufferSet.length * 2 - ? Math.min(ringBufferSet.length * 2, maxBufferSize) - : Math.min(index + ringBufferSet.length, maxBufferSize); - - Object[] extRingBuffer = new Object[extendto]; - boolean[] extRingBufferSet = new boolean[extendto]; - - System.arraycopy(ringBufferSet, currentStart, extRingBufferSet, 0, ringBufferSet.length - currentStart); - System.arraycopy(ringBufferSet, 0, extRingBufferSet, ringBufferSet.length - currentStart, currentStart); - - currentStart = 0; - ringBufferSet = extRingBufferSet; - } - - private int indexToLocal(int index) { - return (currentStart + index) % ringBufferSet.length; - } - - public void clear() - { - currentStart = 0; - currentLength = 0; - for (int i = 0; i < ringBufferSet.length; i ++) ringBufferSet[i] = false; - mappedBaseOffset = 0; - generation = 0; - } - - public void set(int mappedValue) { - int index = mappedToIndex(mappedValue); - - if (isSetIndex(index) != ItemSetStatus.IN_WINDOW_NOT_SET) - throw new IllegalStateException("object cannot be set"); - - bufferSet(index); - } - - private int mappedToIndex(int mappedValue) { - if (mappedValue >= mappedMod) - throw new ArrayIndexOutOfBoundsException("mappedValue"); - - if (isNextGen(mappedValue)) { - return (mappedValue + mappedMod) - mappedBaseOffset; - } else { - return mappedValue - mappedBaseOffset; - } - } - - public boolean isNextGen(int mappedValue) { - return mappedBaseOffset > mappedMod - maxBufferSize && mappedValue < maxBufferSize; - } - - public int getGeneration(int mappedValue) { - return generation + (isNextGen(mappedValue) ? 1 : 0); - } - - private ItemSetStatus isSetIndex(int index) { - if (index < 0) - return ItemSetStatus.OUT_OF_WINDOW_SET; - else if (index > currentLength && index < maxBufferSize) - return ItemSetStatus.IN_WINDOW_NOT_SET; - else if (index >= maxBufferSize) - return ItemSetStatus.OUT_OF_WINDOW_NOT_SET; - - return stateGet(index) ? ItemSetStatus.IN_WINDOW_SET : ItemSetStatus.IN_WINDOW_NOT_SET; - } - - public int getCount() { - return currentLength; - } - - public boolean isSet(int packetId) { - return isSetIndex(packetId) == ItemSetStatus.IN_WINDOW_SET; - } - - public enum ItemSetStatus { - OUT_OF_WINDOW_NOT_SET(0x00), - OUT_OF_WINDOW_SET(0x01), - IN_WINDOW_NOT_SET(0x10), - IN_WINDOW_SET(0x11); - - private final int index; - - ItemSetStatus(int index) { - this.index = index; - } - - public int getIndex() { - return index; - } - - public static ItemSetStatus fromId(int index) { - for (ItemSetStatus value : values()) - if (value.getIndex() == index) return value; - - throw new IllegalArgumentException("invalid index: " + index); - } - } -} diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/header/PacketHeader.java b/src/main/java/com/github/manevolent/ts3j/protocol/header/PacketHeader.java index 77b04bf..b677b5f 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/header/PacketHeader.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/header/PacketHeader.java @@ -107,6 +107,7 @@ public abstract class PacketHeader { } public void setGeneration(int packetGeneration) { + if (packetGeneration < 0) throw new IllegalArgumentException("packetGeneration"); this.packetGeneration = packetGeneration; } } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody0Voice.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody0Voice.java index 12452d9..173241f 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody0Voice.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody0Voice.java @@ -2,6 +2,7 @@ package com.github.manevolent.ts3j.protocol.packet; import com.github.manevolent.ts3j.enums.CodecType; import com.github.manevolent.ts3j.protocol.ProtocolRole; +import com.github.manevolent.ts3j.util.Ts3Debugging; import java.nio.ByteBuffer; diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBodyType.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBodyType.java index 96c9624..dec3c68 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBodyType.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBodyType.java @@ -1,7 +1,7 @@ package com.github.manevolent.ts3j.protocol.packet; public enum PacketBodyType { - VOICE(0x0, PacketBody0Voice.class, null, false, false, false, false, false), + VOICE(0x0, PacketBody0Voice.class, null, true, false, false, false, false), VOICE_WHISPER(0x1, PacketBody1VoiceWhisper.class, null, false, false, false, false, false), PONG(0x5, PacketBody5Pong.class, null, false, false, false, false, false), PING(0x4, PacketBody4Ping.class, PONG, false, false, false, false, false), diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java index c0f6161..a1f7da2 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java @@ -56,8 +56,8 @@ public class PacketTransformation { // ivStruct[0] = ivStruct[0] xor ((PId & 0xFF00) >> 8) // ivStruct[1] = ivStruct[1] xor ((PId & 0x00FF) >> 0) - key[0] = (byte) (key[0] ^ ((byte) (header.getPacketId() & 0xFF) >> 8) & 0xFF); - key[1] = (byte) (key[1] ^ ((byte) (header.getPacketId() & 0xFF) >> 0) & 0xFF); + key[0] = (byte) (key[0] ^ (header.getPacketId() >> 8) & 0xFF); + key[1] = (byte) (key[1] ^ (header.getPacketId() >> 0) & 0xFF); return new Pair<>(key, nonce); } 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 ea76bae..8403c22 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 @@ -4,7 +4,6 @@ import com.github.manevolent.ts3j.command.*; 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.RingQueue; import com.github.manevolent.ts3j.protocol.SocketRole; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.header.ClientPacketHeader; @@ -49,8 +48,8 @@ public abstract class AbstractTeamspeakClientSocket private final Map sendQueue = new ConcurrentHashMap<>(); private final Map sendQueueLow = new ConcurrentHashMap<>(); - private final Map localSendCounter = new ConcurrentHashMap<>(); - private final Map remoteQueue = new ConcurrentHashMap<>(); + private final Map localSendCounter = new ConcurrentHashMap<>(); + private final Map remoteSendCounter = new ConcurrentHashMap<>(); private CommandProcessor commandProcessor; @@ -89,12 +88,12 @@ public abstract class AbstractTeamspeakClientSocket // Initialize counters for (PacketBodyType bodyType : PacketBodyType.values()) { if (bodyType == PacketBodyType.INIT1) { - localSendCounter.put(bodyType, new PacketCounterZero()); + localSendCounter.put(bodyType, new LocalCounterZero()); + remoteSendCounter.put(bodyType, new RemoteCounterZero()); } else { - localSendCounter.put(bodyType, new PacketCounterFull(true)); + localSendCounter.put(bodyType, new LocalCounterFull(65536, true)); + remoteSendCounter.put(bodyType, new RemoteCounterFull(65536, 100)); } - - remoteQueue.put(bodyType, new RingQueue(100, 65536)); } } @@ -216,7 +215,7 @@ public abstract class AbstractTeamspeakClientSocket case ACK: counter = new Pair<>( ((PacketBody6Ack)packet.getBody()).getPacketId(), - remoteQueue.get(PacketBodyType.ACK).getGeneration( + remoteSendCounter.get(PacketBodyType.ACK).getGeneration( ((PacketBody6Ack) packet.getBody()).getPacketId() ) ); @@ -224,7 +223,7 @@ public abstract class AbstractTeamspeakClientSocket case ACK_LOW: counter = new Pair<>( ((PacketBody7AckLow)packet.getBody()).getPacketId(), - remoteQueue.get(PacketBodyType.ACK_LOW).getGeneration( + remoteSendCounter.get(PacketBodyType.ACK_LOW).getGeneration( ((PacketBody7AckLow) packet.getBody()).getPacketId() ) ); @@ -232,7 +231,7 @@ public abstract class AbstractTeamspeakClientSocket case PONG: counter = new Pair<>( ((PacketBody5Pong)packet.getBody()).getPacketId(), - remoteQueue.get(PacketBodyType.PONG).getGeneration( + remoteSendCounter.get(PacketBodyType.PONG).getGeneration( ((PacketBody5Pong) packet.getBody()).getPacketId() ) ); @@ -414,11 +413,6 @@ public abstract class AbstractTeamspeakClientSocket private Packet readPacketIntl(NetworkPacket networkPacket) throws IOException { if (networkPacket.getHeader() == null) throw new NullPointerException("header"); - RingQueue ring = remoteQueue.get(networkPacket.getHeader().getType()); - int currentGeneration = ring == null ? 0 : ring.getGeneration(networkPacket.getHeader().getPacketId()); - - networkPacket.getHeader().setGeneration(currentGeneration); - Packet packet = new Packet(networkPacket.getHeader().getRole()); packet.setHeader(networkPacket.getHeader()); @@ -432,8 +426,7 @@ public abstract class AbstractTeamspeakClientSocket "packet is fragment, but not splittable" ); - boolean encrypted = !networkPacket.getHeader().getPacketFlag(HeaderFlag.UNENCRYPTED) && - networkPacket.getHeader().getType().canEncrypt(); + boolean encrypted = !networkPacket.getHeader().getPacketFlag(HeaderFlag.UNENCRYPTED); if (networkPacket.getHeader().getType().mustEncrypt() && !encrypted) throw new IllegalArgumentException( @@ -446,7 +439,7 @@ public abstract class AbstractTeamspeakClientSocket // Decrypt if (encrypted) { Ts3Debugging.debug("[PROTOCOL] DECRYPT " + networkPacket.getHeader().getType().name() - + " generation=" + currentGeneration); + + " generation=" + networkPacket.getHeader().getGeneration()); try { packetBuffer = ByteBuffer.wrap( @@ -521,6 +514,15 @@ public abstract class AbstractTeamspeakClientSocket continue; } + // Get packet generation + RemoteCounter counter = remoteSendCounter.get(networkPacket.getHeader().getType()); + int generation = 0; + if (counter != null) { + generation = counter.getGeneration(networkPacket.getHeader().getPacketId()); + } + networkPacket.getHeader().setGeneration(generation); + + // Read packet (decrypt, decompress, etc) Packet packet = readPacketIntl(networkPacket); // Find if the packet must be acknowledged @@ -561,16 +563,14 @@ public abstract class AbstractTeamspeakClientSocket if (packet.getHeader().getType().canResend() && packet.getHeader().getType() != PacketBodyType.INIT1) { // Find if we already acknowledged this packet - RingQueue ring = remoteQueue.get(packet.getHeader().getType()); - if (ring.isSet(packet.getHeader().getPacketId())) { + if (!counter.put(packet.getHeader().getPacketId())) { Ts3Debugging.debug("[PROTOCOL] Ignoring handling resent packet: " + packet + " " + packet.getHeader().getType().name() + " id=" + - packet.getHeader().getPacketId()); + packet.getHeader().getPacketId() + " generation=" + + packet.getHeader().getGeneration()); continue; // Drop the packet - } else { - ring.set(packet.getHeader().getPacketId()); } } @@ -809,19 +809,249 @@ public abstract class AbstractTeamspeakClientSocket } } - private interface PacketCounter { - Pair next(); - int getPacketId(); - boolean setPacketId(int packetId); - int getGenerationId(); - void setGenerationId(int i); + public interface RemoteCounter { - default Pair current() { - return new Pair<>(getPacketId(), getGenerationId()); + /** + * Gets the generation for the specified packet ID. + * + * @param packetId packet ID + * @return expected generation + */ + int getGeneration(int packetId); + + /** + * Gets the current generation of the counter. + * + * @return current generation + */ + int getCurrentGeneration(); + + /** + * Counts the given packet by its packet ID and stores it in history. + * + * @param packetId packet to put + * @return true if the packet was placed, false otherwise + */ + boolean put(int packetId); + + } + + public static class RemoteCounterZero implements RemoteCounter { + + @Override + public int getGeneration(int packetId) { + return 0; + } + + @Override + public int getCurrentGeneration() { + return 0; + } + + @Override + public boolean put(int packetId) { + return true; + } + + } + + public static class RemoteCounterFull implements RemoteCounter { + private final Integer[] buffer; // history buffer + private final int bufferSize; // size of the packet history buffer, used for remembering received packets + private final int generationSize; // size of the physical window, typically 65536 for a 16-bit/ushort window field + + private Pair + bufferStart = new Pair<>(0,0), // position of the start of the buffer in the window + bufferEnd; // position of the end of the buffer in the window + + /** + * Constructs a new full counter + * + * @param windowSize size of the packet history buffer, used for remembering received packets + * @param generationSize length of any given generation, typically 65536 for a 16-bit/ushort window field + */ + public RemoteCounterFull(int generationSize, int windowSize) { // most often will be 65536, 100 + if (windowSize >= generationSize) throw new IllegalArgumentException("windowSize > generationSize"); + + this.buffer = new Integer[windowSize]; + this.bufferSize = windowSize; + this.generationSize = generationSize; + + this.bufferEnd = new Pair<>(0, windowSize - 1); + } + + @Override + public int getGeneration(int packetId) { + packetId %= generationSize; + + // find if right of the start and within the start's bounds + if (packetId >= bufferStart.getValue() + && packetId < bufferStart.getValue() + bufferSize + && packetId < generationSize) { + return bufferStart.getKey(); + } + + // find if left of end and within the end's bounds + if (packetId <= bufferEnd.getValue() + && packetId > 0 + && packetId > bufferEnd.getValue() - bufferSize + && packetId < generationSize) { + return bufferEnd.getKey(); + } + + // find if outside of buffer to the right + if (packetId > bufferEnd.getValue()) + return bufferEnd.getKey(); // ahead in current generation + + // find if outside of buffer to the left + if (packetId < bufferStart.getValue()) + return bufferEnd.getKey() + 1; // modulated wrap, ahead of current generation + + // should never arrive here. + throw new IllegalStateException(); + } + + @Override + public int getCurrentGeneration() { + return bufferEnd.getKey(); + } + + @Override + public boolean put(int packetId) { + // find if right of the start and within the start's bounds + if (packetId >= bufferStart.getValue() + && packetId < bufferStart.getValue() + bufferSize + && packetId < generationSize) { + return putRelative(packetId - bufferStart.getValue(), bufferStart.getKey()); + } + + // find if left of end and within the end's bounds + if (packetId <= bufferEnd.getValue() + && packetId >= 0 + && packetId > bufferEnd.getValue() - bufferSize + && packetId < generationSize) { + return putRelative(bufferSize - (bufferEnd.getValue() - packetId) - 1, bufferEnd.getKey()); + } + + // distance the start position must move right by + int amountMoved = 0; + + // find if outside of buffer to the right + if (packetId > bufferEnd.getValue()) { // slide buffer forward uniformly + amountMoved = packetId - bufferEnd.getValue(); + } + + // find if outside of buffer to the left + if (packetId < bufferStart.getValue()) { // start wrapping buffer or continue to do so + amountMoved = + (generationSize - bufferStart.getValue()) + + packetId + 1; + + amountMoved -= bufferSize; + } + + if (amountMoved > 0) { // should always be true + int toMove = Math.max(0, bufferSize - amountMoved); + Ts3Debugging.debug(Arrays.toString(buffer)); + if (toMove > 0 && toMove < bufferSize) + System.arraycopy(buffer, amountMoved, buffer, 0, toMove); + + int toNullify = Math.max(0, Math.min(bufferSize, amountMoved)); + for (int i = bufferSize - toNullify; i < bufferSize; i ++) + buffer[i] = null; + + Ts3Debugging.debug(Arrays.toString(buffer)); + int bufferStartGeneration = bufferStart.getKey(); + int bufferStartPosition = bufferStart.getValue(); + + bufferStartPosition += amountMoved; + if (bufferStartPosition >= generationSize) { + bufferStartPosition %= generationSize; + bufferStartGeneration ++; + } + + int bufferEndGeneration; + int bufferEndPosition = (bufferStartPosition + bufferSize - 1) % generationSize; + if (bufferEndPosition < bufferStartPosition) + bufferEndGeneration = bufferStartGeneration + 1; + else + bufferEndGeneration = bufferStartGeneration; + + this.bufferStart = new Pair<>(bufferStartGeneration, bufferStartPosition); + this.bufferEnd = new Pair<>(bufferEndGeneration, bufferEndPosition); + } else + throw new IllegalStateException(); + + // if we had to adjust the buffer size, recursively retry put + return put(packetId); + } + + private boolean putRelative(int index, int generation) { + Integer existing = buffer[index]; + Ts3Debugging.debug("putRelative: " + index); + if (existing == null || existing != generation) { + buffer[index] = generation; + return true; + } else { + return false; + } } } - private class PacketCounterZero implements PacketCounter { + + + public static class RemoteCounterFullModulated extends RemoteCounterFull { + private final int modulationSize; + private final int modulationsPerGeneration; + + /** + * Constructs a new full, modulated counter + * This counter is used to sub-modulate a full packet counter, in smaller increments, while still using + * the same code in the backend to modulate the physical window. + * + * @param generationSize length of any given generation, typically 65536 for a 16-bit/ushort window field + * @param windowSize size of the packet history buffer, used for remembering received packets + * @param modulationSize slots within the generation to extrapolated generations by + */ + public RemoteCounterFullModulated(int generationSize, int windowSize, int modulationSize) { + super(generationSize, windowSize); + + if (generationSize % modulationSize != 0) + throw new IllegalArgumentException("modulationSize invalid"); + + this.modulationSize = modulationSize; + this.modulationsPerGeneration = generationSize / modulationSize; + } + + private int calculateSubGeneration(int packetId) { + return packetId == 0 ? 0 : (int) Math.floor(packetId / modulationSize); + } + + @Override + public int getGeneration(int packetId) { + return (super.getGeneration(packetId) * modulationsPerGeneration) + calculateSubGeneration(packetId); + } + + @Override + public int getCurrentGeneration() { + // We can't exactly do this right now. This will require extra work. + throw new UnsupportedOperationException(); + } + } + + public interface LocalCounter { + Pair next(); + int getPacketId(); + boolean setPacketId(int packetId); + int getGeneration(); + void setGeneration(int i); + + default Pair current() { + return new Pair<>(getPacketId(), getGeneration()); + } + } + + public static class LocalCounterZero implements LocalCounter { @Override public Pair next() { return new Pair<>(0,0); @@ -838,27 +1068,31 @@ public abstract class AbstractTeamspeakClientSocket } @Override - public int getGenerationId() { + public int getGeneration() { return 0; } @Override - public void setGenerationId(int i) { + public void setGeneration(int i) { throw new UnsupportedOperationException(); } } - private class PacketCounterFull implements PacketCounter { + public static class LocalCounterFull implements LocalCounter { private final Object sendLock = new Object(); private final boolean counting; + private final int generationSize; + private int packetId = 0; private int generationId = 0; - public PacketCounterFull(boolean counting) { + public LocalCounterFull(int generationSize, boolean counting) { + this.generationSize = generationSize; this.counting = counting; } - public PacketCounterFull(int start, boolean counting) { + public LocalCounterFull(int generationSize, int start, boolean counting) { + this.generationSize = generationSize; this.counting = counting; setPacketId(start); @@ -873,9 +1107,9 @@ public abstract class AbstractTeamspeakClientSocket synchronized (sendLock) { if (this.packetId == packetId) return false; - if (packetId >= 65536) { + if (packetId >= generationSize) { this.packetId = 0; // wrap around - if (isCounting()) setGenerationId(getGenerationId() + 1); + if (isCounting()) setGeneration(getGeneration() + 1); } else { this.packetId = packetId; } @@ -884,14 +1118,14 @@ public abstract class AbstractTeamspeakClientSocket } } - public int getGenerationId() { + public int getGeneration() { return generationId; } @Override - public void setGenerationId(int i) { + public void setGeneration(int i) { synchronized (sendLock) { - Ts3Debugging.debug("setGenerationId: " + i); + Ts3Debugging.debug("setGeneration: " + i); this.generationId = i; } } diff --git a/src/test/java/com/github/manevolent/ts3j/PacketCounterTest.java b/src/test/java/com/github/manevolent/ts3j/PacketCounterTest.java new file mode 100644 index 0000000..919e07e --- /dev/null +++ b/src/test/java/com/github/manevolent/ts3j/PacketCounterTest.java @@ -0,0 +1,32 @@ +package com.github.manevolent.ts3j; + +import com.github.manevolent.ts3j.protocol.socket.client.AbstractTeamspeakClientSocket; +import com.github.manevolent.ts3j.util.Ts3Debugging; +import javafx.util.Pair; +import junit.framework.TestCase; + +public class PacketCounterTest extends TestCase { + public static void main(String[] args) throws Exception { + new PacketCounterTest().testParser(); + } + + public void testParser() throws Exception { + Ts3Debugging.setEnabled(true); + + AbstractTeamspeakClientSocket.LocalCounter localCounter = + new AbstractTeamspeakClientSocket.LocalCounterFull(65536, 0, true); + + AbstractTeamspeakClientSocket.RemoteCounter remoteCounter = + new AbstractTeamspeakClientSocket.RemoteCounterFull(65536, 100); + + for (int i = 0; i < 65580 / 5; i ++) { + Pair packet = null; + for (int n = 0; n < 5; n ++) + packet = localCounter.next(); + + assertEquals(true, remoteCounter.put(packet.getKey())); + assertEquals(packet.getValue().intValue(), remoteCounter.getCurrentGeneration()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java index b9d584b..ee02934 100644 --- a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java @@ -41,23 +41,6 @@ public class ServerConnectionTest { 10000L ); - client.setMicrophone(new Microphone() { - @Override - public boolean isReady() { - return true; - } - - @Override - public CodecType getCodec() { - return CodecType.OPUS_MUSIC; - } - - @Override - public byte[] provide() { - return new byte[20]; - } - }); - assertEquals(client.getState(), ClientConnectionState.CONNECTED); while (true) {