use of cn.nukkit.raknet.protocol.DataPacket in project Nukkit by Nukkit.
the class Session method addToQueue.
private void addToQueue(EncapsulatedPacket pk, int flags) throws Exception {
int priority = flags & 0b0000111;
if (pk.needACK && pk.messageIndex != null) {
if (!this.needACK.containsKey(pk.identifierACK)) {
this.needACK.put(pk.identifierACK, new HashMap<>());
}
this.needACK.get(pk.identifierACK).put(pk.messageIndex, pk.messageIndex);
}
if (priority == RakNet.PRIORITY_IMMEDIATE) {
// Skip queues
DataPacket packet = new DATA_PACKET_0();
packet.seqNumber = this.sendSeqNumber++;
if (pk.needACK) {
packet.packets.add(pk.clone());
pk.needACK = false;
} else {
packet.packets.add(pk.toBinary());
}
this.sendPacket(packet);
packet.sendTime = System.currentTimeMillis();
this.recoveryQueue.put(packet.seqNumber, packet);
return;
}
int length = this.sendQueue.length();
if (length + pk.getTotalLength() > this.mtuSize) {
this.sendQueue();
}
if (pk.needACK) {
this.sendQueue.packets.add(pk.clone());
pk.needACK = false;
} else {
this.sendQueue.packets.add(pk.toBinary());
}
}
use of cn.nukkit.raknet.protocol.DataPacket in project Nukkit by Nukkit.
the class Session method handlePacket.
public void handlePacket(Packet packet) throws Exception {
this.isActive = true;
this.lastUpdate = System.currentTimeMillis();
if (this.state == STATE_CONNECTED || this.state == STATE_CONNECTING_2) {
if (((packet.buffer[0] & 0xff) >= 0x80 || (packet.buffer[0] & 0xff) <= 0x8f) && packet instanceof DataPacket) {
DataPacket dp = (DataPacket) packet;
dp.decode();
if (dp.seqNumber < this.windowStart || dp.seqNumber > this.windowEnd || this.receivedWindow.containsKey(dp.seqNumber)) {
return;
}
int diff = dp.seqNumber - this.lastSeqNumber;
this.NACKQueue.remove(dp.seqNumber);
this.ACKQueue.put(dp.seqNumber, dp.seqNumber);
this.receivedWindow.put(dp.seqNumber, dp.seqNumber);
if (diff != 1) {
for (int i = this.lastSeqNumber + 1; i < dp.seqNumber; i++) {
if (!this.receivedWindow.containsKey(i)) {
this.NACKQueue.put(i, i);
}
}
}
if (diff >= 1) {
this.lastSeqNumber = dp.seqNumber;
this.windowStart += diff;
this.windowEnd += diff;
}
for (Object pk : dp.packets) {
if (pk instanceof EncapsulatedPacket) {
this.handleEncapsulatedPacket((EncapsulatedPacket) pk);
}
}
} else {
if (packet instanceof ACK) {
packet.decode();
for (int seq : new ArrayList<>(((ACK) packet).packets.values())) {
if (this.recoveryQueue.containsKey(seq)) {
for (Object pk : this.recoveryQueue.get(seq).packets) {
if (pk instanceof EncapsulatedPacket && ((EncapsulatedPacket) pk).needACK && ((EncapsulatedPacket) pk).messageIndex != null) {
if (this.needACK.containsKey(((EncapsulatedPacket) pk).identifierACK)) {
this.needACK.get(((EncapsulatedPacket) pk).identifierACK).remove(((EncapsulatedPacket) pk).messageIndex);
}
}
}
this.recoveryQueue.remove(seq);
}
}
} else if (packet instanceof NACK) {
packet.decode();
for (int seq : new ArrayList<>(((NACK) packet).packets.values())) {
if (this.recoveryQueue.containsKey(seq)) {
DataPacket pk = this.recoveryQueue.get(seq);
pk.seqNumber = this.sendSeqNumber++;
this.packetToSend.add(pk);
this.recoveryQueue.remove(seq);
}
}
}
}
} else if ((packet.buffer[0] & 0xff) > 0x00 || (packet.buffer[0] & 0xff) < 0x80) {
// Not Data packet :)
packet.decode();
if (packet instanceof OPEN_CONNECTION_REQUEST_1) {
// TODO: check protocol number and refuse connections
OPEN_CONNECTION_REPLY_1 pk = new OPEN_CONNECTION_REPLY_1();
pk.mtuSize = ((OPEN_CONNECTION_REQUEST_1) packet).mtuSize;
pk.serverID = sessionManager.getID();
this.sendPacket(pk);
this.state = STATE_CONNECTING_1;
} else if (this.state == STATE_CONNECTING_1 && packet instanceof OPEN_CONNECTION_REQUEST_2) {
this.id = ((OPEN_CONNECTION_REQUEST_2) packet).clientID;
if (((OPEN_CONNECTION_REQUEST_2) packet).serverPort == this.sessionManager.getPort() || !this.sessionManager.portChecking) {
// Max size, do not allow creating large buffers to fill server memory
this.mtuSize = Math.min(Math.abs(((OPEN_CONNECTION_REQUEST_2) packet).mtuSize), 1464);
OPEN_CONNECTION_REPLY_2 pk = new OPEN_CONNECTION_REPLY_2();
pk.mtuSize = (short) this.mtuSize;
pk.serverID = this.sessionManager.getID();
pk.clientAddress = this.address;
pk.clientPort = this.port;
this.sendPacket(pk);
this.state = STATE_CONNECTING_2;
}
}
}
}
use of cn.nukkit.raknet.protocol.DataPacket in project Nukkit by Nukkit.
the class Session method update.
public void update(long time) throws Exception {
if (!this.isActive && (this.lastUpdate + 10000) < time) {
// 10 second timeout
this.disconnect("timeout");
return;
}
this.isActive = false;
if (!this.ACKQueue.isEmpty()) {
ACK pk = new ACK();
pk.packets = new TreeMap<>(this.ACKQueue);
this.sendPacket(pk);
this.ACKQueue = new HashMap<>();
}
if (!this.NACKQueue.isEmpty()) {
NACK pk = new NACK();
pk.packets = new TreeMap<>(this.NACKQueue);
this.sendPacket(pk);
this.NACKQueue = new HashMap<>();
}
if (!this.packetToSend.isEmpty()) {
int limit = 16;
for (int i = 0; i < this.packetToSend.size(); i++) {
DataPacket pk = this.packetToSend.get(i);
pk.sendTime = time;
pk.encode();
this.recoveryQueue.put(pk.seqNumber, pk);
this.packetToSend.remove(pk);
this.sendPacket(pk);
if (limit-- <= 0) {
break;
}
}
}
if (this.packetToSend.size() > WINDOW_SIZE) {
this.packetToSend.clear();
}
if (!this.needACK.isEmpty()) {
for (int identifierACK : new ArrayList<>(this.needACK.keySet())) {
Map<Integer, Integer> indexes = this.needACK.get(identifierACK);
if (indexes.isEmpty()) {
this.needACK.remove(identifierACK);
this.sessionManager.notifyACK(this, identifierACK);
}
}
}
for (int seq : new ArrayList<>(this.recoveryQueue.keySet())) {
DataPacket pk = this.recoveryQueue.get(seq);
if (pk.sendTime < System.currentTimeMillis() - 8000) {
this.packetToSend.add(pk);
this.recoveryQueue.remove(seq);
} else {
break;
}
}
for (int seq : new ArrayList<>(this.receivedWindow.keySet())) {
if (seq < this.windowStart) {
this.receivedWindow.remove(seq);
} else {
break;
}
}
this.sendQueue();
}
Aggregations