Improved pending data read logic.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package org.l2jmobius.commons.network;
|
package org.l2jmobius.commons.network;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
@@ -17,6 +18,8 @@ public class NetClient
|
|||||||
private SocketChannel _channel;
|
private SocketChannel _channel;
|
||||||
private NetConfig _netConfig;
|
private NetConfig _netConfig;
|
||||||
private Queue<byte[]> _pendingPacketData;
|
private Queue<byte[]> _pendingPacketData;
|
||||||
|
private ByteBuffer _pendingByteBuffer;
|
||||||
|
private int _pendingPacketSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the client.
|
* Initialize the client.
|
||||||
@@ -77,6 +80,11 @@ public class NetClient
|
|||||||
{
|
{
|
||||||
_pendingPacketData.clear();
|
_pendingPacketData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +132,40 @@ public class NetClient
|
|||||||
return _pendingPacketData;
|
return _pendingPacketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public ByteBuffer getPendingByteBuffer()
|
||||||
|
{
|
||||||
|
return _pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pending read ByteBuffer.
|
||||||
|
* @param pendingByteBuffer the pending read ByteBuffer.
|
||||||
|
*/
|
||||||
|
public void setPendingByteBuffer(ByteBuffer pendingByteBuffer)
|
||||||
|
{
|
||||||
|
_pendingByteBuffer = pendingByteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the expected pending packet size.
|
||||||
|
*/
|
||||||
|
public int getPendingPacketSize()
|
||||||
|
{
|
||||||
|
return _pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected pending packet size.
|
||||||
|
* @param pendingPacketSize the expected packet size.
|
||||||
|
*/
|
||||||
|
public void setPendingPacketSize(int pendingPacketSize)
|
||||||
|
{
|
||||||
|
_pendingPacketSize = pendingPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Encryption of this client.
|
* @return the Encryption of this client.
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
public class ReadThread<E extends NetClient> implements Runnable
|
public class ReadThread<E extends NetClient> implements Runnable
|
||||||
{
|
{
|
||||||
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
private final ByteBuffer _sizeBuffer = ByteBuffer.allocate(2); // Reusable size buffer.
|
||||||
|
private final ByteBuffer _pendingSizeBuffer = ByteBuffer.allocate(1); // Reusable pending size buffer.
|
||||||
private final Set<E> _pool;
|
private final Set<E> _pool;
|
||||||
|
|
||||||
public ReadThread(Set<E> pool)
|
public ReadThread(Set<E> pool)
|
||||||
@@ -45,6 +46,45 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue read if there is a pending ByteBuffer.
|
||||||
|
final ByteBuffer pendingByteBuffer = client.getPendingByteBuffer();
|
||||||
|
if (pendingByteBuffer != null)
|
||||||
|
{
|
||||||
|
// Allocate an additional ByteBuffer based on pending packet size.
|
||||||
|
final int pendingPacketSize = client.getPendingPacketSize();
|
||||||
|
final ByteBuffer additionalData = ByteBuffer.allocate(pendingPacketSize - pendingByteBuffer.position());
|
||||||
|
switch (channel.read(additionalData))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Data was read.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Merge additional read data.
|
||||||
|
pendingByteBuffer.put(pendingByteBuffer.position(), additionalData, 0, additionalData.position());
|
||||||
|
pendingByteBuffer.position(pendingByteBuffer.position() + additionalData.position());
|
||||||
|
|
||||||
|
// Read was complete.
|
||||||
|
if (pendingByteBuffer.position() >= pendingPacketSize)
|
||||||
|
{
|
||||||
|
// Add packet data to client.
|
||||||
|
client.addPacketData(pendingByteBuffer.array());
|
||||||
|
client.setPendingByteBuffer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
// Read incoming packet size (short).
|
// Read incoming packet size (short).
|
||||||
_sizeBuffer.clear();
|
_sizeBuffer.clear();
|
||||||
switch (channel.read(_sizeBuffer))
|
switch (channel.read(_sizeBuffer))
|
||||||
@@ -60,6 +100,54 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
{
|
{
|
||||||
continue ITERATE;
|
continue ITERATE;
|
||||||
}
|
}
|
||||||
|
// Need to read two bytes to calculate size.
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int attempt = 0; // Keep it under 10 attempts (100ms).
|
||||||
|
COMPLETE_SIZE_READ: while ((attempt++ < 10) && (_sizeBuffer.position() < 2))
|
||||||
|
{
|
||||||
|
// Wait for pending data.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read the missing extra byte.
|
||||||
|
_pendingSizeBuffer.clear();
|
||||||
|
switch (channel.read(_pendingSizeBuffer))
|
||||||
|
{
|
||||||
|
// Disconnected.
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
// Nothing read.
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
continue COMPLETE_SIZE_READ;
|
||||||
|
}
|
||||||
|
// Merge additional read byte.
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
_sizeBuffer.put(1, _pendingSizeBuffer, 0, 1);
|
||||||
|
_sizeBuffer.position(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read failed.
|
||||||
|
if (_sizeBuffer.position() < 2)
|
||||||
|
{
|
||||||
|
onDisconnection(client);
|
||||||
|
continue ITERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough.
|
||||||
|
}
|
||||||
// Read actual packet bytes.
|
// Read actual packet bytes.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -82,26 +170,21 @@ public class ReadThread<E extends NetClient> implements Runnable
|
|||||||
// Send data read to the client packet queue.
|
// Send data read to the client packet queue.
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Continue read if data length is less than expected.
|
// Read was not complete.
|
||||||
if (packetByteBuffer.position() < packetSize)
|
if (packetByteBuffer.position() < packetSize)
|
||||||
{
|
{
|
||||||
int attempt = 0; // Keep it under 10 attempts.
|
client.setPendingByteBuffer(packetByteBuffer);
|
||||||
while ((attempt++ < 10) && (packetByteBuffer.position() < packetSize))
|
client.setPendingPacketSize(packetSize);
|
||||||
|
}
|
||||||
|
else // Add packet data to client.
|
||||||
{
|
{
|
||||||
final ByteBuffer additionalData = ByteBuffer.allocate(packetSize - packetByteBuffer.position());
|
|
||||||
channel.read(additionalData);
|
|
||||||
packetByteBuffer.put(packetByteBuffer.position(), additionalData, 0, additionalData.position());
|
|
||||||
packetByteBuffer.position(packetByteBuffer.position() + additionalData.position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add packet data to client.
|
|
||||||
client.addPacketData(packetByteBuffer.array());
|
client.addPacketData(packetByteBuffer.array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
onDisconnection(client);
|
onDisconnection(client);
|
||||||
|
Reference in New Issue
Block a user