/** * This file is part of aion-emu <aion-emu.com>. * * aion-emu is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * aion-emu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with aion-emu. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.loginserver.network.gameserver; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.ArrayDeque; import java.util.Deque; import org.apache.log4j.Logger; import com.aionemu.commons.network.AConnection; import com.aionemu.commons.network.Dispatcher; import com.aionemu.loginserver.GameServerInfo; import com.aionemu.loginserver.utils.ThreadPoolManager; /** * Object representing connection between LoginServer and GameServer. * * @author -Nemesiss- */ public class GsConnection extends AConnection { /** * Logger for this class. */ private static final Logger log = Logger.getLogger(GsConnection.class); /** * Possible states of GsConnection */ public static enum State { /** * Means that GameServer just connect, but is not authenticated yet */ CONNECTED, /** * GameServer is authenticated */ AUTHED } /** * Server Packet "to send" Queue */ private final Deque<GsServerPacket> sendMsgQueue = new ArrayDeque<GsServerPacket>(); /** * Current state of this connection */ private State state; /** * GameServerInfo for this GsConnection. */ private GameServerInfo gameServerInfo = null; /** * Constructor. * * @param sc * @param d * @throws IOException */ public GsConnection(SocketChannel sc, Dispatcher d) throws IOException { super(sc, d); state = State.CONNECTED; String ip = getIP(); log.info("GS connection from: " + ip); } /** * Called by Dispatcher. ByteBuffer data contains one packet that should be processed. * * @param data * @return True if data was processed correctly, False if some error occurred and connection should be closed NOW. */ @Override public boolean processData(ByteBuffer data) { GsClientPacket pck = GsPacketHandler.handle(data, this); log.info("recived packet: " + pck); if (pck != null && pck.read()) ThreadPoolManager.getInstance().executeGsPacket(pck); return true; } /** * This method will be called by Dispatcher, and will be repeated till return false. * * @param data * @return True if data was written to buffer, False indicating that there are not any more data to write. */ @Override protected final boolean writeData(ByteBuffer data) { synchronized (guard) { GsServerPacket packet = sendMsgQueue.pollFirst(); if (packet == null) return false; packet.write(this, data); return true; } } /** * This method is called by Dispatcher when connection is ready to be closed. * * @return time in ms after witch onDisconnect() method will be called. Always return 0. */ @Override protected final long getDisconnectionDelay() { return 0; } /** * {@inheritDoc} */ @Override protected final void onDisconnect() { log.info(this + " disconnected"); if (gameServerInfo != null) { gameServerInfo.setGsConnection(null); gameServerInfo.clearAccountsOnGameServer(); gameServerInfo = null; } } /** * {@inheritDoc} */ @Override protected final void onServerClose() { // TODO mb some packet should be send to gameserver before closing? close(/* packet, */true); } /** * Sends GsServerPacket to this client. * * @param bp * GsServerPacket to be sent. */ public final void sendPacket(GsServerPacket bp) { synchronized (guard) { /** * Connection is already closed or waiting for last (close packet) to be sent */ if (isWriteDisabled()) return; log.info("sending packet: " + bp); sendMsgQueue.addLast(bp); enableWriteInterest(); } } /** * Its guaranted that closePacket will be sent before closing connection, but all past and future packets wont. * Connection will be closed [by Dispatcher Thread], and onDisconnect() method will be called to clear all other * things. forced means that server shouldn't wait with removing this connection. * * @param closePacket * Packet that will be send before closing. * @param forced * have no effect in this implementation. */ public final void close(GsServerPacket closePacket, boolean forced) { synchronized (guard) { if (isWriteDisabled()) return; log.info("sending packet: " + closePacket + " and closing connection after that."); pendingClose = true; isForcedClosing = forced; sendMsgQueue.clear(); sendMsgQueue.addLast(closePacket); enableWriteInterest(); } } /** * @return Current state of this connection. */ public State getState() { return state; } /** * @param state * Set current state of this connection. */ public void setState(State state) { this.state = state; } /** * @return GameServerInfo for this GsConnection or null if this GsConnection is not authenticated yet. */ public GameServerInfo getGameServerInfo() { return gameServerInfo; } /** * @param gameServerInfo * Set GameServerInfo for this GsConnection. */ public void setGameServerInfo(GameServerInfo gameServerInfo) { this.gameServerInfo = gameServerInfo; } /** * @return String info about this connection */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("GameServer [ID:"); if (gameServerInfo != null) { sb.append(gameServerInfo.getId()); } else { sb.append("null"); } sb.append("] ").append(getIP()); return sb.toString(); } }