package l2p.loginserver.gameservercon;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import javolution.util.FastList;
import l2p.Config;
import l2p.Server;
import l2p.loginserver.gameservercon.lspackets.ServerBasePacket;
import l2p.util.Util;
/**
* @Author: Death
* @Date: 12/11/2007
* @Time: 17:08:29
*/
public class GSConnection extends Thread
{
// Включение дебага: java -DenableDebugLsGs
public static final boolean DEBUG_LS_GS = System.getProperty("enableDebugLsGs") != null;
private static final Logger log = Logger.getLogger(GSConnection.class.getName());
private static final GSConnection instance = new GSConnection();
private static final FastList<AttGS> gameservers = FastList.newInstance();
private Selector selector;
private boolean shutdown;
public static GSConnection getInstance()
{
return instance;
}
private GSConnection()
{
try
{
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
int port = Config.GAME_SERVER_LOGIN_PORT;
String host = Config.GAME_SERVER_LOGIN_HOST;
server.socket().bind(host.equals("*") ? new InetSocketAddress(port) : new InetSocketAddress(InetAddress.getByName(host), port));
server.register(selector, SelectionKey.OP_ACCEPT);
}
catch(IOException e)
{
e.printStackTrace();
System.out.println("LoginServer: Can't init GameServer Listener.");
Server.exit(0, "LoginServer: Can't init GameServer Listener.");
}
if(DEBUG_LS_GS)
{
log.info("LS Debug: Listening for gameservers.");
}
}
@Override
public void run()
{
log.info("LoginServer: GS listener started.");
Set<SelectionKey> keys;
Iterator<SelectionKey> keys_iterator;
SelectionKey key;
int keyNum, opts;
while(!isShutdown())
{
try
{
keyNum = selector.selectNow();
if(keyNum > 0)
{
keys = selector.selectedKeys();
keys_iterator = keys.iterator();
while(keys_iterator.hasNext())
{
key = keys_iterator.next();
keys_iterator.remove();
if(!key.isValid())
{
close(key);
continue;
}
opts = key.readyOps();
if(DEBUG_LS_GS)
{
log.info("LS Debug: Seletor: key selected, readyOpts: " + opts);
}
switch(opts)
{
case SelectionKey.OP_CONNECT:
close(key);
break;
case SelectionKey.OP_ACCEPT:
accept(key);
break;
case SelectionKey.OP_WRITE:
write(key);
break;
case SelectionKey.OP_READ:
read(key);
break;
case SelectionKey.OP_READ | SelectionKey.OP_WRITE:
write(key);
read(key);
break;
default:
log.severe("GSConnection: Unknow readyOpts: " + opts);
}
}
keys.clear();
}
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
System.out.println("LoginServer: GameServer Listener - NIO Down... Restarting...");
Server.exit(2, "LoginServer: GameServer Listener - NIO Down... Restarting...");
}
}
}
public void accept(SelectionKey key)
{
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc;
try
{
sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
catch(IOException e)
{
close(key);
return;
}
SelectionKey gsKey = sc.keyFor(selector);
gsKey.attach(new AttGS(gsKey));
if(DEBUG_LS_GS)
{
log.info("LS Debug: key accepted.");
}
}
public void read(SelectionKey key)
{
SocketChannel channel = (SocketChannel) key.channel();
AttGS att = (AttGS) key.attachment();
ByteBuffer readBuffer = att.getReadBuffer();
int numRead;
try
{
numRead = channel.read(readBuffer);
}
catch(IOException e)
{
close(key);
return;
}
if(numRead == -1)
{
close(key);
}
if(numRead == 0)
{
return;
}
att.processData();
if(DEBUG_LS_GS)
{
log.info("LS Debug: Data readed.");
}
}
public void write(SelectionKey key)
{
AttGS att = (AttGS) key.attachment();
SocketChannel channel = (SocketChannel) key.channel();
ArrayDeque<ServerBasePacket> sendQueue = att.getSendQueue();
synchronized(sendQueue)
{
ServerBasePacket packet;
while((packet = sendQueue.poll()) != null)
{
try
{
byte[] data = att.encrypt(packet.getBytes());
data = Util.writeLenght(data);
channel.write(ByteBuffer.wrap(data));
if(DEBUG_LS_GS)
{
log.info("LoginServer -> GameServer [" + att.getServerId() + "]: Sending packet: " + packet.getClass().getSimpleName());
}
}
catch(IOException e)
{
e.printStackTrace();
close(key);
return;
}
}
}
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
if(DEBUG_LS_GS)
{
log.info("LS Debug: Data sended.");
}
}
public void close(SelectionKey key)
{
try
{
AttGS att = (AttGS) key.attachment();
if(att != null)
{
att.onClose();
}
key.cancel();
key.channel().close();
}
catch(Exception e)
{
e.printStackTrace();
}
if(DEBUG_LS_GS)
{
log.info("LS Debug: Closing connection with GS.");
}
}
public void addGameServer(AttGS gs)
{
synchronized(gameservers)
{
gameservers.add(gs);
}
}
public void removeGameserver(AttGS gs)
{
synchronized(gameservers)
{
log.info("Removing GameServer");
gameservers.remove(gs);
}
}
public boolean isShutdown()
{
return shutdown;
}
public void setShutdown(boolean shutdown)
{
this.shutdown = shutdown;
}
public void broadcastPacket(ServerBasePacket packet)
{
synchronized(gameservers)
{
for(AttGS gs : gameservers)
{
gs.sendPacket(packet);
}
}
}
public AttGS getGameServerByServerId(int id)
{
synchronized(gameservers)
{
for(AttGS gs : gameservers)
{
if(gs.getServerId() == id)
{
return gs;
}
}
}
return null;
}
}