Fragments which wrap around 65536 and cause the packet ID to ascend more than once will crash the code
This commit is contained in:
+26
-18
@@ -2,6 +2,8 @@ package com.github.manevolent.ts3j.protocol.packet.fragment;
|
||||
|
||||
import com.github.manevolent.ts3j.protocol.Packet;
|
||||
import com.github.manevolent.ts3j.protocol.header.HeaderFlag;
|
||||
import com.github.manevolent.ts3j.protocol.socket.client.AbstractTeamspeakClientSocket;
|
||||
import com.github.manevolent.ts3j.util.Pair;
|
||||
import com.github.manevolent.ts3j.util.QuickLZ;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -10,20 +12,18 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PacketReassembly {
|
||||
private final AbstractTeamspeakClientSocket.LocalCounter counter =
|
||||
new AbstractTeamspeakClientSocket.LocalCounterFull(65536, true);
|
||||
|
||||
private final Map<Integer, Packet> queue = new LinkedHashMap<>();
|
||||
private int currentPacketId = 0;
|
||||
|
||||
public void setPacketId(int currentPacketId) {
|
||||
this.currentPacketId = currentPacketId;
|
||||
}
|
||||
|
||||
public boolean put(Packet packet) throws IOException {
|
||||
public void put(Packet packet) throws IOException {
|
||||
queue.put(packet.getHeader().getPacketId(), packet);
|
||||
|
||||
return currentPacketId == packet.getHeader().getPacketId();
|
||||
}
|
||||
|
||||
public Packet next() throws IOException {
|
||||
if (queue.size() <= 0) return null;
|
||||
|
||||
List<Packet> reassemblyList = new ArrayList<>();
|
||||
|
||||
try {
|
||||
@@ -32,33 +32,38 @@ public class PacketReassembly {
|
||||
|
||||
boolean state = false;
|
||||
|
||||
for (int packetId = currentPacketId; ; packetId++) {
|
||||
if (packetId >= 65536) packetId = 0;
|
||||
AbstractTeamspeakClientSocket.LocalCounter temporaryCounter =
|
||||
new AbstractTeamspeakClientSocket.LocalCounterFull(65536, true);
|
||||
|
||||
Packet packet = queue.get(packetId);
|
||||
Pair<Integer, Integer> currentPacketId = counter.current();
|
||||
|
||||
temporaryCounter.setPacketId(currentPacketId.getKey());
|
||||
temporaryCounter.setGeneration(currentPacketId.getValue());
|
||||
|
||||
while (true) {
|
||||
Pair<Integer, Integer> thisPacketId = temporaryCounter.current();
|
||||
Packet packet = queue.get(thisPacketId.getKey());
|
||||
|
||||
if (packet == null)
|
||||
break; // Chain breaks here
|
||||
else {
|
||||
packetIds.add(packetId);
|
||||
packetIds.add(thisPacketId.getKey());
|
||||
reassemblyList.add(packet);
|
||||
|
||||
if (packet.getHeader().getPacketFlag(HeaderFlag.FRAGMENTED)) {
|
||||
state = !state;
|
||||
|
||||
if (!state) {
|
||||
currentPacketId += packetIds.size();
|
||||
break; // fragmentation stopped, we found the last packet
|
||||
} else
|
||||
continue; // keep collecting fragments
|
||||
}
|
||||
} else if (!state) {
|
||||
currentPacketId ++;
|
||||
break; // don't reassemble this packet, it's not a fragment
|
||||
} else if (state) {
|
||||
// keep collecting fragments
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
temporaryCounter.next();
|
||||
}
|
||||
|
||||
if (state) return null; // cannot reassemble yet because we don't have all fragments
|
||||
@@ -94,6 +99,9 @@ public class PacketReassembly {
|
||||
// Remove read packets
|
||||
packetIds.forEach(queue::remove);
|
||||
|
||||
// Count
|
||||
counter.next(packetIds.size());
|
||||
|
||||
return reassembledPacket;
|
||||
} catch (Exception ex) {
|
||||
throw new IOException("Problem reassembling " + reassemblyList.size() + " packet(s): [" +
|
||||
@@ -106,7 +114,7 @@ public class PacketReassembly {
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentPacketId = 0;
|
||||
counter.reset();
|
||||
queue.clear();
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -68,9 +68,7 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
|
||||
private CommandProcessor commandProcessor;
|
||||
|
||||
private Consumer<Throwable> exceptionHandler = throwable -> {
|
||||
throwable.printStackTrace();
|
||||
};
|
||||
private Consumer<Throwable> exceptionHandler = Throwable::printStackTrace;
|
||||
|
||||
private Identity identity = null;
|
||||
private ClientConnectionState connectionState = null;
|
||||
@@ -929,7 +927,9 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
private int tries = 1, maxTries;
|
||||
private boolean willResend;
|
||||
|
||||
public PacketResponse(NetworkPacket sentPacket, Map<Integer, PacketResponse> responsibleQueue, int maxTries) {
|
||||
public PacketResponse(NetworkPacket sentPacket,
|
||||
Map<Integer, PacketResponse> responsibleQueue,
|
||||
int maxTries) {
|
||||
this.sentPacket = sentPacket;
|
||||
this.responsibleQueue = responsibleQueue;
|
||||
this.maxTries = maxTries;
|
||||
@@ -1248,6 +1248,12 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
public interface LocalCounter {
|
||||
Pair<Integer, Integer> next();
|
||||
|
||||
default Pair<Integer, Integer> next(int n) {
|
||||
Pair<Integer, Integer> last = current();
|
||||
for (int i = 0; i < n; i ++) last = next();
|
||||
return last;
|
||||
}
|
||||
|
||||
int getPacketId();
|
||||
boolean setPacketId(int packetId);
|
||||
|
||||
@@ -1340,7 +1346,6 @@ public abstract class AbstractTeamspeakClientSocket
|
||||
@Override
|
||||
public void setGeneration(int i) {
|
||||
synchronized (sendLock) {
|
||||
Ts3Debugging.debug("setGeneration: " + i);
|
||||
this.generationId = i;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -60,7 +60,6 @@ public class LocalTeamspeakClientSocket
|
||||
private List<TS3Listener> listeners = new LinkedList<>();
|
||||
|
||||
private int acceptingReturnCode = Integer.MAX_VALUE;
|
||||
private int lastReturnCode = 0;
|
||||
|
||||
private Integer serverId = null;
|
||||
|
||||
@@ -251,7 +250,7 @@ public class LocalTeamspeakClientSocket
|
||||
|
||||
serverId = null;
|
||||
awaitingCommands.clear();
|
||||
acceptingReturnCode = lastReturnCode = 0;
|
||||
acceptingReturnCode = 0;
|
||||
|
||||
setOption("client.hostname", remote.getHostString());
|
||||
|
||||
@@ -341,10 +340,10 @@ public class LocalTeamspeakClientSocket
|
||||
if (getState() != ClientConnectionState.CONNECTED)
|
||||
throw new IOException("not connected");
|
||||
|
||||
int returnCode;
|
||||
|
||||
// sync may not be necessary here
|
||||
returnCode = lastReturnCode++;
|
||||
int maxReturnCode = calculateAcceptingReturnCode();
|
||||
if (maxReturnCode == Integer.MAX_VALUE) maxReturnCode = 0;
|
||||
else maxReturnCode = maxReturnCode + 1;
|
||||
int returnCode = maxReturnCode;
|
||||
|
||||
command.add(new CommandSingleParameter("return_code", Integer.toString(returnCode)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user