mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-20 21:40:27 -07:00
351 lines
No EOL
6.6 KiB
Java
351 lines
No EOL
6.6 KiB
Java
package ms.net;
|
|
|
|
import java.io.IOException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.SelectionKey;
|
|
import java.nio.channels.SocketChannel;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.locks.Lock;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
import ms.ServerConstants;
|
|
import ms.net.producer.HSEventProducer;
|
|
import ms.world.GameServer;
|
|
|
|
/**
|
|
* Represents a connected I/O session.
|
|
* @author Emperor
|
|
*
|
|
*/
|
|
public class IoSession {
|
|
|
|
/**
|
|
* The handshake event producer.
|
|
*/
|
|
private static final EventProducer HANDSHAKE_PRODUCER = new HSEventProducer();
|
|
|
|
/**
|
|
* The selection key.
|
|
*/
|
|
private final SelectionKey key;
|
|
|
|
/**
|
|
* The executor service.
|
|
*/
|
|
private final ExecutorService service;
|
|
|
|
/**
|
|
* The event producer.
|
|
*/
|
|
private EventProducer producer = HANDSHAKE_PRODUCER;
|
|
|
|
/**
|
|
* The currently queued writing data.
|
|
*/
|
|
private List<ByteBuffer> writingQueue = new ArrayList<>(20);
|
|
|
|
/**
|
|
* The currently queued reading data.
|
|
*/
|
|
private ByteBuffer readingQueue;
|
|
|
|
/**
|
|
* The writing lock.
|
|
*/
|
|
private final Lock writingLock = new ReentrantLock();
|
|
|
|
/**
|
|
* The name hash.
|
|
*/
|
|
private int nameHash;
|
|
|
|
/**
|
|
* The server key.
|
|
*/
|
|
private long serverKey;
|
|
|
|
/**
|
|
* The JS-5 encryption value.
|
|
*/
|
|
private int js5Encryption;
|
|
|
|
/**
|
|
* If the session is active.
|
|
*/
|
|
private boolean active = true;
|
|
|
|
/**
|
|
* The last ping time stamp.
|
|
*/
|
|
private long lastPing;
|
|
|
|
/**
|
|
* The address.
|
|
*/
|
|
private final String address;
|
|
|
|
/**
|
|
* The game server object for this session.
|
|
*/
|
|
private GameServer gameServer;
|
|
|
|
/**
|
|
* Constructs a new {@code IoSession}.
|
|
* @param key The selection key.
|
|
* @param service The executor service.
|
|
*/
|
|
public IoSession(SelectionKey key, ExecutorService service) {
|
|
this.key = key;
|
|
this.service = service;
|
|
String address = getRemoteAddress().replaceAll("/", "").split(":")[0];
|
|
if (address.equals("127.0.0.1")) {
|
|
address = ServerConstants.HOST_ADDRESS;
|
|
}
|
|
this.address = address;
|
|
}
|
|
|
|
/**
|
|
* Fires a write event created using the current event producer.
|
|
* @param context The event context.
|
|
*/
|
|
public void write(Object context) {
|
|
write(context, false);
|
|
}
|
|
|
|
/**
|
|
* Fires a write event created using the current event producer.
|
|
* @param context The event context.
|
|
* @param instant If the event should be instantly executed on this thread.
|
|
*/
|
|
public void write(Object context, boolean instant) {
|
|
if (context == null) {
|
|
throw new IllegalStateException("Invalid writing context!");
|
|
}
|
|
if (instant) {
|
|
producer.produceWriter(this, context).run();
|
|
return;
|
|
}
|
|
service.execute(producer.produceWriter(this, context));
|
|
}
|
|
|
|
/**
|
|
* Sends the packet data (without write event encoding).
|
|
* @param buffer The buffer.
|
|
*/
|
|
public void queue(ByteBuffer buffer) {
|
|
try {
|
|
writingLock.tryLock(1000L, TimeUnit.MILLISECONDS);
|
|
} catch (Exception e){
|
|
e.printStackTrace();
|
|
writingLock.unlock();
|
|
return;
|
|
}
|
|
writingQueue.add(buffer);
|
|
writingLock.unlock();
|
|
write();
|
|
}
|
|
|
|
/**
|
|
* Handles the writing of all buffers in the queue.
|
|
*/
|
|
public void write() {
|
|
if (!key.isValid()) {
|
|
disconnect();
|
|
return;
|
|
}
|
|
writingLock.lock();
|
|
SocketChannel channel = (SocketChannel) key.channel();
|
|
try {
|
|
while (!writingQueue.isEmpty()) {
|
|
ByteBuffer buffer = writingQueue.get(0);
|
|
channel.write(buffer);
|
|
if (buffer.hasRemaining()) {
|
|
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
|
|
break;
|
|
}
|
|
writingQueue.remove(0);
|
|
}
|
|
} catch (IOException e) {
|
|
disconnect();
|
|
}
|
|
writingLock.unlock();
|
|
}
|
|
|
|
/**
|
|
* Disconnects the session.
|
|
*/
|
|
public void disconnect() {
|
|
try {
|
|
if (!active) {
|
|
return;
|
|
}
|
|
active = false;
|
|
key.cancel();
|
|
SocketChannel channel = (SocketChannel) key.channel();
|
|
channel.socket().close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the IP-address (without the port).
|
|
* @return The address.
|
|
*/
|
|
public String getAddress() {
|
|
return address;
|
|
}
|
|
|
|
/**
|
|
* Gets the remote address of this session.
|
|
* @return The remote address, as a String.
|
|
*/
|
|
public String getRemoteAddress() {
|
|
try {
|
|
return ((SocketChannel) key.channel()).getRemoteAddress().toString();
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the current event producer.
|
|
* @return The producer.
|
|
*/
|
|
public EventProducer getProducer() {
|
|
return producer;
|
|
}
|
|
|
|
/**
|
|
* Sets the event producer.
|
|
* @param producer The producer to set.
|
|
*/
|
|
public void setProducer(EventProducer producer) {
|
|
this.producer = producer;
|
|
}
|
|
|
|
/**
|
|
* Gets the queued reading data.
|
|
* @return The readingQueue.
|
|
*/
|
|
public ByteBuffer getReadingQueue() {
|
|
synchronized (this) {
|
|
return readingQueue;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Queues reading data.
|
|
* @param readingQueue The readingQueue to set.
|
|
*/
|
|
public void setReadingQueue(ByteBuffer readingQueue) {
|
|
synchronized (this) {
|
|
this.readingQueue = readingQueue;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the writing lock.
|
|
* @return The writing lock.
|
|
*/
|
|
public Lock getWritingLock() {
|
|
return writingLock;
|
|
}
|
|
|
|
/**
|
|
* Gets the selection key.
|
|
* @return The selection key.
|
|
*/
|
|
public SelectionKey getKey() {
|
|
return key;
|
|
}
|
|
|
|
/**
|
|
* @return The active.
|
|
*/
|
|
public boolean isActive() {
|
|
return active;
|
|
}
|
|
|
|
/**
|
|
* @return The js5Encryption.
|
|
*/
|
|
public int getJs5Encryption() {
|
|
return js5Encryption;
|
|
}
|
|
|
|
/**
|
|
* @param js5Encryption The js5Encryption to set.
|
|
*/
|
|
public void setJs5Encryption(int js5Encryption) {
|
|
this.js5Encryption = js5Encryption;
|
|
}
|
|
|
|
/**
|
|
* Gets the lastPing.
|
|
* @return The lastPing.
|
|
*/
|
|
public long getLastPing() {
|
|
return lastPing;
|
|
}
|
|
|
|
/**
|
|
* Sets the lastPing.
|
|
* @param lastPing The lastPing to set.
|
|
*/
|
|
public void setLastPing(long lastPing) {
|
|
this.lastPing = lastPing;
|
|
}
|
|
|
|
/**
|
|
* Gets the nameHash.
|
|
* @return The nameHash.
|
|
*/
|
|
public int getNameHash() {
|
|
return nameHash;
|
|
}
|
|
|
|
/**
|
|
* Sets the nameHash.
|
|
* @param nameHash The nameHash to set.
|
|
*/
|
|
public void setNameHash(int nameHash) {
|
|
this.nameHash = nameHash;
|
|
}
|
|
|
|
/**
|
|
* Gets the serverKey.
|
|
* @return The serverKey.
|
|
*/
|
|
public long getServerKey() {
|
|
return serverKey;
|
|
}
|
|
|
|
/**
|
|
* Sets the serverKey.
|
|
* @param serverKey The serverKey to set.
|
|
*/
|
|
public void setServerKey(long serverKey) {
|
|
this.serverKey = serverKey;
|
|
}
|
|
|
|
/**
|
|
* Gets the gameServer value.
|
|
* @return The gameServer.
|
|
*/
|
|
public GameServer getGameServer() {
|
|
return gameServer;
|
|
}
|
|
|
|
/**
|
|
* Sets the gameServer value.
|
|
* @param gameServer The gameServer to set.
|
|
*/
|
|
public void setGameServer(GameServer gameServer) {
|
|
this.gameServer = gameServer;
|
|
}
|
|
|
|
} |