Package l2p.gameserver.loginservercon

Source Code of l2p.gameserver.loginservercon.LSConnection

package l2p.gameserver.loginservercon;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Logger;

import javolution.util.FastMap;
import l2p.Config;
import l2p.Server;
import l2p.common.ThreadPoolManager;
import l2p.gameserver.cache.Msg;
import l2p.gameserver.loginservercon.gspackets.GameServerBasePacket;
import l2p.gameserver.loginservercon.gspackets.PlayerAuthRequest;
import l2p.gameserver.model.L2Player;
import l2p.gameserver.network.L2GameClient;
import l2p.gameserver.serverpackets.LoginFail;
import l2p.util.BannedIp;
import l2p.util.GArray;
import l2p.util.Util;

public class LSConnection extends Thread
{
  private static final Logger log = Logger.getLogger(LSConnection.class.getName());
  private static final LSConnection instance = new LSConnection();
  private Selector selector;
  private final FastMap<String, L2GameClient> waitingClients = FastMap.newInstance();
  private final FastMap<String, L2GameClient> accountsInGame = FastMap.newInstance();
  private SelectionKey key;
  private SocketChannel channel;
  private volatile boolean shutdown;
  private volatile boolean restart = true;
  private GArray<BannedIp> bannedIpList;

  public static LSConnection getInstance()
  {
    return instance;
  }

  private LSConnection()
  {
    try
    {
      selector = Selector.open();
    }
    catch(IOException e)
    {
      e.printStackTrace();
      log.warning("LSConnection: Can't open selector, restarting.");
      Server.exit(2, "LSConnection: Can't open selector, restarting.");
    }
    if(Config.DEBUG_GS_LS)
    {
      log.info("GS Debug: Selector started.");
    }
  }

  private void reconnect()
  {
    try
    {
      log.info("GameServer: Connecting to LoginServer on " + Config.GAME_SERVER_LOGIN_HOST + ":" + Config.GAME_SERVER_LOGIN_PORT);
      selector.close();
      selector = Selector.open();
      channel = SocketChannel.open();
      channel.configureBlocking(false);
      channel.register(selector, SelectionKey.OP_CONNECT);
      channel.connect(new InetSocketAddress(Config.GAME_SERVER_LOGIN_HOST, Config.GAME_SERVER_LOGIN_PORT));
      key = channel.keyFor(selector);
      restart = false;
    }
    catch(Exception e)
    {
      log.info("Cant connect to server: " + e.getMessage());
    }
  }

  private void readSelected()
  {
    while(!(shutdown || restart))
    {
      try
      {
        if(key == null || !key.isValid())
        {
          return;
        }
        AttLS att = (AttLS) key.attachment();
        if(att != null)
        {
          ArrayDeque<GameServerBasePacket> sendQueue = att.getSendPacketQueue();
          synchronized(sendQueue)
          {
            if(sendQueue.isEmpty())
            {
              key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
              key.interestOps(key.interestOps() | SelectionKey.OP_READ);
            }
            else
            {
              key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
            }
          }
        }
        int keyNum = selector.selectNow();
        if(keyNum > 0)
        {
          Iterator<?> keys = selector.selectedKeys().iterator();
          while(keys.hasNext())
          {
            SelectionKey key = (SelectionKey) keys.next();
            keys.remove();
            if(!key.isValid())
            {
              close(key);
              continue;
            }
            int opts = key.readyOps();
            if(Config.DEBUG_GS_LS)
            {
              log.info("GS Debug: key selected, readyOpts: " + opts);
            }
            switch(opts)
            {
              case SelectionKey.OP_CONNECT:
                connect(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.warning("LSConnection: unknown readyOpts: " + opts);
            }
          }
        }
        Thread.sleep(1);
      }
      catch(Exception e)
      {
        System.out.println("Disconnected from LoginServer:");
        e.printStackTrace();
        close(key);
        break;
      }
    }
  }

  @Override
  public void run()
  {
    while(restart)
    {
      reconnect();
      readSelected();
      close(null);
      try
      {
        Thread.sleep(1000);
      }
      catch(InterruptedException e)
      {
        e.printStackTrace();
      }
      if(shutdown)
      {
        break;
      }
    }
  }

  public void read(SelectionKey key)
  {
    AttLS att = (AttLS) key.attachment();
    SocketChannel channel = (SocketChannel) key.channel();
    int numRead;
    try
    {
      numRead = channel.read(att.getReadBuffer());
    }
    catch(IOException e)
    {
      close(key);
      return;
    }
    if(numRead == -1)
    {
      close(key);
      return;
    }
    if(numRead == 0)
    {
      return;
    }
    att.processData();
    if(Config.DEBUG_GS_LS)
    {
      log.info("GS Debug: data readed");
    }
  }

  public void write(SelectionKey key)
  {
    AttLS att = (AttLS) key.attachment();
    SocketChannel channel = (SocketChannel) key.channel();
    ArrayDeque<GameServerBasePacket> sendPacketQueue = att.getSendPacketQueue();
    if(!att.isCryptInitialized())
    {
      return;
    }
    try
    {
      GameServerBasePacket packet;
      byte[] data;
      synchronized(sendPacketQueue)
      {
        while((packet = sendPacketQueue.poll()) != null)
        {
          data = packet.getBytes();
          if(!(packet instanceof l2p.gameserver.loginservercon.gspackets.BlowFishKey))
          {
            data = att.encrypt(data);
          }
          data = Util.writeLenght(data);
          channel.write(ByteBuffer.wrap(data));
          if(Config.DEBUG_GS_LS)
          {
            log.info("GameServer -> LoginServer: Sending packet: " + packet.getClass().getSimpleName());
          }
        }
      }
    }
    catch(Exception e)
    {
      close(key);
      return;
    }
    key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
    if(Config.DEBUG_GS_LS)
    {
      log.info("GS Debug: Data sended");
    }
  }

  public void connect(SelectionKey key)
  {
    SocketChannel channel = (SocketChannel) key.channel();
    try
    {
      channel.finishConnect();
    }
    catch(IOException e)
    {
      close(key);
      return;
    }
    key.attach(new AttLS(key, this));
    key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
    key.interestOps(key.interestOps() | SelectionKey.OP_READ);
    if(Config.DEBUG_GS_LS)
    {
      log.info("GS Debug: connection established");
    }
  }

  public void close(SelectionKey key)
  {
    if(Config.DEBUG_GS_LS)
    {
      log.info("GS Debug: closing connection");
    }
    if(key == null)
    {
      key = this.key;
    }
    if(key == null && channel != null)
    {
      key = channel.keyFor(selector);
    }
    if(key != null)
    {
      key.cancel();
      AttLS att = (AttLS) key.attachment();
      if(att != null)
      {
        att.close();
      }
    }
    try
    {
      if(channel != null)
      {
        channel.close();
      }
    }
    catch(IOException e)
    {
    }
    this.key = null;
    channel = null;
    if(shutdown)
    {
      return;
    }
    restart = true;
    synchronized(waitingClients)
    {
      Collection<L2GameClient> wc = waitingClients.values();
      for(L2GameClient c : wc)
      {
        c.sendPacket(new LoginFail(LoginFail.SYSTEM_ERROR_LOGIN_LATER));
        ThreadPoolManager.getInstance().scheduleGeneral(new KickWaitingClientTask(c), 1000);
      }
      waitingClients.clear();
    }
    GArray<L2GameClient> accountsToClose = new GArray<L2GameClient>(accountsInGame.size());
    synchronized(accountsInGame)
    {
      for(L2GameClient client : accountsInGame.values())
      {
        if(client.getActiveChar() == null)
        {
          accountsToClose.add(client);
        }
      }
      accountsInGame.clear();
    }
    for(L2GameClient client : accountsToClose)
    {
      if(client.getActiveChar() == null)
      {
        client.closeNow(false);
      }
    }
  }

  public void sendPacket(GameServerBasePacket packet)
  {
    if(shutdown || key == null || key.attachment() == null)
    {
      return;
    }
    AttLS att = (AttLS) key.attachment();
    att.sendPacket(packet);
  }

  public void addWaitingClient(L2GameClient client)
  {
    synchronized(waitingClients)
    {
      // Если идет процесс выключения даного трида, то не позволяем сюда логинится.
      if(shutdown || key == null || key.attachment() == null)
      {
        client.sendPacket(new LoginFail(LoginFail.SYSTEM_ERROR_LOGIN_LATER));
        ThreadPoolManager.getInstance().scheduleGeneral(new KickWaitingClientTask(client), 1000);
        return;
      }
      L2GameClient sameClient = waitingClients.remove(client.getLoginName());
      if(sameClient != null)
      {
        sameClient.sendPacket(new LoginFail(LoginFail.ACOUNT_ALREADY_IN_USE));
        ThreadPoolManager.getInstance().scheduleGeneral(new KickWaitingClientTask(sameClient), 1000);
      }
      waitingClients.put(client.getLoginName(), client);
      sendPacket(new PlayerAuthRequest(client));
    }
    if(Config.DEBUG_GS_LS)
    {
      log.info("GameServer: Adding client to waiting list: " + client.getLoginName());
    }
  }

  public L2GameClient removeWaitingClient(String account)
  {
    L2GameClient client;
    synchronized(waitingClients)
    {
      client = waitingClients.remove(account);
    }
    return client;
  }

  public void addAccountInGame(L2GameClient client)
  {
    if(client == null)
    {
      return;
    }
    synchronized(accountsInGame)
    {
      // Если идет процесс выключения даного трида, то не позволяем сюда логинится.
      if(shutdown || key == null || key.attachment() == null)
      {
        client.sendPacket(new LoginFail(LoginFail.SYSTEM_ERROR_LOGIN_LATER));
        ThreadPoolManager.getInstance().scheduleGeneral(new KickWaitingClientTask(client), 1000);
        return;
      }
      L2GameClient oldClient = null;
      if(client.getLoginName() != null)
      {
        oldClient = accountsInGame.remove(client.getLoginName());
      }
      if(oldClient != null)
      {
        L2Player activeChar = oldClient.getActiveChar();
        if(activeChar != null)
        {
          activeChar.sendPacket(Msg.ANOTHER_PERSON_HAS_LOGGED_IN_WITH_THE_SAME_ACCOUNT);
          oldClient.sendPacket(Msg.ServerClose);
        }
        else
        {
          oldClient.sendPacket(Msg.ServerClose);
        }
        ThreadPoolManager.getInstance().scheduleGeneral(new KickPlayerInGameTask(oldClient), 1000);
      }
      if(client.getLoginName() != null)
      {
        accountsInGame.put(client.getLoginName(), client);
      }
    }
  }

  public void removeAccountInGame(L2GameClient client)
  {
    synchronized(accountsInGame)
    {
      String loginName = client.getLoginName();
      L2GameClient oldClient = accountsInGame.get(loginName);
      if(client.equals(oldClient))
      {
        accountsInGame.remove(loginName);
      }
    }
  }

  public L2GameClient getAccountInGame(String account)
  {
    synchronized(accountsInGame)
    {
      return accountsInGame.get(account);
    }
  }

  public void kickAccountInGame(String account)
  {
    synchronized(accountsInGame)
    {
      L2GameClient client = accountsInGame.get(account);
      if(client != null)
      {
        L2Player activeChar = client.getActiveChar();
        if(activeChar != null)
        {
          activeChar.sendPacket(Msg.ANOTHER_PERSON_HAS_LOGGED_IN_WITH_THE_SAME_ACCOUNT);
        }
        else
        {
          client.sendPacket(Msg.ServerClose);
        }
        ThreadPoolManager.getInstance().scheduleGeneral(new KickPlayerInGameTask(client), 1000);
      }
    }
  }

  public void removeAccount(L2GameClient client)
  {
    if(client.getState() == L2GameClient.GameClientState.CONNECTED)
    {
      removeWaitingClient(client.getLoginName());
    }
    else
    {
      removeAccountInGame(client);
    }
  }

  public void shutdown()
  {
    shutdown = true;
  }

  public boolean isShutdown()
  {
    return shutdown;
  }

  public void restart()
  {
    restart = true;
  }

  public GArray<BannedIp> getBannedIpList()
  {
    return bannedIpList;
  }

  public void setBannedIpList(GArray<BannedIp> bannedIpList)
  {
    this.bannedIpList = bannedIpList;
  }
}
TOP

Related Classes of l2p.gameserver.loginservercon.LSConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.