Dropped mmocore from login.

Thanks Liamxroy.
This commit is contained in:
MobiusDev
2017-12-19 19:50:01 +00:00
parent 2f91782574
commit 3f9c0c6696
248 changed files with 3692 additions and 12475 deletions

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -12,11 +12,11 @@
# Networking # Networking
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Bind ip of the LoginServer, use * to bind on all available IPs # Bind ip of the LoginServer, use 0.0.0.0 to bind on all available IPs
# WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u> # WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u>
# WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u> # WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u>
# Default: * (0.0.0.0) # Default: 0.0.0.0
LoginserverHostname = * LoginserverHostname = 0.0.0.0
# Default: 2106 # Default: 2106
LoginserverPort = 2106 LoginserverPort = 2106

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -92,7 +92,6 @@ public final class Config
public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini"; public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
public static final String MMO_CONFIG_FILE = "./config/MMO.ini";
public static final String NPC_CONFIG_FILE = "./config/NPC.ini"; public static final String NPC_CONFIG_FILE = "./config/NPC.ini";
public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini"; public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini";
public static final String PVP_CONFIG_FILE = "./config/PVP.ini"; public static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -1776,15 +1775,6 @@ public final class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
// Load IdFactory config file (if exists) // Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE); final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
@@ -2866,7 +2856,7 @@ public final class Config
GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1"); GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1");
GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013); GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013);
LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "*"); LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "0.0.0.0");
PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106); PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106);
try try
@@ -2904,15 +2894,6 @@ public final class Config
NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700); NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700);
FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350); FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350);
MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50); MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
} }
else else
{ {

View File

@@ -16,14 +16,17 @@
*/ */
package com.l2jmobius.commons.util.crypt; package com.l2jmobius.commons.util.crypt;
import java.io.IOException; import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.ICrypt;
import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.commons.util.Rnd;
import io.netty.buffer.ByteBuf;
/** /**
* @author KenM * @author NosBit
*/ */
public class LoginCrypt public class LoginCrypt implements ICrypt
{ {
private static final byte[] STATIC_BLOWFISH_KEY = private static final byte[] STATIC_BLOWFISH_KEY =
{ {
@@ -45,82 +48,102 @@ public class LoginCrypt
(byte) 0x6c (byte) 0x6c
}; };
private static final NewCrypt _STATIC_CRYPT = new NewCrypt(STATIC_BLOWFISH_KEY); private static final BlowfishEngine STATIC_BLOWFISH_ENGINE = new BlowfishEngine();
private NewCrypt _crypt = null;
static
{
STATIC_BLOWFISH_ENGINE.init(STATIC_BLOWFISH_KEY);
}
private final BlowfishEngine _blowfishEngine = new BlowfishEngine();
private boolean _static = true; private boolean _static = true;
/** public LoginCrypt(SecretKey blowfishKey)
* Method to initialize the the blowfish cipher with dynamic key.
* @param key the blowfish key to initialize the dynamic blowfish cipher with
*/
public void setKey(byte[] key)
{ {
_crypt = new NewCrypt(key); _blowfishEngine.init(blowfishKey.getEncoded());
} }
/** /*
* Method to decrypt an incoming login client packet. * (non-Javadoc)
* @param raw array with encrypted data * @see com.l2jserver.commons.network.ICrypt#encrypt(io.netty.buffer.ByteBuf)
* @param offset offset where the encrypted data is located
* @param size number of bytes of encrypted data
* @return true when checksum could be verified, false otherwise
* @throws IOException the size is not multiple of blowfishs block size or the raw array can't hold size bytes starting at offset due to it's size
*/ */
public boolean decrypt(byte[] raw, int offset, int size) throws IOException @Override
public void encrypt(ByteBuf buf)
{ {
if ((size % 8) != 0) // Checksum & XOR Key or Checksum only
{ buf.writeZero(_static ? 16 : 12);
throw new IOException("size have to be multiple of 8");
}
if ((offset + size) > raw.length)
{
throw new IOException("raw array too short for size starting from offset");
}
_crypt.decrypt(raw, offset, size); // Padding
return NewCrypt.verifyChecksum(raw, offset, size); buf.writeZero(8 - (buf.readableBytes() % 8));
}
/**
* Method to encrypt an outgoing packet to login client.<br>
* Performs padding and resizing of data array.
* @param raw array with plain data
* @param offset offset where the plain data is located
* @param size number of bytes of plain data
* @return the new array size
* @throws IOException packet is too long to make padding and add verification data
*/
public int encrypt(byte[] raw, int offset, int size) throws IOException
{
// reserve checksum
size += 4;
if (_static) if (_static)
{ {
// reserve for XOR "key"
size += 4;
// padding
size += 8 - (size % 8);
if ((offset + size) > raw.length)
{
throw new IOException("packet too long");
}
NewCrypt.encXORPass(raw, offset, size, Rnd.nextInt());
_STATIC_CRYPT.crypt(raw, offset, size);
_static = false; _static = false;
int key = Rnd.nextInt();
buf.skipBytes(4); // The first 4 bytes are ignored
while (buf.readerIndex() < (buf.writerIndex() - 8))
{
int data = buf.readIntLE();
key += data;
data ^= key;
buf.setIntLE(buf.readerIndex() - 4, data);
}
buf.setIntLE(buf.readerIndex(), key);
buf.resetReaderIndex();
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
STATIC_BLOWFISH_ENGINE.encryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
}
} }
else else
{ {
// padding int checksum = 0;
size += 8 - (size % 8); while (buf.isReadable(8))
if ((offset + size) > raw.length)
{ {
throw new IOException("packet too long"); checksum ^= buf.readIntLE();
}
buf.setIntLE(buf.readerIndex(), checksum);
buf.resetReaderIndex();
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
_blowfishEngine.encryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
} }
NewCrypt.appendChecksum(raw, offset, size);
_crypt.crypt(raw, offset, size);
} }
return size; }
/*
* (non-Javadoc)
* @see com.l2jserver.commons.network.ICrypt#decrypt(io.netty.buffer.ByteBuf)
*/
@Override
public void decrypt(ByteBuf buf)
{
// Packet size must be multiple of 8
if ((buf.readableBytes() % 8) != 0)
{
buf.clear();
return;
}
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
_blowfishEngine.decryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
}
// TODO: verify checksum also dont forget!
} }
} }

View File

@@ -72,4 +72,9 @@ public class ScrambledKeyPair
return scrambledMod; return scrambledMod;
} }
public byte[] getScrambledModulus()
{
return _scrambledModulus;
}
} }

View File

@@ -65,7 +65,7 @@ public final class GameServerTable implements IGameXmlReader
load(); load();
loadRegisteredGameServers(); loadRegisteredGameServers();
LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + GAME_SERVER_TABLE.size() + " registered Game Servers"); LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + GAME_SERVER_TABLE.size() + " registered Game Servers.");
initRSAKeys(); initRSAKeys();
LOGGER.info(GameServerTable.class.getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication."); LOGGER.info(GameServerTable.class.getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication.");
@@ -76,7 +76,7 @@ public final class GameServerTable implements IGameXmlReader
{ {
SERVER_NAMES.clear(); SERVER_NAMES.clear();
parseDatapackFile("data/servername.xml"); parseDatapackFile("data/servername.xml");
LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + SERVER_NAMES.size() + " server names"); LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + SERVER_NAMES.size() + " server names.");
} }
@Override @Override

View File

@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.logging.Level; import java.util.logging.Level;
@@ -32,10 +31,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.Server; import com.l2jmobius.Server;
import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.ClientNetworkManager;
import com.l2jmobius.loginserver.network.L2LoginPacketHandler;
import com.l2jmobius.loginserver.network.mmocore.SelectorConfig;
import com.l2jmobius.loginserver.network.mmocore.SelectorThread;
/** /**
* @author KenM * @author KenM
@@ -47,10 +43,9 @@ public final class L2LoginServer
public static final int PROTOCOL_REV = 0x0106; public static final int PROTOCOL_REV = 0x0106;
private static L2LoginServer _instance; private static L2LoginServer _instance;
private GameServerListener _gameServerListener; private GameServerListener _gameServerListener;
private SelectorThread<L2LoginClient> _selectorThread;
private Thread _restartLoginServer; private Thread _restartLoginServer;
public static void main(String[] args) public static void main(String[] args) throws Exception
{ {
new L2LoginServer(); new L2LoginServer();
} }
@@ -60,7 +55,7 @@ public final class L2LoginServer
return _instance; return _instance;
} }
private L2LoginServer() private L2LoginServer() throws Exception
{ {
_instance = this; _instance = this;
Server.serverMode = Server.MODE_LOGINSERVER; Server.serverMode = Server.MODE_LOGINSERVER;
@@ -105,37 +100,6 @@ public final class L2LoginServer
loadBanFile(); loadBanFile();
InetAddress bindAddress = null;
if (!Config.LOGIN_BIND_ADDRESS.equals("*"))
{
try
{
bindAddress = InetAddress.getByName(Config.LOGIN_BIND_ADDRESS);
}
catch (UnknownHostException e)
{
_log.log(Level.WARNING, "WARNING: The LoginServer bind address is invalid, using all avaliable IPs. Reason: " + e.getMessage(), e);
}
}
final SelectorConfig sc = new SelectorConfig();
sc.MAX_READ_PER_PASS = Config.MMO_MAX_READ_PER_PASS;
sc.MAX_SEND_PER_PASS = Config.MMO_MAX_SEND_PER_PASS;
sc.SLEEP_TIME = Config.MMO_SELECTOR_SLEEP_TIME;
sc.HELPER_BUFFER_COUNT = Config.MMO_HELPER_BUFFER_COUNT;
final L2LoginPacketHandler lph = new L2LoginPacketHandler();
final SelectorHelper sh = new SelectorHelper();
try
{
_selectorThread = new SelectorThread<>(sc, sh, lph, sh, sh);
}
catch (IOException e)
{
_log.log(Level.SEVERE, "FATAL: Failed to open Selector. Reason: " + e.getMessage(), e);
System.exit(1);
}
try try
{ {
_gameServerListener = new GameServerListener(); _gameServerListener = new GameServerListener();
@@ -148,17 +112,7 @@ public final class L2LoginServer
System.exit(1); System.exit(1);
} }
try ClientNetworkManager.getInstance().start();
{
_selectorThread.openServerSocket(bindAddress, Config.PORT_LOGIN);
_selectorThread.start();
_log.info(getClass().getSimpleName() + ": is now listening on: " + Config.LOGIN_BIND_ADDRESS + ":" + Config.PORT_LOGIN);
}
catch (IOException e)
{
_log.log(Level.SEVERE, "FATAL: Failed to open server socket. Reason: " + e.getMessage(), e);
System.exit(1);
}
} }
public GameServerListener getGameServerListener() public GameServerListener getGameServerListener()

View File

@@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAKeyGenParameterSpec; import java.security.spec.RSAKeyGenParameterSpec;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@@ -37,7 +36,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.Cipher; import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.commons.database.DatabaseFactory;
@@ -64,10 +64,8 @@ public class LoginController
private final Map<InetAddress, Integer> _failedLoginAttemps = new HashMap<>(); private final Map<InetAddress, Integer> _failedLoginAttemps = new HashMap<>();
private final Map<InetAddress, Long> _bannedIps = new ConcurrentHashMap<>(); private final Map<InetAddress, Long> _bannedIps = new ConcurrentHashMap<>();
protected ScrambledKeyPair[] _keyPairs; private final ScrambledKeyPair[] _keyPairs;
private final KeyGenerator _blowfishKeyGenerator;
protected byte[][] _blowfishKeys;
private static final int BLOWFISH_KEYS = 20;
// SQL Queries // SQL Queries
private static final String USER_INFO_SELECT = "SELECT login, password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?"; private static final String USER_INFO_SELECT = "SELECT login, password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?";
@@ -83,62 +81,26 @@ public class LoginController
_log.info("Loading LoginController..."); _log.info("Loading LoginController...");
_keyPairs = new ScrambledKeyPair[10]; _keyPairs = new ScrambledKeyPair[10];
_blowfishKeyGenerator = KeyGenerator.getInstance("Blowfish");
final KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA"); final KeyPairGenerator rsaKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4); final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4);
keygen.initialize(spec); rsaKeyPairGenerator.initialize(spec);
// generate the initial set of keys for (int i = 0; i < _keyPairs.length; i++)
for (int i = 0; i < 10; i++)
{ {
_keyPairs[i] = new ScrambledKeyPair(keygen.generateKeyPair()); _keyPairs[i] = new ScrambledKeyPair(rsaKeyPairGenerator.generateKeyPair());
} }
_log.info("Cached 10 KeyPairs for RSA communication");
testCipher((RSAPrivateKey) _keyPairs[0]._pair.getPrivate()); _log.info("Cached 10 KeyPairs for RSA communication.");
// Store keys for blowfish communication
generateBlowFishKeys();
final Thread purge = new PurgeThread(); final Thread purge = new PurgeThread();
purge.setDaemon(true); purge.setDaemon(true);
purge.start(); purge.start();
} }
/** public SecretKey generateBlowfishKey()
* This is mostly to force the initialization of the Crypto Implementation, avoiding it being done on runtime when its first needed.<BR>
* In short it avoids the worst-case execution time on runtime by doing it on loading.
* @param key Any private RSA Key just for testing purposes.
* @throws GeneralSecurityException if a underlying exception was thrown by the Cipher
*/
private void testCipher(RSAPrivateKey key) throws GeneralSecurityException
{ {
// avoid worst-case execution, KenM return _blowfishKeyGenerator.generateKey();
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
rsaCipher.init(Cipher.DECRYPT_MODE, key);
}
private void generateBlowFishKeys()
{
_blowfishKeys = new byte[BLOWFISH_KEYS][16];
for (int i = 0; i < BLOWFISH_KEYS; i++)
{
for (int j = 0; j < _blowfishKeys[i].length; j++)
{
_blowfishKeys[i][j] = (byte) (Rnd.nextInt(255) + 1);
}
}
_log.info("Stored " + _blowfishKeys.length + " keys for Blowfish communication");
}
/**
* @return Returns a random key
*/
public byte[] getBlowfishKey()
{
return _blowfishKeys[(int) (Math.random() * BLOWFISH_KEYS)];
} }
public SessionKey assignSessionKeyToClient(String account, L2LoginClient client) public SessionKey assignSessionKeyToClient(String account, L2LoginClient client)

View File

@@ -1,67 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.IAcceptFilter;
import com.l2jmobius.loginserver.network.mmocore.IClientFactory;
import com.l2jmobius.loginserver.network.mmocore.IMMOExecutor;
import com.l2jmobius.loginserver.network.mmocore.MMOConnection;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
import com.l2jmobius.loginserver.network.serverpackets.Init;
import com.l2jmobius.loginserver.network.util.IPv4Filter;
/**
* @author KenM
*/
public class SelectorHelper implements IMMOExecutor<L2LoginClient>, IClientFactory<L2LoginClient>, IAcceptFilter
{
private final ThreadPoolExecutor _generalPacketsThreadPool;
private final IPv4Filter _ipv4filter;
public SelectorHelper()
{
_generalPacketsThreadPool = new ThreadPoolExecutor(4, 6, 15L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
_ipv4filter = new IPv4Filter();
}
@Override
public void execute(ReceivablePacket<L2LoginClient> packet)
{
_generalPacketsThreadPool.execute(packet);
}
@Override
public L2LoginClient create(MMOConnection<L2LoginClient> con)
{
final L2LoginClient client = new L2LoginClient(con);
client.sendPacket(new Init(client));
return client;
}
@Override
public boolean accept(SocketChannel sc) throws UnknownHostException
{
return _ipv4filter.accept(sc) && !LoginController.getInstance().isBannedAddress(sc.socket().getInetAddress());
}
}

View File

@@ -14,15 +14,26 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import com.l2jmobius.loginserver.LoginController;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ipfilter.AbstractRemoteAddressFilter;
/** /**
* @author KenM * @author lord_rex
*/ */
public interface IAcceptFilter @Sharable
public final class BannedIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress>
{ {
boolean accept(SocketChannel sc) throws UnknownHostException; @Override
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws UnknownHostException
{
return !LoginController.getInstance().isBannedAddress(remoteAddress.getAddress());
}
} }

View File

@@ -0,0 +1,56 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.nio.ByteOrder;
import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.codecs.CryptCodec;
import com.l2jmobius.commons.network.codecs.LengthFieldBasedFrameEncoder;
import com.l2jmobius.commons.network.codecs.PacketDecoder;
import com.l2jmobius.commons.network.codecs.PacketEncoder;
import com.l2jmobius.commons.util.crypt.LoginCrypt;
import com.l2jmobius.loginserver.LoginController;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
/**
* @author Nos
*/
public class ClientInitializer extends ChannelInitializer<SocketChannel>
{
private static final LengthFieldBasedFrameEncoder LENGTH_ENCODER = new LengthFieldBasedFrameEncoder();
private static final PacketEncoder PACKET_ENCODER = new PacketEncoder(0x8000 - 2);
@Override
protected void initChannel(SocketChannel ch)
{
final SecretKey newKey = LoginController.getInstance().generateBlowfishKey();
final L2LoginClient client = new L2LoginClient(newKey);
ch.pipeline().addLast(new BannedIpFilter());
ch.pipeline().addLast("length-decoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 0x8000 - 2, 0, 2, -2, 2, false));
ch.pipeline().addLast("length-encoder", LENGTH_ENCODER);
ch.pipeline().addLast("crypt-codec", new CryptCodec(new LoginCrypt(newKey)));
// ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
ch.pipeline().addLast("packet-decoder", new PacketDecoder<>(IncomingPackets.PACKET_ARRAY, client));
ch.pipeline().addLast("packet-encoder", PACKET_ENCODER);
ch.pipeline().addLast(client);
}
}

View File

@@ -14,48 +14,28 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import java.nio.BufferOverflowException; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.NetworkManager;
/** /**
* @author Forsaiken * @author Nos
*/ */
public final class NioNetStringBuffer public class ClientNetworkManager extends NetworkManager
{ {
private final char[] _buf; protected ClientNetworkManager()
private final int _size;
private int _len;
public NioNetStringBuffer(int size)
{ {
_buf = new char[size]; super(EventLoopGroupManager.getInstance().getBossGroup(), EventLoopGroupManager.getInstance().getWorkerGroup(), new ClientInitializer(), Config.LOGIN_BIND_ADDRESS, Config.PORT_LOGIN);
_size = size;
_len = 0;
} }
public final void clear() public static ClientNetworkManager getInstance()
{ {
_len = 0; return SingletonHolder._instance;
} }
public final void append(char c) private static class SingletonHolder
{ {
if (_len < _size) protected static final ClientNetworkManager _instance = new ClientNetworkManager();
{
_buf[_len++] = c;
}
else
{
throw new BufferOverflowException();
}
}
@Override
public final String toString()
{
return new String(_buf, 0, _len);
} }
} }

View File

@@ -14,13 +14,16 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import com.l2jmobius.commons.network.IConnectionState;
/** /**
* @author KenM * @author Mobius
* @param <T>
*/ */
public interface IClientFactory<T extends MMOClient<?>> public enum ConnectionState implements IConnectionState
{ {
T create(MMOConnection<T> con); CONNECTED,
AUTHED_GG,
AUTHED_LOGIN;
} }

View File

@@ -0,0 +1,56 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import com.l2jmobius.Config;
import io.netty.channel.nio.NioEventLoopGroup;
/**
* @author Nos
*/
public class EventLoopGroupManager
{
private final NioEventLoopGroup _bossGroup = new NioEventLoopGroup(1);
private final NioEventLoopGroup _workerGroup = new NioEventLoopGroup(Config.IO_PACKET_THREAD_CORE_SIZE);
public NioEventLoopGroup getBossGroup()
{
return _bossGroup;
}
public NioEventLoopGroup getWorkerGroup()
{
return _workerGroup;
}
public void shutdown()
{
_bossGroup.shutdownGracefully();
_workerGroup.shutdownGracefully();
}
public static EventLoopGroupManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final EventLoopGroupManager _instance = new EventLoopGroupManager();
}
}

View File

@@ -0,0 +1,92 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import com.l2jmobius.commons.network.IConnectionState;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IIncomingPackets;
import com.l2jmobius.loginserver.network.clientpackets.AuthGameGuard;
import com.l2jmobius.loginserver.network.clientpackets.RequestAuthLogin;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreement;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreementCheck;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerList;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerLogin;
/**
* @author Mobius
*/
public enum IncomingPackets implements IIncomingPackets<L2LoginClient>
{
AUTH_GAME_GUARD(0x07, AuthGameGuard::new, ConnectionState.CONNECTED),
REQUEST_AUTH_LOGIN(0x00, RequestAuthLogin::new, ConnectionState.AUTHED_GG),
REQUEST_SERVER_LOGIN(0x02, RequestServerLogin::new, ConnectionState.AUTHED_LOGIN),
REQUEST_SERVER_LIST(0x05, RequestServerList::new, ConnectionState.AUTHED_LOGIN),
REQUEST_PI_AGREEMENT_CHECK(0x0E, RequestPIAgreementCheck::new, ConnectionState.AUTHED_LOGIN),
REQUEST_PI_AGREEMENT(0x0F, RequestPIAgreement::new, ConnectionState.AUTHED_LOGIN);
public static final IncomingPackets[] PACKET_ARRAY;
static
{
final short maxPacketId = (short) Arrays.stream(values()).mapToInt(IIncomingPackets::getPacketId).max().orElse(0);
PACKET_ARRAY = new IncomingPackets[maxPacketId + 1];
for (IncomingPackets incomingPacket : values())
{
PACKET_ARRAY[incomingPacket.getPacketId()] = incomingPacket;
}
}
private short _packetId;
private Supplier<IIncomingPacket<L2LoginClient>> _incomingPacketFactory;
private Set<IConnectionState> _connectionStates;
IncomingPackets(int packetId, Supplier<IIncomingPacket<L2LoginClient>> incomingPacketFactory, IConnectionState... connectionStates)
{
// packetId is an unsigned byte
if (packetId > 0xFF)
{
throw new IllegalArgumentException("packetId must not be bigger than 0xFF");
}
_packetId = (short) packetId;
_incomingPacketFactory = incomingPacketFactory != null ? incomingPacketFactory : () -> null;
_connectionStates = new HashSet<>(Arrays.asList(connectionStates));
}
@Override
public int getPacketId()
{
return _packetId;
}
@Override
public IIncomingPacket<L2LoginClient> newIncomingPacket()
{
return _incomingPacketFactory.get();
}
@Override
public Set<IConnectionState> getConnectionStates()
{
return _connectionStates;
}
}

View File

@@ -16,127 +16,103 @@
*/ */
package com.l2jmobius.loginserver.network; package com.l2jmobius.loginserver.network;
import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.nio.ByteBuffer; import java.net.InetSocketAddress;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.ChannelInboundHandler;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.commons.util.crypt.LoginCrypt;
import com.l2jmobius.commons.util.crypt.ScrambledKeyPair; import com.l2jmobius.commons.util.crypt.ScrambledKeyPair;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.mmocore.MMOClient; import com.l2jmobius.loginserver.network.serverpackets.Init;
import com.l2jmobius.loginserver.network.mmocore.MMOConnection;
import com.l2jmobius.loginserver.network.mmocore.SendablePacket;
import com.l2jmobius.loginserver.network.serverpackets.L2LoginServerPacket;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail; import com.l2jmobius.loginserver.network.serverpackets.LoginFail;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail; import com.l2jmobius.loginserver.network.serverpackets.PlayFail;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
/** /**
* Represents a client connected into the LoginServer * Represents a client connected into the LoginServer
* @author KenM * @author KenM
*/ */
public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>> public final class L2LoginClient extends ChannelInboundHandler<L2LoginClient>
{ {
private static final Logger _log = Logger.getLogger(L2LoginClient.class.getName()); private static final Logger _log = Logger.getLogger(L2LoginClient.class.getName());
public enum LoginClientState
{
CONNECTED,
AUTHED_GG,
AUTHED_LOGIN
}
private LoginClientState _state;
// Crypt // Crypt
private final LoginCrypt _loginCrypt;
private final ScrambledKeyPair _scrambledPair; private final ScrambledKeyPair _scrambledPair;
private final byte[] _blowfishKey; private final SecretKey _blowfishKey;
private InetAddress _addr;
private Channel _channel;
private String _account; private String _account;
private int _accessLevel; private int _accessLevel;
private int _lastServer; private int _lastServer;
private SessionKey _sessionKey; private SessionKey _sessionKey;
private final int _sessionId; private int _sessionId;
private boolean _joinedGS; private boolean _joinedGS;
private Map<Integer, Integer> _charsOnServers; private Map<Integer, Integer> _charsOnServers;
private Map<Integer, long[]> _charsToDelete; private Map<Integer, long[]> _charsToDelete;
private final long _connectionStartTime; private long _connectionStartTime;
/** public L2LoginClient(SecretKey blowfishKey)
* @param con
*/
public L2LoginClient(MMOConnection<L2LoginClient> con)
{ {
super(con); super();
_state = LoginClientState.CONNECTED;
_scrambledPair = LoginController.getInstance().getScrambledRSAKeyPair(); _scrambledPair = LoginController.getInstance().getScrambledRSAKeyPair();
_blowfishKey = LoginController.getInstance().getBlowfishKey(); _blowfishKey = blowfishKey;
}
@Override
public void channelActive(ChannelHandlerContext ctx)
{
super.channelActive(ctx);
setConnectionState(ConnectionState.CONNECTED);
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
_addr = address.getAddress();
_channel = ctx.channel();
_sessionId = Rnd.nextInt(); _sessionId = Rnd.nextInt();
_connectionStartTime = System.currentTimeMillis(); _connectionStartTime = System.currentTimeMillis();
_loginCrypt = new LoginCrypt();
_loginCrypt.setKey(_blowfishKey); sendPacket(new Init(_scrambledPair.getScrambledModulus(), _blowfishKey.getEncoded(), _sessionId));
} }
@Override @Override
public boolean decrypt(ByteBuffer buf, int size) public void channelInactive(ChannelHandlerContext ctx)
{ {
boolean isChecksumValid = false; if (!hasJoinedGS() || ((getConnectionStartTime() + LoginController.LOGIN_TIMEOUT) < System.currentTimeMillis()))
try
{ {
isChecksumValid = _loginCrypt.decrypt(buf.array(), buf.position(), size); LoginController.getInstance().removeAuthedLoginClient(getAccount());
if (!isChecksumValid)
{
// _log.warning("Wrong checksum from client: " + toString());
}
return true;
}
catch (IOException e)
{
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
super.getConnection().close((SendablePacket<L2LoginClient>) null);
return false;
} }
} }
@Override @Override
public boolean encrypt(ByteBuffer buf, int size) protected void channelRead0(ChannelHandlerContext ctx, IIncomingPacket<L2LoginClient> packet)
{ {
final int offset = buf.position();
try try
{ {
size = _loginCrypt.encrypt(buf.array(), offset, size); packet.run(this);
} }
catch (IOException e) catch (Exception e)
{ {
_log.warning(getClass().getSimpleName() + ": " + e.getMessage()); _log.warning(getClass().getSimpleName() + ": " + e.getMessage());
return false;
} }
buf.position(offset + size);
return true;
} }
public LoginClientState getState() public InetAddress getConnectionAddress()
{ {
return _state; return _addr;
}
public void setState(LoginClientState state)
{
_state = state;
}
public byte[] getBlowfishKey()
{
return _blowfishKey;
} }
public byte[] getScrambledModulus() public byte[] getScrambledModulus()
@@ -209,24 +185,39 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
return _connectionStartTime; return _connectionStartTime;
} }
public void sendPacket(L2LoginServerPacket lsp) public void sendPacket(IOutgoingPacket packet)
{ {
getConnection().sendPacket(lsp); if ((packet == null))
{
return;
}
// Write into the channel.
_channel.writeAndFlush(packet);
} }
public void close(LoginFailReason reason) public void close(LoginFailReason reason)
{ {
getConnection().close(new LoginFail(reason)); close(new LoginFail(reason));
} }
public void close(PlayFailReason reason) public void close(PlayFailReason reason)
{ {
getConnection().close(new PlayFail(reason)); close(new PlayFail(reason));
} }
public void close(L2LoginServerPacket lsp) public void close(IOutgoingPacket packet)
{ {
getConnection().close(lsp); sendPacket(packet);
closeNow();
}
public void closeNow()
{
if (_channel != null)
{
_channel.close();
}
} }
public void setCharsOnServ(int servId, int chars) public void setCharsOnServ(int servId, int chars)
@@ -256,30 +247,4 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
{ {
return _charsToDelete; return _charsToDelete;
} }
@Override
public void onDisconnection()
{
if (!hasJoinedGS() || ((getConnectionStartTime() + LoginController.LOGIN_TIMEOUT) < System.currentTimeMillis()))
{
LoginController.getInstance().removeAuthedLoginClient(getAccount());
}
}
@Override
public String toString()
{
final InetAddress address = getConnection().getInetAddress();
if (getState() == LoginClientState.AUTHED_LOGIN)
{
return "[" + getAccount() + " (" + (address == null ? "disconnected" : address.getHostAddress()) + ")]";
}
return "[" + (address == null ? "disconnected" : address.getHostAddress()) + "]";
}
@Override
protected void onForcedDisconnection()
{
// Empty
}
} }

View File

@@ -1,124 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState;
import com.l2jmobius.loginserver.network.clientpackets.AuthGameGuard;
import com.l2jmobius.loginserver.network.clientpackets.RequestAuthLogin;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreement;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreementCheck;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerList;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerLogin;
import com.l2jmobius.loginserver.network.mmocore.IPacketHandler;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
/**
* Handler for packets received by Login Server
* @author KenM
*/
public final class L2LoginPacketHandler implements IPacketHandler<L2LoginClient>
{
protected static final Logger _log = Logger.getLogger(L2LoginPacketHandler.class.getName());
@Override
public ReceivablePacket<L2LoginClient> handlePacket(ByteBuffer buf, L2LoginClient client)
{
final int opcode = buf.get() & 0xFF;
ReceivablePacket<L2LoginClient> packet = null;
final LoginClientState state = client.getState();
switch (state)
{
case CONNECTED:
{
switch (opcode)
{
case 0x07:
{
packet = new AuthGameGuard();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
case AUTHED_GG:
{
switch (opcode)
{
case 0x00:
{
packet = new RequestAuthLogin();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
case AUTHED_LOGIN:
{
switch (opcode)
{
case 0x02:
{
packet = new RequestServerLogin();
break;
}
case 0x05:
{
packet = new RequestServerList();
break;
}
case 0x0E:
{
packet = new RequestPIAgreementCheck(); // TODO: Verify names
break;
}
case 0x0F:
{
packet = new RequestPIAgreement();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
}
return packet;
}
private void debugOpcode(int opcode, LoginClientState state)
{
_log.info("Unknown Opcode: " + opcode + " for state: " + state.name());
}
}

View File

@@ -0,0 +1,83 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import com.l2jmobius.commons.network.PacketWriter;
/**
* @author Mobius
*/
public enum OutgoingPackets
{
INIT(0x00),
LOGIN_FAIL(0x01),
ACCOUNT_KICKED(0x02),
LOGIN_OK(0x03),
SERVER_LIST(0x04),
PLAY_FAIL(0x06),
PLAY_OK(0x07),
PI_AGREEMENT_CHECK(0x11),
PI_AGREEMENT_ACK(0x12),
GG_AUTH(0x0b),
LOGIN_OPT_FAIL(0x0D);
private final int _id1;
private final int _id2;
OutgoingPackets(int id1)
{
this(id1, -1);
}
OutgoingPackets(int id1, int id2)
{
_id1 = id1;
_id2 = id2;
}
public int getId1()
{
return _id1;
}
public int getId2()
{
return _id2;
}
public void writeId(PacketWriter packet)
{
packet.writeC(_id1);
if (_id2 > 0)
{
packet.writeH(_id2);
}
}
public static OutgoingPackets getPacket(int id1, int id2)
{
for (OutgoingPackets packet : values())
{
if ((packet.getId1() == id1) && (packet.getId2() == id2))
{
return packet;
}
}
return null;
}
}

View File

@@ -16,7 +16,10 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState; import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.ConnectionState;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.GGAuth; import com.l2jmobius.loginserver.network.serverpackets.GGAuth;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
@@ -24,65 +27,39 @@ import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason
* Format: ddddd * Format: ddddd
* @author -Wooden- * @author -Wooden-
*/ */
public class AuthGameGuard extends L2LoginClientPacket public class AuthGameGuard implements IIncomingPacket<L2LoginClient>
{ {
private int _sessionId; private int _sessionId;
private int _data1;
private int _data2;
private int _data3;
private int _data4;
public int getSessionId() @SuppressWarnings("unused")
{ private int _data1, _data2, _data3, _data4;
return _sessionId;
}
public int getData1()
{
return _data1;
}
public int getData2()
{
return _data2;
}
public int getData3()
{
return _data3;
}
public int getData4()
{
return _data4;
}
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 20) if (packet.getReadableBytes() >= 20)
{ {
_sessionId = readD(); _sessionId = packet.readD();
_data1 = readD(); _data1 = packet.readD();
_data2 = readD(); _data2 = packet.readD();
_data3 = readD(); _data3 = packet.readD();
_data4 = readD(); _data4 = packet.readD();
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
if (_sessionId == getClient().getSessionId()) if (_sessionId == client.getSessionId())
{ {
getClient().setState(LoginClientState.AUTHED_GG); client.setConnectionState(ConnectionState.AUTHED_GG);
getClient().sendPacket(new GGAuth(getClient().getSessionId())); client.sendPacket(new GGAuth(client.getSessionId()));
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -1,47 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.clientpackets;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
/**
* @author KenM
*/
public abstract class L2LoginClientPacket extends ReceivablePacket<L2LoginClient>
{
private static Logger _log = Logger.getLogger(L2LoginClientPacket.class.getName());
@Override
protected final boolean read()
{
try
{
return readImpl();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "ERROR READING: " + getClass().getSimpleName() + ": " + e.getMessage(), e);
return false;
}
}
protected abstract boolean readImpl();
}

View File

@@ -24,12 +24,14 @@ import java.util.logging.Logger;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; import com.l2jmobius.loginserver.GameServerTable.GameServerInfo;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.LoginController.AuthLoginResult; import com.l2jmobius.loginserver.LoginController.AuthLoginResult;
import com.l2jmobius.loginserver.model.data.AccountInfo; import com.l2jmobius.loginserver.model.data.AccountInfo;
import com.l2jmobius.loginserver.network.ConnectionState;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked; import com.l2jmobius.loginserver.network.serverpackets.AccountKicked;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked.AccountKickedReason; import com.l2jmobius.loginserver.network.serverpackets.AccountKicked.AccountKickedReason;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
@@ -42,7 +44,7 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
* *
* <pre> * <pre>
*/ */
public class RequestAuthLogin extends L2LoginClientPacket public class RequestAuthLogin implements IIncomingPacket<L2LoginClient>
{ {
private static Logger _log = Logger.getLogger(RequestAuthLogin.class.getName()); private static Logger _log = Logger.getLogger(RequestAuthLogin.class.getName());
@@ -53,45 +55,28 @@ public class RequestAuthLogin extends L2LoginClientPacket
private String _user; private String _user;
private String _password; private String _password;
/**
* @return
*/
public String getPassword()
{
return _password;
}
/**
* @return
*/
public String getUser()
{
return _user;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 256) if (packet.getReadableBytes() >= 256)
{ {
_newAuthMethod = true; _newAuthMethod = true;
readB(_raw1); packet.readB(_raw1, 0, _raw1.length);
readB(_raw2); packet.readB(_raw2, 0, _raw2.length);
return true; return true;
} }
else if (super._buf.remaining() >= 128) else if (packet.getReadableBytes() >= 128)
{ {
readB(_raw1); packet.readB(_raw1, 0, _raw1.length);
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
final L2LoginClient client = getClient(); byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
final byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
try try
{ {
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding"); final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
@@ -127,7 +112,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
return; return;
} }
final InetAddress clientAddr = client.getConnection().getInetAddress(); final InetAddress clientAddr = client.getConnectionAddress();
final LoginController lc = LoginController.getInstance(); final LoginController lc = LoginController.getInstance();
final AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password); final AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password);
if (info == null) if (info == null)
@@ -143,7 +128,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
case AUTH_SUCCESS: case AUTH_SUCCESS:
{ {
client.setAccount(info.getLogin()); client.setAccount(info.getLogin());
client.setState(LoginClientState.AUTHED_LOGIN); client.setConnectionState(ConnectionState.AUTHED_LOGIN);
client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client)); client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client));
lc.getCharactersOnAccount(info.getLogin()); lc.getCharactersOnAccount(info.getLogin());
if (Config.SHOW_LICENCE) if (Config.SHOW_LICENCE)

View File

@@ -16,27 +16,30 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.PIAgreementAck; import com.l2jmobius.loginserver.network.serverpackets.PIAgreementAck;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class RequestPIAgreement extends L2LoginClientPacket public class RequestPIAgreement implements IIncomingPacket<L2LoginClient>
{ {
private int _accountId; private int _accountId;
private int _status; private int _status;
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
_accountId = readD(); _accountId = packet.readD();
_status = readC(); _status = packet.readC();
return true; return true;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
getClient().sendPacket(new PIAgreementAck(_accountId, _status)); client.sendPacket(new PIAgreementAck(_accountId, _status));
} }
} }

View File

@@ -17,31 +17,34 @@
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.PIAgreementCheck; import com.l2jmobius.loginserver.network.serverpackets.PIAgreementCheck;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class RequestPIAgreementCheck extends L2LoginClientPacket public class RequestPIAgreementCheck implements IIncomingPacket<L2LoginClient>
{ {
private int _accountId; private int _accountId;
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
_accountId = readD(); _accountId = packet.readD();
final byte[] padding0 = new byte[3]; byte[] padding0 = new byte[3];
final byte[] checksum = new byte[4]; byte[] checksum = new byte[4];
final byte[] padding1 = new byte[12]; byte[] padding1 = new byte[12];
readB(padding0); packet.readB(padding0, 0, padding0.length);
readB(checksum); packet.readB(checksum, 0, checksum.length);
readB(padding1); packet.readB(padding1, 0, padding1.length);
return true; return true;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
getClient().sendPacket(new PIAgreementCheck(_accountId, Config.SHOW_PI_AGREEMENT ? 0x01 : 0x00)); client.sendPacket(new PIAgreementCheck(_accountId, Config.SHOW_PI_AGREEMENT ? 0x01 : 0x00));
} }
} }

View File

@@ -16,6 +16,9 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.ServerList; import com.l2jmobius.loginserver.network.serverpackets.ServerList;
@@ -27,58 +30,35 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
* c: ? * c: ?
* </pre> * </pre>
*/ */
public class RequestServerList extends L2LoginClientPacket public class RequestServerList implements IIncomingPacket<L2LoginClient>
{ {
private int _skey1; private int _skey1;
private int _skey2; private int _skey2;
@SuppressWarnings("unused")
private int _data3; private int _data3;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getData3()
{
return _data3;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 8) if (packet.getReadableBytes() >= 8)
{ {
_skey1 = readD(); // loginOk 1 _skey1 = packet.readD(); // loginOk 1
_skey2 = readD(); // loginOk 2 _skey2 = packet.readD(); // loginOk 2
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
if (getClient().getSessionKey().checkLoginPair(_skey1, _skey2)) if (client.getSessionKey().checkLoginPair(_skey1, _skey2))
{ {
getClient().sendPacket(new ServerList(getClient())); client.sendPacket(new ServerList(client));
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -17,8 +17,11 @@
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayOk; import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
@@ -31,70 +34,46 @@ import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
* c: server ID * c: server ID
* </pre> * </pre>
*/ */
public class RequestServerLogin extends L2LoginClientPacket public class RequestServerLogin implements IIncomingPacket<L2LoginClient>
{ {
private int _skey1; private int _skey1;
private int _skey2; private int _skey2;
private int _serverId; private int _serverId;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getServerID()
{
return _serverId;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 9) if (packet.getReadableBytes() >= 9)
{ {
_skey1 = readD(); _skey1 = packet.readD();
_skey2 = readD(); _skey2 = packet.readD();
_serverId = readC(); _serverId = packet.readC();
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
final SessionKey sk = getClient().getSessionKey(); final SessionKey sk = client.getSessionKey();
// if we didnt showed the license we cant check these values // if we didnt showed the license we cant check these values
if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2))
{ {
if (LoginController.getInstance().isLoginPossible(getClient(), _serverId)) if (LoginController.getInstance().isLoginPossible(client, _serverId))
{ {
getClient().setJoinedGS(true); client.setJoinedGS(true);
getClient().sendPacket(new PlayOk(sk)); client.sendPacket(new PlayOk(sk));
} }
else else
{ {
getClient().close(PlayFailReason.REASON_SERVER_OVERLOADED); client.close(PlayFailReason.REASON_SERVER_OVERLOADED);
} }
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -1,35 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class AbstractPacket<T extends MMOClient<?>>
{
protected ByteBuffer _buf;
T _client;
public final T getClient()
{
return _client;
}
}

View File

@@ -1,28 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public interface IPacketHandler<T extends MMOClient<?>>
{
ReceivablePacket<T> handlePacket(ByteBuffer buf, T client);
}

View File

@@ -1,46 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class MMOClient<T extends MMOConnection<?>>
{
private final T _con;
public MMOClient(T con)
{
_con = con;
}
public T getConnection()
{
return _con;
}
public abstract boolean decrypt(ByteBuffer buf, int size);
public abstract boolean encrypt(ByteBuffer buf, int size);
protected abstract void onDisconnection();
protected abstract void onForcedDisconnection();
}

View File

@@ -1,283 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.WritableByteChannel;
/**
* @author KenM
* @param <T>
*/
public class MMOConnection<T extends MMOClient<?>>
{
private final SelectorThread<T> _selectorThread;
private final Socket _socket;
private final InetAddress _address;
private final ReadableByteChannel _readableByteChannel;
private final WritableByteChannel _writableByteChannel;
private final int _port;
private final NioNetStackList<SendablePacket<T>> _sendQueue;
private final SelectionKey _selectionKey;
private ByteBuffer _readBuffer;
private ByteBuffer _primaryWriteBuffer;
private ByteBuffer _secondaryWriteBuffer;
private volatile boolean _pendingClose;
private T _client;
public MMOConnection(SelectorThread<T> selectorThread, Socket socket, SelectionKey key, boolean tcpNoDelay)
{
_selectorThread = selectorThread;
_socket = socket;
_address = socket.getInetAddress();
_readableByteChannel = socket.getChannel();
_writableByteChannel = socket.getChannel();
_port = socket.getPort();
_selectionKey = key;
_sendQueue = new NioNetStackList<>();
try
{
_socket.setTcpNoDelay(tcpNoDelay);
}
catch (SocketException e)
{
e.printStackTrace();
}
}
final void setClient(T client)
{
_client = client;
}
public final T getClient()
{
return _client;
}
public final void sendPacket(SendablePacket<T> sp)
{
sp._client = _client;
if (_pendingClose)
{
return;
}
synchronized (getSendQueue())
{
_sendQueue.addLast(sp);
}
if (!_sendQueue.isEmpty())
{
try
{
_selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE);
}
catch (CancelledKeyException e)
{
// ignore
}
}
}
final SelectionKey getSelectionKey()
{
return _selectionKey;
}
public final InetAddress getInetAddress()
{
return _address;
}
public final int getPort()
{
return _port;
}
final void close() throws IOException
{
_socket.close();
}
final int read(ByteBuffer buf) throws IOException
{
return _readableByteChannel.read(buf);
}
final int write(ByteBuffer buf) throws IOException
{
return _writableByteChannel.write(buf);
}
final void createWriteBuffer(ByteBuffer buf)
{
if (_primaryWriteBuffer == null)
{
_primaryWriteBuffer = _selectorThread.getPooledBuffer();
_primaryWriteBuffer.put(buf);
}
else
{
final ByteBuffer temp = _selectorThread.getPooledBuffer();
temp.put(buf);
final int remaining = temp.remaining();
_primaryWriteBuffer.flip();
final int limit = _primaryWriteBuffer.limit();
if (remaining >= _primaryWriteBuffer.remaining())
{
temp.put(_primaryWriteBuffer);
_selectorThread.recycleBuffer(_primaryWriteBuffer);
}
else
{
_primaryWriteBuffer.limit(remaining);
temp.put(_primaryWriteBuffer);
_primaryWriteBuffer.limit(limit);
_primaryWriteBuffer.compact();
_secondaryWriteBuffer = _primaryWriteBuffer;
}
_primaryWriteBuffer = temp;
}
}
final boolean hasPendingWriteBuffer()
{
return _primaryWriteBuffer != null;
}
final void movePendingWriteBufferTo(ByteBuffer dest)
{
_primaryWriteBuffer.flip();
dest.put(_primaryWriteBuffer);
_selectorThread.recycleBuffer(_primaryWriteBuffer);
_primaryWriteBuffer = _secondaryWriteBuffer;
_secondaryWriteBuffer = null;
}
final void setReadBuffer(ByteBuffer buf)
{
_readBuffer = buf;
}
final ByteBuffer getReadBuffer()
{
return _readBuffer;
}
public final boolean isClosed()
{
return _pendingClose;
}
final NioNetStackList<SendablePacket<T>> getSendQueue()
{
return _sendQueue;
}
/*
* final SendablePacket<T> getClosePacket() { return _closePacket; }
*/
@SuppressWarnings("unchecked")
public final void close(SendablePacket<T> sp)
{
close(new SendablePacket[]
{
sp
});
}
public final void close(SendablePacket<T>[] closeList)
{
if (_pendingClose)
{
return;
}
synchronized (getSendQueue())
{
if (!_pendingClose)
{
_pendingClose = true;
_sendQueue.clear();
for (SendablePacket<T> sp : closeList)
{
_sendQueue.addLast(sp);
}
}
}
try
{
_selectionKey.interestOps(_selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
}
catch (CancelledKeyException e)
{
// ignore
}
// _closePacket = sp;
_selectorThread.closeConnection(this);
}
final void releaseBuffers()
{
if (_primaryWriteBuffer != null)
{
_selectorThread.recycleBuffer(_primaryWriteBuffer);
_primaryWriteBuffer = null;
if (_secondaryWriteBuffer != null)
{
_selectorThread.recycleBuffer(_secondaryWriteBuffer);
_secondaryWriteBuffer = null;
}
}
if (_readBuffer != null)
{
_selectorThread.recycleBuffer(_readBuffer);
_readBuffer = null;
}
}
}

View File

@@ -1,101 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author Forsaiken
* @param <E>
*/
public final class NioNetStackList<E>
{
private final NioNetStackNode _start = new NioNetStackNode();
private final NioNetStackNodeBuf _buf = new NioNetStackNodeBuf();
private NioNetStackNode _end = new NioNetStackNode();
public NioNetStackList()
{
clear();
}
public final void addLast(E elem)
{
final NioNetStackNode newEndNode = _buf.removeFirst();
_end._value = elem;
_end._next = newEndNode;
_end = newEndNode;
}
public final E removeFirst()
{
final NioNetStackNode old = _start._next;
final E value = old._value;
_start._next = old._next;
_buf.addLast(old);
return value;
}
public final boolean isEmpty()
{
return _start._next == _end;
}
public final void clear()
{
_start._next = _end;
}
protected final class NioNetStackNode
{
protected NioNetStackNode _next;
protected E _value;
}
private final class NioNetStackNodeBuf
{
private final NioNetStackNode _start = new NioNetStackNode();
private NioNetStackNode _end = new NioNetStackNode();
NioNetStackNodeBuf()
{
_start._next = _end;
}
final void addLast(NioNetStackNode node)
{
node._next = null;
node._value = null;
_end._next = node;
_end = node;
}
final NioNetStackNode removeFirst()
{
if (_start._next == _end)
{
return new NioNetStackNode();
}
final NioNetStackNode old = _start._next;
_start._next = old._next;
return old;
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class ReceivablePacket<T extends MMOClient<?>>extends AbstractPacket<T> implements Runnable
{
NioNetStringBuffer _sbuf;
protected ReceivablePacket()
{
}
protected abstract boolean read();
@Override
public abstract void run();
/**
* Reads <B>byte[]</B> from the buffer. <BR>
* Reads as many bytes as the length of the array.
* @param dst : the byte array which will be filled with the data.
*/
protected final void readB(byte[] dst)
{
_buf.get(dst);
}
/**
* Reads <B>byte[]</B> from the buffer. <BR>
* Reads as many bytes as the given length (len). Starts to fill the byte array from the given offset to <B>offset</B> + <B>len</B>.
* @param dst : the byte array which will be filled with the data.
* @param offset : starts to fill the byte array from the given offset.
* @param len : the given length of bytes to be read.
*/
protected final void readB(byte[] dst, int offset, int len)
{
_buf.get(dst, offset, len);
}
/**
* Reads <B>byte</B> from the buffer. <BR>
* 8bit integer (00)
* @return
*/
protected final int readC()
{
return _buf.get() & 0xFF;
}
/**
* Reads <B>short</B> from the buffer. <BR>
* 16bit integer (00 00)
* @return
*/
protected final int readH()
{
return _buf.getShort() & 0xFFFF;
}
/**
* Reads <B>int</B> from the buffer. <BR>
* 32bit integer (00 00 00 00)
* @return
*/
protected final int readD()
{
return _buf.getInt();
}
/**
* Reads <B>long</B> from the buffer. <BR>
* 64bit integer (00 00 00 00 00 00 00 00)
* @return
*/
protected final long readQ()
{
return _buf.getLong();
}
/**
* Reads <B>double</B> from the buffer. <BR>
* 64bit double precision float (00 00 00 00 00 00 00 00)
* @return
*/
protected final double readF()
{
return _buf.getDouble();
}
/**
* Reads <B>String</B> from the buffer.
* @return
*/
protected final String readS()
{
_sbuf.clear();
char ch;
while ((ch = _buf.getChar()) != 0)
{
_sbuf.append(ch);
}
return _sbuf.toString();
}
/**
* packet forge purpose
* @param data
* @param client
* @param sBuffer
*/
public void setBuffers(ByteBuffer data, T client, NioNetStringBuffer sBuffer)
{
_buf = data;
_client = client;
_sbuf = sBuffer;
}
}

View File

@@ -1,63 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author KenM
*/
public final class SelectorConfig
{
public int READ_BUFFER_SIZE = 64 * 1024;
public int WRITE_BUFFER_SIZE = 64 * 1024;
public int HELPER_BUFFER_COUNT = 20;
public int HELPER_BUFFER_SIZE = 64 * 1024;
/**
* Server will try to send MAX_SEND_PER_PASS packets per socket write call<br>
* however it may send less if the write buffer was filled before achieving this value.
*/
public int MAX_SEND_PER_PASS = 10;
/**
* Server will try to read MAX_READ_PER_PASS packets per socket read call<br>
* however it may read less if the read buffer was empty before achieving this value.
*/
public int MAX_READ_PER_PASS = 10;
/**
* Defines how much time (in milis) should the selector sleep, an higher value increases throughput but also increases latency(to a max of the sleep value itself).<BR>
* Also an extremely high value(usually > 100) will decrease throughput due to the server not doing enough sends per second (depends on max sends per pass).<BR>
* <BR>
* Recommended values:<BR>
* 1 for minimal latency.<BR>
* 10-30 for an latency/troughput trade-off based on your needs.<BR>
*/
public int SLEEP_TIME = 10;
/**
* Used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm.<BR>
* <BR>
* Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase
* in bandwidth consumption. The Nagle's algorithm is described in RFC 896.<BR>
* <BR>
* Summary, data will be sent earlier, thus lowering the ping, at the cost of a small increase in bandwidth consumption.
*/
public boolean TCP_NODELAY = true;
}

View File

@@ -1,714 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Parts of design based on network core from WoodenGil
* @param <T>
* @author KenM
*/
public final class SelectorThread<T extends MMOClient<?>>extends Thread
{
// default BYTE_ORDER
private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;
// default HEADER_SIZE
private static final int HEADER_SIZE = 2;
// Selector
private final Selector _selector;
// Implementations
private final IPacketHandler<T> _packetHandler;
private final IMMOExecutor<T> _executor;
private final IClientFactory<T> _clientFactory;
private final IAcceptFilter _acceptFilter;
// Configurations
private final int HELPER_BUFFER_SIZE;
private final int HELPER_BUFFER_COUNT;
private final int MAX_SEND_PER_PASS;
private final int MAX_READ_PER_PASS;
private final long SLEEP_TIME;
public boolean TCP_NODELAY;
// Main Buffers
private final ByteBuffer DIRECT_WRITE_BUFFER;
private final ByteBuffer WRITE_BUFFER;
private final ByteBuffer READ_BUFFER;
// String Buffer
private final NioNetStringBuffer STRING_BUFFER;
// ByteBuffers General Purpose Pool
private final LinkedList<ByteBuffer> _bufferPool;
// Pending Close
private final NioNetStackList<MMOConnection<T>> _pendingClose;
private boolean _shutdown;
public SelectorThread(SelectorConfig sc, IMMOExecutor<T> executor, IPacketHandler<T> packetHandler, IClientFactory<T> clientFactory, IAcceptFilter acceptFilter) throws IOException
{
super.setName("SelectorThread-" + super.getId());
HELPER_BUFFER_SIZE = sc.HELPER_BUFFER_SIZE;
HELPER_BUFFER_COUNT = sc.HELPER_BUFFER_COUNT;
MAX_SEND_PER_PASS = sc.MAX_SEND_PER_PASS;
MAX_READ_PER_PASS = sc.MAX_READ_PER_PASS;
SLEEP_TIME = sc.SLEEP_TIME;
TCP_NODELAY = sc.TCP_NODELAY;
DIRECT_WRITE_BUFFER = ByteBuffer.allocateDirect(sc.WRITE_BUFFER_SIZE).order(BYTE_ORDER);
WRITE_BUFFER = ByteBuffer.wrap(new byte[sc.WRITE_BUFFER_SIZE]).order(BYTE_ORDER);
READ_BUFFER = ByteBuffer.wrap(new byte[sc.READ_BUFFER_SIZE]).order(BYTE_ORDER);
STRING_BUFFER = new NioNetStringBuffer(64 * 1024);
_pendingClose = new NioNetStackList<>();
_bufferPool = new LinkedList<>();
for (int i = 0; i < HELPER_BUFFER_COUNT; i++)
{
_bufferPool.addLast(ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER));
}
_acceptFilter = acceptFilter;
_packetHandler = packetHandler;
_clientFactory = clientFactory;
_executor = executor;
_selector = Selector.open();
}
public final void openServerSocket(InetAddress address, int tcpPort) throws IOException
{
final ServerSocketChannel selectable = ServerSocketChannel.open();
selectable.configureBlocking(false);
final ServerSocket ss = selectable.socket();
if (address != null)
{
ss.bind(new InetSocketAddress(address, tcpPort));
}
else
{
ss.bind(new InetSocketAddress(tcpPort));
}
selectable.register(_selector, SelectionKey.OP_ACCEPT);
}
final ByteBuffer getPooledBuffer()
{
if (_bufferPool.isEmpty())
{
return ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER);
}
return _bufferPool.removeFirst();
}
final void recycleBuffer(ByteBuffer buf)
{
if (_bufferPool.size() < HELPER_BUFFER_COUNT)
{
buf.clear();
_bufferPool.addLast(buf);
}
}
@SuppressWarnings("unchecked")
@Override
public final void run()
{
int selectedKeysCount = 0;
SelectionKey key;
MMOConnection<T> con;
Iterator<SelectionKey> selectedKeys;
while (!_shutdown)
{
try
{
selectedKeysCount = _selector.selectNow();
}
catch (IOException e)
{
e.printStackTrace();
}
if (selectedKeysCount > 0)
{
selectedKeys = _selector.selectedKeys().iterator();
while (selectedKeys.hasNext())
{
key = selectedKeys.next();
selectedKeys.remove();
con = (MMOConnection<T>) key.attachment();
switch (key.readyOps())
{
case SelectionKey.OP_CONNECT:
{
finishConnection(key, con);
break;
}
case SelectionKey.OP_ACCEPT:
{
acceptConnection(key, con);
break;
}
case SelectionKey.OP_READ:
{
readPacket(key, con);
break;
}
case SelectionKey.OP_WRITE:
{
writePacket(key, con);
break;
}
case SelectionKey.OP_READ | SelectionKey.OP_WRITE:
{
writePacket(key, con);
if (key.isValid())
{
readPacket(key, con);
}
break;
}
}
}
}
synchronized (_pendingClose)
{
while (!_pendingClose.isEmpty())
{
try
{
con = _pendingClose.removeFirst();
writeClosePacket(con);
closeConnectionImpl(con.getSelectionKey(), con);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
try
{
Thread.sleep(SLEEP_TIME);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
closeSelectorThread();
}
private final void finishConnection(SelectionKey key, MMOConnection<T> con)
{
try
{
((SocketChannel) key.channel()).finishConnect();
}
catch (IOException e)
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
}
// key might have been invalidated on finishConnect()
if (key.isValid())
{
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
}
}
private final void acceptConnection(SelectionKey key, MMOConnection<T> con)
{
final ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc;
try
{
while ((sc = ssc.accept()) != null)
{
if ((_acceptFilter == null) || _acceptFilter.accept(sc))
{
sc.configureBlocking(false);
final SelectionKey clientKey = sc.register(_selector, SelectionKey.OP_READ);
con = new MMOConnection<>(this, sc.socket(), clientKey, TCP_NODELAY);
con.setClient(_clientFactory.create(con));
clientKey.attach(con);
}
else
{
sc.socket().close();
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private final void readPacket(SelectionKey key, MMOConnection<T> con)
{
if (con.isClosed())
{
return;
}
ByteBuffer buf = con.getReadBuffer();
if (buf == null)
{
buf = READ_BUFFER;
}
// if we try to to do a read with no space in the buffer it will read 0 bytes going into infinite loop
if (buf.position() == buf.limit())
{
System.exit(0);
}
int result = -2;
try
{
result = con.read(buf);
}
catch (IOException e)
{
// error handling goes bellow
}
if (result > 0)
{
buf.flip();
final T client = con.getClient();
for (int i = 0; i < MAX_READ_PER_PASS; i++)
{
if (!tryReadPacket(key, client, buf, con))
{
return;
}
}
// only reachable if MAX_READ_PER_PASS has been reached
// check if there are some more bytes in buffer
// and allocate/compact to prevent content lose.
if (buf.remaining() > 0)
{
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
// move the first byte to the beginning :)
buf.compact();
}
}
}
else
{
switch (result)
{
case 0:
case -1:
{
closeConnectionImpl(key, con);
break;
}
case -2:
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
break;
}
}
}
}
private final boolean tryReadPacket(SelectionKey key, T client, ByteBuffer buf, MMOConnection<T> con)
{
switch (buf.remaining())
{
case 0:
{
// buffer is full nothing to read
return false;
}
case 1:
{
// we don`t have enough data for header so we need to read
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
// move the first byte to the beginning :)
buf.compact();
}
return false;
}
default:
{
// data size excluding header size :>
final int dataPending = (buf.getShort() & 0xFFFF) - HEADER_SIZE;
// do we got enough bytes for the packet?
if (dataPending <= buf.remaining())
{
// avoid parsing dummy packets (packets without body)
if (dataPending > 0)
{
final int pos = buf.position();
parseClientPacket(pos, buf, dataPending, client);
buf.position(pos + dataPending);
}
if (buf.hasRemaining())
{
return true;
}
if (buf != READ_BUFFER)
{
con.setReadBuffer(null);
recycleBuffer(buf);
}
else
{
READ_BUFFER.clear();
}
return false;
}
// we don`t have enough bytes for the dataPacket so we need to read
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
// move it`s position
buf.position(buf.position() - HEADER_SIZE);
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
buf.compact();
}
return false;
}
}
}
private final void allocateReadBuffer(MMOConnection<T> con)
{
con.setReadBuffer(getPooledBuffer().put(READ_BUFFER));
READ_BUFFER.clear();
}
private final void parseClientPacket(int pos, ByteBuffer buf, int dataSize, T client)
{
if (!client.decrypt(buf, dataSize) || !buf.hasRemaining())
{
return;
}
// apply limit
final int limit = buf.limit();
buf.limit(pos + dataSize);
final ReceivablePacket<T> cp = _packetHandler.handlePacket(buf, client);
if (cp != null)
{
cp._buf = buf;
cp._sbuf = STRING_BUFFER;
cp._client = client;
if (cp.read())
{
_executor.execute(cp);
}
cp._buf = null;
cp._sbuf = null;
}
buf.limit(limit);
}
private final void writeClosePacket(MMOConnection<T> con)
{
SendablePacket<T> sp;
synchronized (con.getSendQueue())
{
if (con.getSendQueue().isEmpty())
{
return;
}
while ((sp = con.getSendQueue().removeFirst()) != null)
{
WRITE_BUFFER.clear();
putPacketIntoWriteBuffer(con.getClient(), sp);
WRITE_BUFFER.flip();
try
{
con.write(WRITE_BUFFER);
}
catch (IOException e)
{
// error handling goes on the if bellow
}
}
}
}
protected final void writePacket(SelectionKey key, MMOConnection<T> con)
{
if (!prepareWriteBuffer(con))
{
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
return;
}
DIRECT_WRITE_BUFFER.flip();
final int size = DIRECT_WRITE_BUFFER.remaining();
int result = -1;
try
{
result = con.write(DIRECT_WRITE_BUFFER);
}
catch (IOException e)
{
// error handling goes on the if bellow
}
// check if no error happened
if (result >= 0)
{
// check if we written everything
if (result == size)
{
// complete write
synchronized (con.getSendQueue())
{
if (con.getSendQueue().isEmpty() && !con.hasPendingWriteBuffer())
{
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
}
}
}
else
{
// incomplete write
con.createWriteBuffer(DIRECT_WRITE_BUFFER);
}
}
else
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
}
}
private final boolean prepareWriteBuffer(MMOConnection<T> con)
{
boolean hasPending = false;
DIRECT_WRITE_BUFFER.clear();
// if there is pending content add it
if (con.hasPendingWriteBuffer())
{
con.movePendingWriteBufferTo(DIRECT_WRITE_BUFFER);
hasPending = true;
}
if ((DIRECT_WRITE_BUFFER.remaining() > 1) && !con.hasPendingWriteBuffer())
{
final NioNetStackList<SendablePacket<T>> sendQueue = con.getSendQueue();
final T client = con.getClient();
SendablePacket<T> sp;
for (int i = 0; i < MAX_SEND_PER_PASS; i++)
{
synchronized (con.getSendQueue())
{
if (sendQueue.isEmpty())
{
sp = null;
}
else
{
sp = sendQueue.removeFirst();
}
}
if (sp == null)
{
break;
}
hasPending = true;
// put into WriteBuffer
putPacketIntoWriteBuffer(client, sp);
WRITE_BUFFER.flip();
if (DIRECT_WRITE_BUFFER.remaining() < WRITE_BUFFER.limit())
{
con.createWriteBuffer(WRITE_BUFFER);
break;
}
DIRECT_WRITE_BUFFER.put(WRITE_BUFFER);
}
}
return hasPending;
}
private final void putPacketIntoWriteBuffer(T client, SendablePacket<T> sp)
{
WRITE_BUFFER.clear();
// reserve space for the size
final int headerPos = WRITE_BUFFER.position();
final int dataPos = headerPos + HEADER_SIZE;
WRITE_BUFFER.position(dataPos);
// set the write buffer
sp._buf = WRITE_BUFFER;
// set the client.
sp._client = client;
// write content to buffer
sp.write();
// delete the write buffer
sp._buf = null;
// size (inclusive header)
int dataSize = WRITE_BUFFER.position() - dataPos;
WRITE_BUFFER.position(dataPos);
client.encrypt(WRITE_BUFFER, dataSize);
// recalculate size after encryption
dataSize = WRITE_BUFFER.position() - dataPos;
WRITE_BUFFER.position(headerPos);
// write header
WRITE_BUFFER.putShort((short) (dataSize + HEADER_SIZE));
WRITE_BUFFER.position(dataPos + dataSize);
}
final void closeConnection(MMOConnection<T> con)
{
synchronized (_pendingClose)
{
_pendingClose.addLast(con);
}
}
private final void closeConnectionImpl(SelectionKey key, MMOConnection<T> con)
{
try
{
// notify connection
con.getClient().onDisconnection();
}
finally
{
try
{
// close socket and the SocketChannel
con.close();
}
catch (IOException e)
{
// ignore, we are closing anyway
}
finally
{
con.releaseBuffers();
// clear attachment
key.attach(null);
// cancel key
key.cancel();
}
}
}
public final void shutdown()
{
_shutdown = true;
}
protected void closeSelectorThread()
{
for (SelectionKey key : _selector.keys())
{
try
{
key.channel().close();
}
catch (IOException e)
{
// ignore
}
}
try
{
_selector.close();
}
catch (IOException e)
{
// Ignore
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author KenM
* @param <T>
*/
public abstract class SendablePacket<T extends MMOClient<?>>extends AbstractPacket<T>
{
protected final void putInt(int value)
{
_buf.putInt(value);
}
protected final void putDouble(double value)
{
_buf.putDouble(value);
}
protected final void putFloat(float value)
{
_buf.putFloat(value);
}
/**
* Write <B>byte</B> to the buffer. <BR>
* 8bit integer (00)
* @param data
*/
protected final void writeC(boolean data)
{
_buf.put((byte) (data ? 0x01 : 0x00));
}
/**
* Write <B>byte</B> to the buffer. <BR>
* 8bit integer (00)
* @param data
*/
protected final void writeC(int data)
{
_buf.put((byte) data);
}
/**
* Write <B>double</B> to the buffer. <BR>
* 64bit double precision float (00 00 00 00 00 00 00 00)
* @param value
*/
protected final void writeF(double value)
{
_buf.putDouble(value);
}
/**
* Write <B>short</B> to the buffer. <BR>
* 16bit integer (00 00)
* @param value
*/
protected final void writeH(int value)
{
_buf.putShort((short) value);
}
/**
* Write <B>int</B> to the buffer. <BR>
* 32bit integer (00 00 00 00)
* @param value
*/
protected final void writeD(int value)
{
_buf.putInt(value);
}
/**
* Write <B>int</B> to the buffer. <BR>
* 32bit integer (00 00 00 00)
* @param value
*/
protected final void writeD(boolean value)
{
_buf.putInt(value ? 0x01 : 0x00);
}
/**
* Write <B>long</B> to the buffer. <BR>
* 64bit integer (00 00 00 00 00 00 00 00)
* @param value
*/
protected final void writeQ(long value)
{
_buf.putLong(value);
}
/**
* Write <B>byte[]</B> to the buffer. <BR>
* 8bit integer array (00 ...)
* @param data
*/
protected final void writeB(byte[] data)
{
_buf.put(data);
}
/**
* Write <B>String</B> to the buffer.
* @param text
*/
protected final void writeS(String text)
{
if (text != null)
{
final int len = text.length();
for (int i = 0; i < len; i++)
{
_buf.putChar(text.charAt(i));
}
}
_buf.putChar('\000');
}
protected abstract void write();
}

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author KenM * @author KenM
*/ */
public final class AccountKicked extends L2LoginServerPacket public final class AccountKicked implements IOutgoingPacket
{ {
public enum AccountKickedReason public enum AccountKickedReason
{ {
@@ -52,9 +56,11 @@ public final class AccountKicked extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x02); OutgoingPackets.ACCOUNT_KICKED.writeId(packet);
writeD(_reason.getCode()); packet.writeD(_reason.getCode());
return true;
} }
} }

View File

@@ -16,16 +16,15 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import java.util.logging.Logger; import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* Fromat: d d: response * Fromat: d d: response
*/ */
public final class GGAuth extends L2LoginServerPacket public final class GGAuth implements IOutgoingPacket
{ {
static final Logger _log = Logger.getLogger(GGAuth.class.getName());
public static final int SKIP_GG_AUTH_REQUEST = 0x0b;
private final int _response; private final int _response;
public GGAuth(int response) public GGAuth(int response)
@@ -34,13 +33,14 @@ public final class GGAuth extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x0b); OutgoingPackets.GG_AUTH.writeId(packet);
writeD(_response); packet.writeD(_response);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
return true;
} }
} }

View File

@@ -16,7 +16,9 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* <pre> * <pre>
@@ -32,18 +34,13 @@ import com.l2jmobius.loginserver.network.L2LoginClient;
* s: blowfish key * s: blowfish key
* </pre> * </pre>
*/ */
public final class Init extends L2LoginServerPacket public final class Init implements IOutgoingPacket
{ {
private final int _sessionId; private final int _sessionId;
private final byte[] _publicKey; private final byte[] _publicKey;
private final byte[] _blowfishKey; private final byte[] _blowfishKey;
public Init(L2LoginClient client)
{
this(client.getScrambledModulus(), client.getBlowfishKey(), client.getSessionId());
}
public Init(byte[] publickey, byte[] blowfishkey, int sessionId) public Init(byte[] publickey, byte[] blowfishkey, int sessionId)
{ {
_sessionId = sessionId; _sessionId = sessionId;
@@ -52,22 +49,24 @@ public final class Init extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x00); // init packet id OutgoingPackets.INIT.writeId(packet);
writeD(_sessionId); // session id packet.writeD(_sessionId); // session id
writeD(0x0000c621); // protocol revision packet.writeD(0x0000c621); // protocol revision
writeB(_publicKey); // RSA Public Key packet.writeB(_publicKey); // RSA Public Key
// unk GG related? // unk GG related?
writeD(0x29DD954E); packet.writeD(0x29DD954E);
writeD(0x77C39CFC); packet.writeD(0x77C39CFC);
writeD(0x97ADB620); packet.writeD(0x97ADB620);
writeD(0x07BDE0F7); packet.writeD(0x07BDE0F7);
writeB(_blowfishKey); // BlowFish key packet.writeB(_blowfishKey); // BlowFish key
writeC(0x00); // null termination ;) packet.writeC(0x00); // null termination ;)
return true;
} }
} }

View File

@@ -1,27 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.SendablePacket;
/**
* @author KenM
*/
public abstract class L2LoginServerPacket extends SendablePacket<L2LoginClient>
{
}

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* Fromat: d d: the failure reason * Fromat: d d: the failure reason
*/ */
public final class LoginFail extends L2LoginServerPacket public final class LoginFail implements IOutgoingPacket
{ {
public enum LoginFailReason public enum LoginFailReason
{ {
@@ -84,9 +88,10 @@ public final class LoginFail extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x01); OutgoingPackets.LOGIN_FAIL.writeId(packet);
writeC(_reason.getCode()); packet.writeC(_reason.getCode());
return true;
} }
} }

View File

@@ -16,7 +16,10 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* <pre> * <pre>
@@ -31,7 +34,7 @@ import com.l2jmobius.loginserver.SessionKey;
* b: 16 bytes - unknown * b: 16 bytes - unknown
* </pre> * </pre>
*/ */
public final class LoginOk extends L2LoginServerPacket public final class LoginOk implements IOutgoingPacket
{ {
private final int _loginOk1, _loginOk2; private final int _loginOk1, _loginOk2;
@@ -42,17 +45,18 @@ public final class LoginOk extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x03); OutgoingPackets.LOGIN_OK.writeId(packet);
writeD(_loginOk1); packet.writeD(_loginOk1);
writeD(_loginOk2); packet.writeD(_loginOk2);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x000003ea); packet.writeD(0x000003ea);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeB(new byte[16]); packet.writeB(new byte[16]);
return true;
} }
} }

View File

@@ -16,14 +16,19 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class LoginOtpFail extends L2LoginServerPacket public class LoginOtpFail implements IOutgoingPacket
{ {
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x0D); OutgoingPackets.LOGIN_OPT_FAIL.writeId(packet);
return true;
} }
} }

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class PIAgreementAck extends L2LoginServerPacket public class PIAgreementAck implements IOutgoingPacket
{ {
private final int _accountId; private final int _accountId;
private final int _status; private final int _status;
@@ -31,10 +35,11 @@ public class PIAgreementAck extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x12); OutgoingPackets.PI_AGREEMENT_ACK.writeId(packet);
writeD(_accountId); packet.writeD(_accountId);
writeC(_status); packet.writeC(_status);
return true;
} }
} }

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class PIAgreementCheck extends L2LoginServerPacket public class PIAgreementCheck implements IOutgoingPacket
{ {
private final int _accountId; private final int _accountId;
private final int _status; private final int _status;
@@ -31,10 +35,11 @@ public class PIAgreementCheck extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x11); OutgoingPackets.PI_AGREEMENT_CHECK.writeId(packet);
writeD(_accountId); packet.writeD(_accountId);
writeC(_status); packet.writeC(_status);
return true;
} }
} }

View File

@@ -16,11 +16,15 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* This class ... * This class ...
* @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:11 $ * @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:11 $
*/ */
public final class PlayFail extends L2LoginServerPacket public final class PlayFail implements IOutgoingPacket
{ {
public enum PlayFailReason public enum PlayFailReason
{ {
@@ -85,9 +89,10 @@ public final class PlayFail extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x06); OutgoingPackets.PLAY_FAIL.writeId(packet);
writeC(_reason.getCode()); packet.writeC(_reason.getCode());
return true;
} }
} }

View File

@@ -16,12 +16,12 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** public final class PlayOk implements IOutgoingPacket
*
*/
public final class PlayOk extends L2LoginServerPacket
{ {
private final int _playOk1, _playOk2; private final int _playOk1, _playOk2;
@@ -32,10 +32,11 @@ public final class PlayOk extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x07); OutgoingPackets.PLAY_OK.writeId(packet);
writeD(_playOk1); packet.writeD(_playOk1);
writeD(_playOk2); packet.writeD(_playOk2);
return true;
} }
} }

View File

@@ -23,9 +23,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.GameServerTable; import com.l2jmobius.loginserver.GameServerTable;
import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; import com.l2jmobius.loginserver.GameServerTable.GameServerInfo;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.OutgoingPackets;
import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus;
/** /**
@@ -56,7 +59,7 @@ import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus;
* is less than half the maximum. as Normal between half and 4/5<br> * is less than half the maximum. as Normal between half and 4/5<br>
* and Full when there's more than 4/5 of the maximum number of players. * and Full when there's more than 4/5 of the maximum number of players.
*/ */
public final class ServerList extends L2LoginServerPacket public final class ServerList implements IOutgoingPacket
{ {
protected static final Logger _log = Logger.getLogger(ServerList.class.getName()); protected static final Logger _log = Logger.getLogger(ServerList.class.getName());
@@ -83,7 +86,7 @@ public final class ServerList extends L2LoginServerPacket
{ {
try try
{ {
_ip = InetAddress.getByName(gsi.getServerAddress(client.getConnection().getInetAddress())).getAddress(); _ip = InetAddress.getByName(gsi.getServerAddress(client.getConnectionAddress())).getAddress();
} }
catch (UnknownHostException e) catch (UnknownHostException e)
{ {
@@ -121,54 +124,56 @@ public final class ServerList extends L2LoginServerPacket
} }
@Override @Override
public void write() public boolean write(PacketWriter packet)
{ {
writeC(0x04); OutgoingPackets.SERVER_LIST.writeId(packet);
writeC(_servers.size()); packet.writeC(_servers.size());
writeC(_lastServer); packet.writeC(_lastServer);
for (ServerData server : _servers) for (ServerData server : _servers)
{ {
writeC(server._serverId); // server id packet.writeC(server._serverId); // server id
writeC(server._ip[0] & 0xff); packet.writeC(server._ip[0] & 0xff);
writeC(server._ip[1] & 0xff); packet.writeC(server._ip[1] & 0xff);
writeC(server._ip[2] & 0xff); packet.writeC(server._ip[2] & 0xff);
writeC(server._ip[3] & 0xff); packet.writeC(server._ip[3] & 0xff);
writeD(server._port); packet.writeD(server._port);
writeC(server._ageLimit); // Age Limit 0, 15, 18 packet.writeC(server._ageLimit); // Age Limit 0, 15, 18
writeC(server._pvp ? 0x01 : 0x00); packet.writeC(server._pvp ? 0x01 : 0x00);
writeH(server._currentPlayers); packet.writeH(server._currentPlayers);
writeH(server._maxPlayers); packet.writeH(server._maxPlayers);
writeC(server._status == ServerStatus.STATUS_DOWN ? 0x00 : 0x01); packet.writeC(server._status == ServerStatus.STATUS_DOWN ? 0x00 : 0x01);
writeD(server._serverType); // 1: Normal, 2: Relax, 4: Public Test, 8: No Label, 16: Character Creation Restricted, 32: Event, 64: Free packet.writeD(server._serverType); // 1: Normal, 2: Relax, 4: Public Test, 8: No Label, 16: Character Creation Restricted, 32: Event, 64: Free
writeC(server._brackets ? 0x01 : 0x00); packet.writeC(server._brackets ? 0x01 : 0x00);
} }
writeH(0x00); // unknown packet.writeH(0x00); // unknown
if (_charsOnServers != null) if (_charsOnServers != null)
{ {
writeC(_charsOnServers.size()); packet.writeC(_charsOnServers.size());
for (int servId : _charsOnServers.keySet()) for (int servId : _charsOnServers.keySet())
{ {
writeC(servId); packet.writeC(servId);
writeC(_charsOnServers.get(servId)); packet.writeC(_charsOnServers.get(servId));
if ((_charsToDelete == null) || !_charsToDelete.containsKey(servId)) if ((_charsToDelete == null) || !_charsToDelete.containsKey(servId))
{ {
writeC(0x00); packet.writeC(0x00);
} }
else else
{ {
writeC(_charsToDelete.get(servId).length); packet.writeC(_charsToDelete.get(servId).length);
for (long deleteTime : _charsToDelete.get(servId)) for (long deleteTime : _charsToDelete.get(servId))
{ {
writeD((int) ((deleteTime - System.currentTimeMillis()) / 1000)); packet.writeD((int) ((deleteTime - System.currentTimeMillis()) / 1000));
} }
} }
} }
} }
else else
{ {
writeC(0x00); packet.writeC(0x00);
} }
return true;
} }
} }

View File

@@ -24,13 +24,11 @@ import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.mmocore.IAcceptFilter;
/** /**
* IPv4 filter. * IPv4 filter.
* @author Forsaiken * @author Forsaiken
*/ */
public class IPv4Filter implements IAcceptFilter, Runnable public class IPv4Filter implements Runnable
{ {
protected final Logger _log = Logger.getLogger(getClass().getName()); protected final Logger _log = Logger.getLogger(getClass().getName());
@@ -66,7 +64,6 @@ public class IPv4Filter implements IAcceptFilter, Runnable
} }
} }
@Override
public boolean accept(SocketChannel sc) public boolean accept(SocketChannel sc)
{ {
final InetAddress addr = sc.socket().getInetAddress(); final InetAddress addr = sc.socket().getInetAddress();

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -12,11 +12,11 @@
# Networking # Networking
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Bind ip of the LoginServer, use * to bind on all available IPs # Bind ip of the LoginServer, use 0.0.0.0 to bind on all available IPs
# WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u> # WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u>
# WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u> # WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u>
# Default: * (0.0.0.0) # Default: 0.0.0.0
LoginserverHostname = * LoginserverHostname = 0.0.0.0
# Default: 2106 # Default: 2106
LoginserverPort = 2106 LoginserverPort = 2106

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -92,7 +92,6 @@ public final class Config
public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini"; public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
public static final String MMO_CONFIG_FILE = "./config/MMO.ini";
public static final String NPC_CONFIG_FILE = "./config/NPC.ini"; public static final String NPC_CONFIG_FILE = "./config/NPC.ini";
public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini"; public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini";
public static final String PVP_CONFIG_FILE = "./config/PVP.ini"; public static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -1777,15 +1776,6 @@ public final class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
// Load IdFactory config file (if exists) // Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE); final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
@@ -2868,7 +2858,7 @@ public final class Config
GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1"); GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1");
GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013); GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013);
LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "*"); LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "0.0.0.0");
PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106); PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106);
try try
@@ -2906,15 +2896,6 @@ public final class Config
NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700); NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700);
FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350); FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350);
MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50); MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
} }
else else
{ {

View File

@@ -16,14 +16,17 @@
*/ */
package com.l2jmobius.commons.util.crypt; package com.l2jmobius.commons.util.crypt;
import java.io.IOException; import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.ICrypt;
import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.commons.util.Rnd;
import io.netty.buffer.ByteBuf;
/** /**
* @author KenM * @author NosBit
*/ */
public class LoginCrypt public class LoginCrypt implements ICrypt
{ {
private static final byte[] STATIC_BLOWFISH_KEY = private static final byte[] STATIC_BLOWFISH_KEY =
{ {
@@ -45,82 +48,102 @@ public class LoginCrypt
(byte) 0x6c (byte) 0x6c
}; };
private static final NewCrypt _STATIC_CRYPT = new NewCrypt(STATIC_BLOWFISH_KEY); private static final BlowfishEngine STATIC_BLOWFISH_ENGINE = new BlowfishEngine();
private NewCrypt _crypt = null;
static
{
STATIC_BLOWFISH_ENGINE.init(STATIC_BLOWFISH_KEY);
}
private final BlowfishEngine _blowfishEngine = new BlowfishEngine();
private boolean _static = true; private boolean _static = true;
/** public LoginCrypt(SecretKey blowfishKey)
* Method to initialize the the blowfish cipher with dynamic key.
* @param key the blowfish key to initialize the dynamic blowfish cipher with
*/
public void setKey(byte[] key)
{ {
_crypt = new NewCrypt(key); _blowfishEngine.init(blowfishKey.getEncoded());
} }
/** /*
* Method to decrypt an incoming login client packet. * (non-Javadoc)
* @param raw array with encrypted data * @see com.l2jserver.commons.network.ICrypt#encrypt(io.netty.buffer.ByteBuf)
* @param offset offset where the encrypted data is located
* @param size number of bytes of encrypted data
* @return true when checksum could be verified, false otherwise
* @throws IOException the size is not multiple of blowfishs block size or the raw array can't hold size bytes starting at offset due to it's size
*/ */
public boolean decrypt(byte[] raw, int offset, int size) throws IOException @Override
public void encrypt(ByteBuf buf)
{ {
if ((size % 8) != 0) // Checksum & XOR Key or Checksum only
{ buf.writeZero(_static ? 16 : 12);
throw new IOException("size have to be multiple of 8");
}
if ((offset + size) > raw.length)
{
throw new IOException("raw array too short for size starting from offset");
}
_crypt.decrypt(raw, offset, size); // Padding
return NewCrypt.verifyChecksum(raw, offset, size); buf.writeZero(8 - (buf.readableBytes() % 8));
}
/**
* Method to encrypt an outgoing packet to login client.<br>
* Performs padding and resizing of data array.
* @param raw array with plain data
* @param offset offset where the plain data is located
* @param size number of bytes of plain data
* @return the new array size
* @throws IOException packet is too long to make padding and add verification data
*/
public int encrypt(byte[] raw, int offset, int size) throws IOException
{
// reserve checksum
size += 4;
if (_static) if (_static)
{ {
// reserve for XOR "key"
size += 4;
// padding
size += 8 - (size % 8);
if ((offset + size) > raw.length)
{
throw new IOException("packet too long");
}
NewCrypt.encXORPass(raw, offset, size, Rnd.nextInt());
_STATIC_CRYPT.crypt(raw, offset, size);
_static = false; _static = false;
int key = Rnd.nextInt();
buf.skipBytes(4); // The first 4 bytes are ignored
while (buf.readerIndex() < (buf.writerIndex() - 8))
{
int data = buf.readIntLE();
key += data;
data ^= key;
buf.setIntLE(buf.readerIndex() - 4, data);
}
buf.setIntLE(buf.readerIndex(), key);
buf.resetReaderIndex();
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
STATIC_BLOWFISH_ENGINE.encryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
}
} }
else else
{ {
// padding int checksum = 0;
size += 8 - (size % 8); while (buf.isReadable(8))
if ((offset + size) > raw.length)
{ {
throw new IOException("packet too long"); checksum ^= buf.readIntLE();
}
buf.setIntLE(buf.readerIndex(), checksum);
buf.resetReaderIndex();
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
_blowfishEngine.encryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
} }
NewCrypt.appendChecksum(raw, offset, size);
_crypt.crypt(raw, offset, size);
} }
return size; }
/*
* (non-Javadoc)
* @see com.l2jserver.commons.network.ICrypt#decrypt(io.netty.buffer.ByteBuf)
*/
@Override
public void decrypt(ByteBuf buf)
{
// Packet size must be multiple of 8
if ((buf.readableBytes() % 8) != 0)
{
buf.clear();
return;
}
final byte[] block = new byte[8];
while (buf.isReadable(8))
{
buf.readBytes(block);
_blowfishEngine.decryptBlock(block, 0);
buf.setBytes(buf.readerIndex() - block.length, block);
}
// TODO: verify checksum also dont forget!
} }
} }

View File

@@ -72,4 +72,9 @@ public class ScrambledKeyPair
return scrambledMod; return scrambledMod;
} }
public byte[] getScrambledModulus()
{
return _scrambledModulus;
}
} }

View File

@@ -65,7 +65,7 @@ public final class GameServerTable implements IGameXmlReader
load(); load();
loadRegisteredGameServers(); loadRegisteredGameServers();
LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + GAME_SERVER_TABLE.size() + " registered Game Servers"); LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + GAME_SERVER_TABLE.size() + " registered Game Servers.");
initRSAKeys(); initRSAKeys();
LOGGER.info(GameServerTable.class.getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication."); LOGGER.info(GameServerTable.class.getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication.");
@@ -76,7 +76,7 @@ public final class GameServerTable implements IGameXmlReader
{ {
SERVER_NAMES.clear(); SERVER_NAMES.clear();
parseDatapackFile("data/servername.xml"); parseDatapackFile("data/servername.xml");
LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + SERVER_NAMES.size() + " server names"); LOGGER.info(GameServerTable.class.getSimpleName() + ": Loaded " + SERVER_NAMES.size() + " server names.");
} }
@Override @Override

View File

@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.logging.Level; import java.util.logging.Level;
@@ -32,10 +31,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.Server; import com.l2jmobius.Server;
import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.ClientNetworkManager;
import com.l2jmobius.loginserver.network.L2LoginPacketHandler;
import com.l2jmobius.loginserver.network.mmocore.SelectorConfig;
import com.l2jmobius.loginserver.network.mmocore.SelectorThread;
/** /**
* @author KenM * @author KenM
@@ -47,10 +43,9 @@ public final class L2LoginServer
public static final int PROTOCOL_REV = 0x0106; public static final int PROTOCOL_REV = 0x0106;
private static L2LoginServer _instance; private static L2LoginServer _instance;
private GameServerListener _gameServerListener; private GameServerListener _gameServerListener;
private SelectorThread<L2LoginClient> _selectorThread;
private Thread _restartLoginServer; private Thread _restartLoginServer;
public static void main(String[] args) public static void main(String[] args) throws Exception
{ {
new L2LoginServer(); new L2LoginServer();
} }
@@ -60,7 +55,7 @@ public final class L2LoginServer
return _instance; return _instance;
} }
private L2LoginServer() private L2LoginServer() throws Exception
{ {
_instance = this; _instance = this;
Server.serverMode = Server.MODE_LOGINSERVER; Server.serverMode = Server.MODE_LOGINSERVER;
@@ -105,37 +100,6 @@ public final class L2LoginServer
loadBanFile(); loadBanFile();
InetAddress bindAddress = null;
if (!Config.LOGIN_BIND_ADDRESS.equals("*"))
{
try
{
bindAddress = InetAddress.getByName(Config.LOGIN_BIND_ADDRESS);
}
catch (UnknownHostException e)
{
_log.log(Level.WARNING, "WARNING: The LoginServer bind address is invalid, using all avaliable IPs. Reason: " + e.getMessage(), e);
}
}
final SelectorConfig sc = new SelectorConfig();
sc.MAX_READ_PER_PASS = Config.MMO_MAX_READ_PER_PASS;
sc.MAX_SEND_PER_PASS = Config.MMO_MAX_SEND_PER_PASS;
sc.SLEEP_TIME = Config.MMO_SELECTOR_SLEEP_TIME;
sc.HELPER_BUFFER_COUNT = Config.MMO_HELPER_BUFFER_COUNT;
final L2LoginPacketHandler lph = new L2LoginPacketHandler();
final SelectorHelper sh = new SelectorHelper();
try
{
_selectorThread = new SelectorThread<>(sc, sh, lph, sh, sh);
}
catch (IOException e)
{
_log.log(Level.SEVERE, "FATAL: Failed to open Selector. Reason: " + e.getMessage(), e);
System.exit(1);
}
try try
{ {
_gameServerListener = new GameServerListener(); _gameServerListener = new GameServerListener();
@@ -148,17 +112,7 @@ public final class L2LoginServer
System.exit(1); System.exit(1);
} }
try ClientNetworkManager.getInstance().start();
{
_selectorThread.openServerSocket(bindAddress, Config.PORT_LOGIN);
_selectorThread.start();
_log.info(getClass().getSimpleName() + ": is now listening on: " + Config.LOGIN_BIND_ADDRESS + ":" + Config.PORT_LOGIN);
}
catch (IOException e)
{
_log.log(Level.SEVERE, "FATAL: Failed to open server socket. Reason: " + e.getMessage(), e);
System.exit(1);
}
} }
public GameServerListener getGameServerListener() public GameServerListener getGameServerListener()

View File

@@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAKeyGenParameterSpec; import java.security.spec.RSAKeyGenParameterSpec;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@@ -37,7 +36,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.Cipher; import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.commons.database.DatabaseFactory;
@@ -64,10 +64,8 @@ public class LoginController
private final Map<InetAddress, Integer> _failedLoginAttemps = new HashMap<>(); private final Map<InetAddress, Integer> _failedLoginAttemps = new HashMap<>();
private final Map<InetAddress, Long> _bannedIps = new ConcurrentHashMap<>(); private final Map<InetAddress, Long> _bannedIps = new ConcurrentHashMap<>();
protected ScrambledKeyPair[] _keyPairs; private final ScrambledKeyPair[] _keyPairs;
private final KeyGenerator _blowfishKeyGenerator;
protected byte[][] _blowfishKeys;
private static final int BLOWFISH_KEYS = 20;
// SQL Queries // SQL Queries
private static final String USER_INFO_SELECT = "SELECT login, password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?"; private static final String USER_INFO_SELECT = "SELECT login, password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?";
@@ -83,62 +81,26 @@ public class LoginController
_log.info("Loading LoginController..."); _log.info("Loading LoginController...");
_keyPairs = new ScrambledKeyPair[10]; _keyPairs = new ScrambledKeyPair[10];
_blowfishKeyGenerator = KeyGenerator.getInstance("Blowfish");
final KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA"); final KeyPairGenerator rsaKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4); final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4);
keygen.initialize(spec); rsaKeyPairGenerator.initialize(spec);
// generate the initial set of keys for (int i = 0; i < _keyPairs.length; i++)
for (int i = 0; i < 10; i++)
{ {
_keyPairs[i] = new ScrambledKeyPair(keygen.generateKeyPair()); _keyPairs[i] = new ScrambledKeyPair(rsaKeyPairGenerator.generateKeyPair());
} }
_log.info("Cached 10 KeyPairs for RSA communication");
testCipher((RSAPrivateKey) _keyPairs[0]._pair.getPrivate()); _log.info("Cached 10 KeyPairs for RSA communication.");
// Store keys for blowfish communication
generateBlowFishKeys();
final Thread purge = new PurgeThread(); final Thread purge = new PurgeThread();
purge.setDaemon(true); purge.setDaemon(true);
purge.start(); purge.start();
} }
/** public SecretKey generateBlowfishKey()
* This is mostly to force the initialization of the Crypto Implementation, avoiding it being done on runtime when its first needed.<BR>
* In short it avoids the worst-case execution time on runtime by doing it on loading.
* @param key Any private RSA Key just for testing purposes.
* @throws GeneralSecurityException if a underlying exception was thrown by the Cipher
*/
private void testCipher(RSAPrivateKey key) throws GeneralSecurityException
{ {
// avoid worst-case execution, KenM return _blowfishKeyGenerator.generateKey();
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
rsaCipher.init(Cipher.DECRYPT_MODE, key);
}
private void generateBlowFishKeys()
{
_blowfishKeys = new byte[BLOWFISH_KEYS][16];
for (int i = 0; i < BLOWFISH_KEYS; i++)
{
for (int j = 0; j < _blowfishKeys[i].length; j++)
{
_blowfishKeys[i][j] = (byte) (Rnd.nextInt(255) + 1);
}
}
_log.info("Stored " + _blowfishKeys.length + " keys for Blowfish communication");
}
/**
* @return Returns a random key
*/
public byte[] getBlowfishKey()
{
return _blowfishKeys[(int) (Math.random() * BLOWFISH_KEYS)];
} }
public SessionKey assignSessionKeyToClient(String account, L2LoginClient client) public SessionKey assignSessionKeyToClient(String account, L2LoginClient client)

View File

@@ -1,67 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.IAcceptFilter;
import com.l2jmobius.loginserver.network.mmocore.IClientFactory;
import com.l2jmobius.loginserver.network.mmocore.IMMOExecutor;
import com.l2jmobius.loginserver.network.mmocore.MMOConnection;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
import com.l2jmobius.loginserver.network.serverpackets.Init;
import com.l2jmobius.loginserver.network.util.IPv4Filter;
/**
* @author KenM
*/
public class SelectorHelper implements IMMOExecutor<L2LoginClient>, IClientFactory<L2LoginClient>, IAcceptFilter
{
private final ThreadPoolExecutor _generalPacketsThreadPool;
private final IPv4Filter _ipv4filter;
public SelectorHelper()
{
_generalPacketsThreadPool = new ThreadPoolExecutor(4, 6, 15L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
_ipv4filter = new IPv4Filter();
}
@Override
public void execute(ReceivablePacket<L2LoginClient> packet)
{
_generalPacketsThreadPool.execute(packet);
}
@Override
public L2LoginClient create(MMOConnection<L2LoginClient> con)
{
final L2LoginClient client = new L2LoginClient(con);
client.sendPacket(new Init(client));
return client;
}
@Override
public boolean accept(SocketChannel sc) throws UnknownHostException
{
return _ipv4filter.accept(sc) && !LoginController.getInstance().isBannedAddress(sc.socket().getInetAddress());
}
}

View File

@@ -14,15 +14,26 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import com.l2jmobius.loginserver.LoginController;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ipfilter.AbstractRemoteAddressFilter;
/** /**
* @author KenM * @author lord_rex
*/ */
public interface IAcceptFilter @Sharable
public final class BannedIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress>
{ {
boolean accept(SocketChannel sc) throws UnknownHostException; @Override
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws UnknownHostException
{
return !LoginController.getInstance().isBannedAddress(remoteAddress.getAddress());
}
} }

View File

@@ -0,0 +1,56 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.nio.ByteOrder;
import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.codecs.CryptCodec;
import com.l2jmobius.commons.network.codecs.LengthFieldBasedFrameEncoder;
import com.l2jmobius.commons.network.codecs.PacketDecoder;
import com.l2jmobius.commons.network.codecs.PacketEncoder;
import com.l2jmobius.commons.util.crypt.LoginCrypt;
import com.l2jmobius.loginserver.LoginController;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
/**
* @author Nos
*/
public class ClientInitializer extends ChannelInitializer<SocketChannel>
{
private static final LengthFieldBasedFrameEncoder LENGTH_ENCODER = new LengthFieldBasedFrameEncoder();
private static final PacketEncoder PACKET_ENCODER = new PacketEncoder(0x8000 - 2);
@Override
protected void initChannel(SocketChannel ch)
{
final SecretKey newKey = LoginController.getInstance().generateBlowfishKey();
final L2LoginClient client = new L2LoginClient(newKey);
ch.pipeline().addLast(new BannedIpFilter());
ch.pipeline().addLast("length-decoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 0x8000 - 2, 0, 2, -2, 2, false));
ch.pipeline().addLast("length-encoder", LENGTH_ENCODER);
ch.pipeline().addLast("crypt-codec", new CryptCodec(new LoginCrypt(newKey)));
// ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
ch.pipeline().addLast("packet-decoder", new PacketDecoder<>(IncomingPackets.PACKET_ARRAY, client));
ch.pipeline().addLast("packet-encoder", PACKET_ENCODER);
ch.pipeline().addLast(client);
}
}

View File

@@ -14,48 +14,28 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import java.nio.BufferOverflowException; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.NetworkManager;
/** /**
* @author Forsaiken * @author Nos
*/ */
public final class NioNetStringBuffer public class ClientNetworkManager extends NetworkManager
{ {
private final char[] _buf; protected ClientNetworkManager()
private final int _size;
private int _len;
public NioNetStringBuffer(int size)
{ {
_buf = new char[size]; super(EventLoopGroupManager.getInstance().getBossGroup(), EventLoopGroupManager.getInstance().getWorkerGroup(), new ClientInitializer(), Config.LOGIN_BIND_ADDRESS, Config.PORT_LOGIN);
_size = size;
_len = 0;
} }
public final void clear() public static ClientNetworkManager getInstance()
{ {
_len = 0; return SingletonHolder._instance;
} }
public final void append(char c) private static class SingletonHolder
{ {
if (_len < _size) protected static final ClientNetworkManager _instance = new ClientNetworkManager();
{
_buf[_len++] = c;
}
else
{
throw new BufferOverflowException();
}
}
@Override
public final String toString()
{
return new String(_buf, 0, _len);
} }
} }

View File

@@ -14,13 +14,16 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.l2jmobius.loginserver.network.mmocore; package com.l2jmobius.loginserver.network;
import com.l2jmobius.commons.network.IConnectionState;
/** /**
* @author KenM * @author Mobius
* @param <T>
*/ */
public interface IClientFactory<T extends MMOClient<?>> public enum ConnectionState implements IConnectionState
{ {
T create(MMOConnection<T> con); CONNECTED,
AUTHED_GG,
AUTHED_LOGIN;
} }

View File

@@ -0,0 +1,56 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import com.l2jmobius.Config;
import io.netty.channel.nio.NioEventLoopGroup;
/**
* @author Nos
*/
public class EventLoopGroupManager
{
private final NioEventLoopGroup _bossGroup = new NioEventLoopGroup(1);
private final NioEventLoopGroup _workerGroup = new NioEventLoopGroup(Config.IO_PACKET_THREAD_CORE_SIZE);
public NioEventLoopGroup getBossGroup()
{
return _bossGroup;
}
public NioEventLoopGroup getWorkerGroup()
{
return _workerGroup;
}
public void shutdown()
{
_bossGroup.shutdownGracefully();
_workerGroup.shutdownGracefully();
}
public static EventLoopGroupManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final EventLoopGroupManager _instance = new EventLoopGroupManager();
}
}

View File

@@ -0,0 +1,92 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import com.l2jmobius.commons.network.IConnectionState;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IIncomingPackets;
import com.l2jmobius.loginserver.network.clientpackets.AuthGameGuard;
import com.l2jmobius.loginserver.network.clientpackets.RequestAuthLogin;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreement;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreementCheck;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerList;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerLogin;
/**
* @author Mobius
*/
public enum IncomingPackets implements IIncomingPackets<L2LoginClient>
{
AUTH_GAME_GUARD(0x07, AuthGameGuard::new, ConnectionState.CONNECTED),
REQUEST_AUTH_LOGIN(0x00, RequestAuthLogin::new, ConnectionState.AUTHED_GG),
REQUEST_SERVER_LOGIN(0x02, RequestServerLogin::new, ConnectionState.AUTHED_LOGIN),
REQUEST_SERVER_LIST(0x05, RequestServerList::new, ConnectionState.AUTHED_LOGIN),
REQUEST_PI_AGREEMENT_CHECK(0x0E, RequestPIAgreementCheck::new, ConnectionState.AUTHED_LOGIN),
REQUEST_PI_AGREEMENT(0x0F, RequestPIAgreement::new, ConnectionState.AUTHED_LOGIN);
public static final IncomingPackets[] PACKET_ARRAY;
static
{
final short maxPacketId = (short) Arrays.stream(values()).mapToInt(IIncomingPackets::getPacketId).max().orElse(0);
PACKET_ARRAY = new IncomingPackets[maxPacketId + 1];
for (IncomingPackets incomingPacket : values())
{
PACKET_ARRAY[incomingPacket.getPacketId()] = incomingPacket;
}
}
private short _packetId;
private Supplier<IIncomingPacket<L2LoginClient>> _incomingPacketFactory;
private Set<IConnectionState> _connectionStates;
IncomingPackets(int packetId, Supplier<IIncomingPacket<L2LoginClient>> incomingPacketFactory, IConnectionState... connectionStates)
{
// packetId is an unsigned byte
if (packetId > 0xFF)
{
throw new IllegalArgumentException("packetId must not be bigger than 0xFF");
}
_packetId = (short) packetId;
_incomingPacketFactory = incomingPacketFactory != null ? incomingPacketFactory : () -> null;
_connectionStates = new HashSet<>(Arrays.asList(connectionStates));
}
@Override
public int getPacketId()
{
return _packetId;
}
@Override
public IIncomingPacket<L2LoginClient> newIncomingPacket()
{
return _incomingPacketFactory.get();
}
@Override
public Set<IConnectionState> getConnectionStates()
{
return _connectionStates;
}
}

View File

@@ -16,127 +16,103 @@
*/ */
package com.l2jmobius.loginserver.network; package com.l2jmobius.loginserver.network;
import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.nio.ByteBuffer; import java.net.InetSocketAddress;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.crypto.SecretKey;
import com.l2jmobius.commons.network.ChannelInboundHandler;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.commons.util.crypt.LoginCrypt;
import com.l2jmobius.commons.util.crypt.ScrambledKeyPair; import com.l2jmobius.commons.util.crypt.ScrambledKeyPair;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.mmocore.MMOClient; import com.l2jmobius.loginserver.network.serverpackets.Init;
import com.l2jmobius.loginserver.network.mmocore.MMOConnection;
import com.l2jmobius.loginserver.network.mmocore.SendablePacket;
import com.l2jmobius.loginserver.network.serverpackets.L2LoginServerPacket;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail; import com.l2jmobius.loginserver.network.serverpackets.LoginFail;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail; import com.l2jmobius.loginserver.network.serverpackets.PlayFail;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
/** /**
* Represents a client connected into the LoginServer * Represents a client connected into the LoginServer
* @author KenM * @author KenM
*/ */
public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>> public final class L2LoginClient extends ChannelInboundHandler<L2LoginClient>
{ {
private static final Logger _log = Logger.getLogger(L2LoginClient.class.getName()); private static final Logger _log = Logger.getLogger(L2LoginClient.class.getName());
public enum LoginClientState
{
CONNECTED,
AUTHED_GG,
AUTHED_LOGIN
}
private LoginClientState _state;
// Crypt // Crypt
private final LoginCrypt _loginCrypt;
private final ScrambledKeyPair _scrambledPair; private final ScrambledKeyPair _scrambledPair;
private final byte[] _blowfishKey; private final SecretKey _blowfishKey;
private InetAddress _addr;
private Channel _channel;
private String _account; private String _account;
private int _accessLevel; private int _accessLevel;
private int _lastServer; private int _lastServer;
private SessionKey _sessionKey; private SessionKey _sessionKey;
private final int _sessionId; private int _sessionId;
private boolean _joinedGS; private boolean _joinedGS;
private Map<Integer, Integer> _charsOnServers; private Map<Integer, Integer> _charsOnServers;
private Map<Integer, long[]> _charsToDelete; private Map<Integer, long[]> _charsToDelete;
private final long _connectionStartTime; private long _connectionStartTime;
/** public L2LoginClient(SecretKey blowfishKey)
* @param con
*/
public L2LoginClient(MMOConnection<L2LoginClient> con)
{ {
super(con); super();
_state = LoginClientState.CONNECTED;
_scrambledPair = LoginController.getInstance().getScrambledRSAKeyPair(); _scrambledPair = LoginController.getInstance().getScrambledRSAKeyPair();
_blowfishKey = LoginController.getInstance().getBlowfishKey(); _blowfishKey = blowfishKey;
}
@Override
public void channelActive(ChannelHandlerContext ctx)
{
super.channelActive(ctx);
setConnectionState(ConnectionState.CONNECTED);
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
_addr = address.getAddress();
_channel = ctx.channel();
_sessionId = Rnd.nextInt(); _sessionId = Rnd.nextInt();
_connectionStartTime = System.currentTimeMillis(); _connectionStartTime = System.currentTimeMillis();
_loginCrypt = new LoginCrypt();
_loginCrypt.setKey(_blowfishKey); sendPacket(new Init(_scrambledPair.getScrambledModulus(), _blowfishKey.getEncoded(), _sessionId));
} }
@Override @Override
public boolean decrypt(ByteBuffer buf, int size) public void channelInactive(ChannelHandlerContext ctx)
{ {
boolean isChecksumValid = false; if (!hasJoinedGS() || ((getConnectionStartTime() + LoginController.LOGIN_TIMEOUT) < System.currentTimeMillis()))
try
{ {
isChecksumValid = _loginCrypt.decrypt(buf.array(), buf.position(), size); LoginController.getInstance().removeAuthedLoginClient(getAccount());
if (!isChecksumValid)
{
// _log.warning("Wrong checksum from client: " + toString());
}
return true;
}
catch (IOException e)
{
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
super.getConnection().close((SendablePacket<L2LoginClient>) null);
return false;
} }
} }
@Override @Override
public boolean encrypt(ByteBuffer buf, int size) protected void channelRead0(ChannelHandlerContext ctx, IIncomingPacket<L2LoginClient> packet)
{ {
final int offset = buf.position();
try try
{ {
size = _loginCrypt.encrypt(buf.array(), offset, size); packet.run(this);
} }
catch (IOException e) catch (Exception e)
{ {
_log.warning(getClass().getSimpleName() + ": " + e.getMessage()); _log.warning(getClass().getSimpleName() + ": " + e.getMessage());
return false;
} }
buf.position(offset + size);
return true;
} }
public LoginClientState getState() public InetAddress getConnectionAddress()
{ {
return _state; return _addr;
}
public void setState(LoginClientState state)
{
_state = state;
}
public byte[] getBlowfishKey()
{
return _blowfishKey;
} }
public byte[] getScrambledModulus() public byte[] getScrambledModulus()
@@ -209,24 +185,39 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
return _connectionStartTime; return _connectionStartTime;
} }
public void sendPacket(L2LoginServerPacket lsp) public void sendPacket(IOutgoingPacket packet)
{ {
getConnection().sendPacket(lsp); if ((packet == null))
{
return;
}
// Write into the channel.
_channel.writeAndFlush(packet);
} }
public void close(LoginFailReason reason) public void close(LoginFailReason reason)
{ {
getConnection().close(new LoginFail(reason)); close(new LoginFail(reason));
} }
public void close(PlayFailReason reason) public void close(PlayFailReason reason)
{ {
getConnection().close(new PlayFail(reason)); close(new PlayFail(reason));
} }
public void close(L2LoginServerPacket lsp) public void close(IOutgoingPacket packet)
{ {
getConnection().close(lsp); sendPacket(packet);
closeNow();
}
public void closeNow()
{
if (_channel != null)
{
_channel.close();
}
} }
public void setCharsOnServ(int servId, int chars) public void setCharsOnServ(int servId, int chars)
@@ -256,30 +247,4 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
{ {
return _charsToDelete; return _charsToDelete;
} }
@Override
public void onDisconnection()
{
if (!hasJoinedGS() || ((getConnectionStartTime() + LoginController.LOGIN_TIMEOUT) < System.currentTimeMillis()))
{
LoginController.getInstance().removeAuthedLoginClient(getAccount());
}
}
@Override
public String toString()
{
final InetAddress address = getConnection().getInetAddress();
if (getState() == LoginClientState.AUTHED_LOGIN)
{
return "[" + getAccount() + " (" + (address == null ? "disconnected" : address.getHostAddress()) + ")]";
}
return "[" + (address == null ? "disconnected" : address.getHostAddress()) + "]";
}
@Override
protected void onForcedDisconnection()
{
// Empty
}
} }

View File

@@ -1,124 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState;
import com.l2jmobius.loginserver.network.clientpackets.AuthGameGuard;
import com.l2jmobius.loginserver.network.clientpackets.RequestAuthLogin;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreement;
import com.l2jmobius.loginserver.network.clientpackets.RequestPIAgreementCheck;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerList;
import com.l2jmobius.loginserver.network.clientpackets.RequestServerLogin;
import com.l2jmobius.loginserver.network.mmocore.IPacketHandler;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
/**
* Handler for packets received by Login Server
* @author KenM
*/
public final class L2LoginPacketHandler implements IPacketHandler<L2LoginClient>
{
protected static final Logger _log = Logger.getLogger(L2LoginPacketHandler.class.getName());
@Override
public ReceivablePacket<L2LoginClient> handlePacket(ByteBuffer buf, L2LoginClient client)
{
final int opcode = buf.get() & 0xFF;
ReceivablePacket<L2LoginClient> packet = null;
final LoginClientState state = client.getState();
switch (state)
{
case CONNECTED:
{
switch (opcode)
{
case 0x07:
{
packet = new AuthGameGuard();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
case AUTHED_GG:
{
switch (opcode)
{
case 0x00:
{
packet = new RequestAuthLogin();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
case AUTHED_LOGIN:
{
switch (opcode)
{
case 0x02:
{
packet = new RequestServerLogin();
break;
}
case 0x05:
{
packet = new RequestServerList();
break;
}
case 0x0E:
{
packet = new RequestPIAgreementCheck(); // TODO: Verify names
break;
}
case 0x0F:
{
packet = new RequestPIAgreement();
break;
}
default:
{
debugOpcode(opcode, state);
break;
}
}
break;
}
}
return packet;
}
private void debugOpcode(int opcode, LoginClientState state)
{
_log.info("Unknown Opcode: " + opcode + " for state: " + state.name());
}
}

View File

@@ -0,0 +1,83 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network;
import com.l2jmobius.commons.network.PacketWriter;
/**
* @author Mobius
*/
public enum OutgoingPackets
{
INIT(0x00),
LOGIN_FAIL(0x01),
ACCOUNT_KICKED(0x02),
LOGIN_OK(0x03),
SERVER_LIST(0x04),
PLAY_FAIL(0x06),
PLAY_OK(0x07),
PI_AGREEMENT_CHECK(0x11),
PI_AGREEMENT_ACK(0x12),
GG_AUTH(0x0b),
LOGIN_OPT_FAIL(0x0D);
private final int _id1;
private final int _id2;
OutgoingPackets(int id1)
{
this(id1, -1);
}
OutgoingPackets(int id1, int id2)
{
_id1 = id1;
_id2 = id2;
}
public int getId1()
{
return _id1;
}
public int getId2()
{
return _id2;
}
public void writeId(PacketWriter packet)
{
packet.writeC(_id1);
if (_id2 > 0)
{
packet.writeH(_id2);
}
}
public static OutgoingPackets getPacket(int id1, int id2)
{
for (OutgoingPackets packet : values())
{
if ((packet.getId1() == id1) && (packet.getId2() == id2))
{
return packet;
}
}
return null;
}
}

View File

@@ -16,7 +16,10 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState; import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.ConnectionState;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.GGAuth; import com.l2jmobius.loginserver.network.serverpackets.GGAuth;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
@@ -24,65 +27,39 @@ import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason
* Format: ddddd * Format: ddddd
* @author -Wooden- * @author -Wooden-
*/ */
public class AuthGameGuard extends L2LoginClientPacket public class AuthGameGuard implements IIncomingPacket<L2LoginClient>
{ {
private int _sessionId; private int _sessionId;
private int _data1;
private int _data2;
private int _data3;
private int _data4;
public int getSessionId() @SuppressWarnings("unused")
{ private int _data1, _data2, _data3, _data4;
return _sessionId;
}
public int getData1()
{
return _data1;
}
public int getData2()
{
return _data2;
}
public int getData3()
{
return _data3;
}
public int getData4()
{
return _data4;
}
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 20) if (packet.getReadableBytes() >= 20)
{ {
_sessionId = readD(); _sessionId = packet.readD();
_data1 = readD(); _data1 = packet.readD();
_data2 = readD(); _data2 = packet.readD();
_data3 = readD(); _data3 = packet.readD();
_data4 = readD(); _data4 = packet.readD();
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
if (_sessionId == getClient().getSessionId()) if (_sessionId == client.getSessionId())
{ {
getClient().setState(LoginClientState.AUTHED_GG); client.setConnectionState(ConnectionState.AUTHED_GG);
getClient().sendPacket(new GGAuth(getClient().getSessionId())); client.sendPacket(new GGAuth(client.getSessionId()));
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -1,47 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.clientpackets;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.ReceivablePacket;
/**
* @author KenM
*/
public abstract class L2LoginClientPacket extends ReceivablePacket<L2LoginClient>
{
private static Logger _log = Logger.getLogger(L2LoginClientPacket.class.getName());
@Override
protected final boolean read()
{
try
{
return readImpl();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "ERROR READING: " + getClass().getSimpleName() + ": " + e.getMessage(), e);
return false;
}
}
protected abstract boolean readImpl();
}

View File

@@ -24,12 +24,14 @@ import java.util.logging.Logger;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; import com.l2jmobius.loginserver.GameServerTable.GameServerInfo;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.LoginController.AuthLoginResult; import com.l2jmobius.loginserver.LoginController.AuthLoginResult;
import com.l2jmobius.loginserver.model.data.AccountInfo; import com.l2jmobius.loginserver.model.data.AccountInfo;
import com.l2jmobius.loginserver.network.ConnectionState;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.L2LoginClient.LoginClientState;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked; import com.l2jmobius.loginserver.network.serverpackets.AccountKicked;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked.AccountKickedReason; import com.l2jmobius.loginserver.network.serverpackets.AccountKicked.AccountKickedReason;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
@@ -42,7 +44,7 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
* *
* <pre> * <pre>
*/ */
public class RequestAuthLogin extends L2LoginClientPacket public class RequestAuthLogin implements IIncomingPacket<L2LoginClient>
{ {
private static Logger _log = Logger.getLogger(RequestAuthLogin.class.getName()); private static Logger _log = Logger.getLogger(RequestAuthLogin.class.getName());
@@ -53,45 +55,28 @@ public class RequestAuthLogin extends L2LoginClientPacket
private String _user; private String _user;
private String _password; private String _password;
/**
* @return
*/
public String getPassword()
{
return _password;
}
/**
* @return
*/
public String getUser()
{
return _user;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 256) if (packet.getReadableBytes() >= 256)
{ {
_newAuthMethod = true; _newAuthMethod = true;
readB(_raw1); packet.readB(_raw1, 0, _raw1.length);
readB(_raw2); packet.readB(_raw2, 0, _raw2.length);
return true; return true;
} }
else if (super._buf.remaining() >= 128) else if (packet.getReadableBytes() >= 128)
{ {
readB(_raw1); packet.readB(_raw1, 0, _raw1.length);
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
final L2LoginClient client = getClient(); byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
final byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
try try
{ {
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding"); final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
@@ -127,7 +112,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
return; return;
} }
final InetAddress clientAddr = client.getConnection().getInetAddress(); final InetAddress clientAddr = client.getConnectionAddress();
final LoginController lc = LoginController.getInstance(); final LoginController lc = LoginController.getInstance();
final AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password); final AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password);
if (info == null) if (info == null)
@@ -143,7 +128,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
case AUTH_SUCCESS: case AUTH_SUCCESS:
{ {
client.setAccount(info.getLogin()); client.setAccount(info.getLogin());
client.setState(LoginClientState.AUTHED_LOGIN); client.setConnectionState(ConnectionState.AUTHED_LOGIN);
client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client)); client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client));
lc.getCharactersOnAccount(info.getLogin()); lc.getCharactersOnAccount(info.getLogin());
if (Config.SHOW_LICENCE) if (Config.SHOW_LICENCE)

View File

@@ -16,27 +16,30 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.PIAgreementAck; import com.l2jmobius.loginserver.network.serverpackets.PIAgreementAck;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class RequestPIAgreement extends L2LoginClientPacket public class RequestPIAgreement implements IIncomingPacket<L2LoginClient>
{ {
private int _accountId; private int _accountId;
private int _status; private int _status;
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
_accountId = readD(); _accountId = packet.readD();
_status = readC(); _status = packet.readC();
return true; return true;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
getClient().sendPacket(new PIAgreementAck(_accountId, _status)); client.sendPacket(new PIAgreementAck(_accountId, _status));
} }
} }

View File

@@ -17,31 +17,34 @@
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.PIAgreementCheck; import com.l2jmobius.loginserver.network.serverpackets.PIAgreementCheck;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class RequestPIAgreementCheck extends L2LoginClientPacket public class RequestPIAgreementCheck implements IIncomingPacket<L2LoginClient>
{ {
private int _accountId; private int _accountId;
@Override @Override
protected boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
_accountId = readD(); _accountId = packet.readD();
final byte[] padding0 = new byte[3]; byte[] padding0 = new byte[3];
final byte[] checksum = new byte[4]; byte[] checksum = new byte[4];
final byte[] padding1 = new byte[12]; byte[] padding1 = new byte[12];
readB(padding0); packet.readB(padding0, 0, padding0.length);
readB(checksum); packet.readB(checksum, 0, checksum.length);
readB(padding1); packet.readB(padding1, 0, padding1.length);
return true; return true;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
getClient().sendPacket(new PIAgreementCheck(_accountId, Config.SHOW_PI_AGREEMENT ? 0x01 : 0x00)); client.sendPacket(new PIAgreementCheck(_accountId, Config.SHOW_PI_AGREEMENT ? 0x01 : 0x00));
} }
} }

View File

@@ -16,6 +16,9 @@
*/ */
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.ServerList; import com.l2jmobius.loginserver.network.serverpackets.ServerList;
@@ -27,58 +30,35 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
* c: ? * c: ?
* </pre> * </pre>
*/ */
public class RequestServerList extends L2LoginClientPacket public class RequestServerList implements IIncomingPacket<L2LoginClient>
{ {
private int _skey1; private int _skey1;
private int _skey2; private int _skey2;
@SuppressWarnings("unused")
private int _data3; private int _data3;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getData3()
{
return _data3;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 8) if (packet.getReadableBytes() >= 8)
{ {
_skey1 = readD(); // loginOk 1 _skey1 = packet.readD(); // loginOk 1
_skey2 = readD(); // loginOk 2 _skey2 = packet.readD(); // loginOk 2
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
if (getClient().getSessionKey().checkLoginPair(_skey1, _skey2)) if (client.getSessionKey().checkLoginPair(_skey1, _skey2))
{ {
getClient().sendPacket(new ServerList(getClient())); client.sendPacket(new ServerList(client));
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -17,8 +17,11 @@
package com.l2jmobius.loginserver.network.clientpackets; package com.l2jmobius.loginserver.network.clientpackets;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.loginserver.LoginController; import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayOk; import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
@@ -31,70 +34,46 @@ import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
* c: server ID * c: server ID
* </pre> * </pre>
*/ */
public class RequestServerLogin extends L2LoginClientPacket public class RequestServerLogin implements IIncomingPacket<L2LoginClient>
{ {
private int _skey1; private int _skey1;
private int _skey2; private int _skey2;
private int _serverId; private int _serverId;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getServerID()
{
return _serverId;
}
@Override @Override
public boolean readImpl() public boolean read(L2LoginClient client, PacketReader packet)
{ {
if (super._buf.remaining() >= 9) if (packet.getReadableBytes() >= 9)
{ {
_skey1 = readD(); _skey1 = packet.readD();
_skey2 = readD(); _skey2 = packet.readD();
_serverId = readC(); _serverId = packet.readC();
return true; return true;
} }
return false; return false;
} }
@Override @Override
public void run() public void run(L2LoginClient client)
{ {
final SessionKey sk = getClient().getSessionKey(); final SessionKey sk = client.getSessionKey();
// if we didnt showed the license we cant check these values // if we didnt showed the license we cant check these values
if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2))
{ {
if (LoginController.getInstance().isLoginPossible(getClient(), _serverId)) if (LoginController.getInstance().isLoginPossible(client, _serverId))
{ {
getClient().setJoinedGS(true); client.setJoinedGS(true);
getClient().sendPacket(new PlayOk(sk)); client.sendPacket(new PlayOk(sk));
} }
else else
{ {
getClient().close(PlayFailReason.REASON_SERVER_OVERLOADED); client.close(PlayFailReason.REASON_SERVER_OVERLOADED);
} }
} }
else else
{ {
getClient().close(LoginFailReason.REASON_ACCESS_FAILED); client.close(LoginFailReason.REASON_ACCESS_FAILED);
} }
} }
} }

View File

@@ -1,35 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class AbstractPacket<T extends MMOClient<?>>
{
protected ByteBuffer _buf;
T _client;
public final T getClient()
{
return _client;
}
}

View File

@@ -1,28 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public interface IPacketHandler<T extends MMOClient<?>>
{
ReceivablePacket<T> handlePacket(ByteBuffer buf, T client);
}

View File

@@ -1,46 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class MMOClient<T extends MMOConnection<?>>
{
private final T _con;
public MMOClient(T con)
{
_con = con;
}
public T getConnection()
{
return _con;
}
public abstract boolean decrypt(ByteBuffer buf, int size);
public abstract boolean encrypt(ByteBuffer buf, int size);
protected abstract void onDisconnection();
protected abstract void onForcedDisconnection();
}

View File

@@ -1,283 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.WritableByteChannel;
/**
* @author KenM
* @param <T>
*/
public class MMOConnection<T extends MMOClient<?>>
{
private final SelectorThread<T> _selectorThread;
private final Socket _socket;
private final InetAddress _address;
private final ReadableByteChannel _readableByteChannel;
private final WritableByteChannel _writableByteChannel;
private final int _port;
private final NioNetStackList<SendablePacket<T>> _sendQueue;
private final SelectionKey _selectionKey;
private ByteBuffer _readBuffer;
private ByteBuffer _primaryWriteBuffer;
private ByteBuffer _secondaryWriteBuffer;
private volatile boolean _pendingClose;
private T _client;
public MMOConnection(SelectorThread<T> selectorThread, Socket socket, SelectionKey key, boolean tcpNoDelay)
{
_selectorThread = selectorThread;
_socket = socket;
_address = socket.getInetAddress();
_readableByteChannel = socket.getChannel();
_writableByteChannel = socket.getChannel();
_port = socket.getPort();
_selectionKey = key;
_sendQueue = new NioNetStackList<>();
try
{
_socket.setTcpNoDelay(tcpNoDelay);
}
catch (SocketException e)
{
e.printStackTrace();
}
}
final void setClient(T client)
{
_client = client;
}
public final T getClient()
{
return _client;
}
public final void sendPacket(SendablePacket<T> sp)
{
sp._client = _client;
if (_pendingClose)
{
return;
}
synchronized (getSendQueue())
{
_sendQueue.addLast(sp);
}
if (!_sendQueue.isEmpty())
{
try
{
_selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE);
}
catch (CancelledKeyException e)
{
// ignore
}
}
}
final SelectionKey getSelectionKey()
{
return _selectionKey;
}
public final InetAddress getInetAddress()
{
return _address;
}
public final int getPort()
{
return _port;
}
final void close() throws IOException
{
_socket.close();
}
final int read(ByteBuffer buf) throws IOException
{
return _readableByteChannel.read(buf);
}
final int write(ByteBuffer buf) throws IOException
{
return _writableByteChannel.write(buf);
}
final void createWriteBuffer(ByteBuffer buf)
{
if (_primaryWriteBuffer == null)
{
_primaryWriteBuffer = _selectorThread.getPooledBuffer();
_primaryWriteBuffer.put(buf);
}
else
{
final ByteBuffer temp = _selectorThread.getPooledBuffer();
temp.put(buf);
final int remaining = temp.remaining();
_primaryWriteBuffer.flip();
final int limit = _primaryWriteBuffer.limit();
if (remaining >= _primaryWriteBuffer.remaining())
{
temp.put(_primaryWriteBuffer);
_selectorThread.recycleBuffer(_primaryWriteBuffer);
}
else
{
_primaryWriteBuffer.limit(remaining);
temp.put(_primaryWriteBuffer);
_primaryWriteBuffer.limit(limit);
_primaryWriteBuffer.compact();
_secondaryWriteBuffer = _primaryWriteBuffer;
}
_primaryWriteBuffer = temp;
}
}
final boolean hasPendingWriteBuffer()
{
return _primaryWriteBuffer != null;
}
final void movePendingWriteBufferTo(ByteBuffer dest)
{
_primaryWriteBuffer.flip();
dest.put(_primaryWriteBuffer);
_selectorThread.recycleBuffer(_primaryWriteBuffer);
_primaryWriteBuffer = _secondaryWriteBuffer;
_secondaryWriteBuffer = null;
}
final void setReadBuffer(ByteBuffer buf)
{
_readBuffer = buf;
}
final ByteBuffer getReadBuffer()
{
return _readBuffer;
}
public final boolean isClosed()
{
return _pendingClose;
}
final NioNetStackList<SendablePacket<T>> getSendQueue()
{
return _sendQueue;
}
/*
* final SendablePacket<T> getClosePacket() { return _closePacket; }
*/
@SuppressWarnings("unchecked")
public final void close(SendablePacket<T> sp)
{
close(new SendablePacket[]
{
sp
});
}
public final void close(SendablePacket<T>[] closeList)
{
if (_pendingClose)
{
return;
}
synchronized (getSendQueue())
{
if (!_pendingClose)
{
_pendingClose = true;
_sendQueue.clear();
for (SendablePacket<T> sp : closeList)
{
_sendQueue.addLast(sp);
}
}
}
try
{
_selectionKey.interestOps(_selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
}
catch (CancelledKeyException e)
{
// ignore
}
// _closePacket = sp;
_selectorThread.closeConnection(this);
}
final void releaseBuffers()
{
if (_primaryWriteBuffer != null)
{
_selectorThread.recycleBuffer(_primaryWriteBuffer);
_primaryWriteBuffer = null;
if (_secondaryWriteBuffer != null)
{
_selectorThread.recycleBuffer(_secondaryWriteBuffer);
_secondaryWriteBuffer = null;
}
}
if (_readBuffer != null)
{
_selectorThread.recycleBuffer(_readBuffer);
_readBuffer = null;
}
}
}

View File

@@ -1,101 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author Forsaiken
* @param <E>
*/
public final class NioNetStackList<E>
{
private final NioNetStackNode _start = new NioNetStackNode();
private final NioNetStackNodeBuf _buf = new NioNetStackNodeBuf();
private NioNetStackNode _end = new NioNetStackNode();
public NioNetStackList()
{
clear();
}
public final void addLast(E elem)
{
final NioNetStackNode newEndNode = _buf.removeFirst();
_end._value = elem;
_end._next = newEndNode;
_end = newEndNode;
}
public final E removeFirst()
{
final NioNetStackNode old = _start._next;
final E value = old._value;
_start._next = old._next;
_buf.addLast(old);
return value;
}
public final boolean isEmpty()
{
return _start._next == _end;
}
public final void clear()
{
_start._next = _end;
}
protected final class NioNetStackNode
{
protected NioNetStackNode _next;
protected E _value;
}
private final class NioNetStackNodeBuf
{
private final NioNetStackNode _start = new NioNetStackNode();
private NioNetStackNode _end = new NioNetStackNode();
NioNetStackNodeBuf()
{
_start._next = _end;
}
final void addLast(NioNetStackNode node)
{
node._next = null;
node._value = null;
_end._next = node;
_end = node;
}
final NioNetStackNode removeFirst()
{
if (_start._next == _end)
{
return new NioNetStackNode();
}
final NioNetStackNode old = _start._next;
_start._next = old._next;
return old;
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.nio.ByteBuffer;
/**
* @author KenM
* @param <T>
*/
public abstract class ReceivablePacket<T extends MMOClient<?>>extends AbstractPacket<T> implements Runnable
{
NioNetStringBuffer _sbuf;
protected ReceivablePacket()
{
}
protected abstract boolean read();
@Override
public abstract void run();
/**
* Reads <B>byte[]</B> from the buffer. <BR>
* Reads as many bytes as the length of the array.
* @param dst : the byte array which will be filled with the data.
*/
protected final void readB(byte[] dst)
{
_buf.get(dst);
}
/**
* Reads <B>byte[]</B> from the buffer. <BR>
* Reads as many bytes as the given length (len). Starts to fill the byte array from the given offset to <B>offset</B> + <B>len</B>.
* @param dst : the byte array which will be filled with the data.
* @param offset : starts to fill the byte array from the given offset.
* @param len : the given length of bytes to be read.
*/
protected final void readB(byte[] dst, int offset, int len)
{
_buf.get(dst, offset, len);
}
/**
* Reads <B>byte</B> from the buffer. <BR>
* 8bit integer (00)
* @return
*/
protected final int readC()
{
return _buf.get() & 0xFF;
}
/**
* Reads <B>short</B> from the buffer. <BR>
* 16bit integer (00 00)
* @return
*/
protected final int readH()
{
return _buf.getShort() & 0xFFFF;
}
/**
* Reads <B>int</B> from the buffer. <BR>
* 32bit integer (00 00 00 00)
* @return
*/
protected final int readD()
{
return _buf.getInt();
}
/**
* Reads <B>long</B> from the buffer. <BR>
* 64bit integer (00 00 00 00 00 00 00 00)
* @return
*/
protected final long readQ()
{
return _buf.getLong();
}
/**
* Reads <B>double</B> from the buffer. <BR>
* 64bit double precision float (00 00 00 00 00 00 00 00)
* @return
*/
protected final double readF()
{
return _buf.getDouble();
}
/**
* Reads <B>String</B> from the buffer.
* @return
*/
protected final String readS()
{
_sbuf.clear();
char ch;
while ((ch = _buf.getChar()) != 0)
{
_sbuf.append(ch);
}
return _sbuf.toString();
}
/**
* packet forge purpose
* @param data
* @param client
* @param sBuffer
*/
public void setBuffers(ByteBuffer data, T client, NioNetStringBuffer sBuffer)
{
_buf = data;
_client = client;
_sbuf = sBuffer;
}
}

View File

@@ -1,63 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author KenM
*/
public final class SelectorConfig
{
public int READ_BUFFER_SIZE = 64 * 1024;
public int WRITE_BUFFER_SIZE = 64 * 1024;
public int HELPER_BUFFER_COUNT = 20;
public int HELPER_BUFFER_SIZE = 64 * 1024;
/**
* Server will try to send MAX_SEND_PER_PASS packets per socket write call<br>
* however it may send less if the write buffer was filled before achieving this value.
*/
public int MAX_SEND_PER_PASS = 10;
/**
* Server will try to read MAX_READ_PER_PASS packets per socket read call<br>
* however it may read less if the read buffer was empty before achieving this value.
*/
public int MAX_READ_PER_PASS = 10;
/**
* Defines how much time (in milis) should the selector sleep, an higher value increases throughput but also increases latency(to a max of the sleep value itself).<BR>
* Also an extremely high value(usually > 100) will decrease throughput due to the server not doing enough sends per second (depends on max sends per pass).<BR>
* <BR>
* Recommended values:<BR>
* 1 for minimal latency.<BR>
* 10-30 for an latency/troughput trade-off based on your needs.<BR>
*/
public int SLEEP_TIME = 10;
/**
* Used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm.<BR>
* <BR>
* Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase
* in bandwidth consumption. The Nagle's algorithm is described in RFC 896.<BR>
* <BR>
* Summary, data will be sent earlier, thus lowering the ping, at the cost of a small increase in bandwidth consumption.
*/
public boolean TCP_NODELAY = true;
}

View File

@@ -1,714 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Parts of design based on network core from WoodenGil
* @param <T>
* @author KenM
*/
public final class SelectorThread<T extends MMOClient<?>>extends Thread
{
// default BYTE_ORDER
private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;
// default HEADER_SIZE
private static final int HEADER_SIZE = 2;
// Selector
private final Selector _selector;
// Implementations
private final IPacketHandler<T> _packetHandler;
private final IMMOExecutor<T> _executor;
private final IClientFactory<T> _clientFactory;
private final IAcceptFilter _acceptFilter;
// Configurations
private final int HELPER_BUFFER_SIZE;
private final int HELPER_BUFFER_COUNT;
private final int MAX_SEND_PER_PASS;
private final int MAX_READ_PER_PASS;
private final long SLEEP_TIME;
public boolean TCP_NODELAY;
// Main Buffers
private final ByteBuffer DIRECT_WRITE_BUFFER;
private final ByteBuffer WRITE_BUFFER;
private final ByteBuffer READ_BUFFER;
// String Buffer
private final NioNetStringBuffer STRING_BUFFER;
// ByteBuffers General Purpose Pool
private final LinkedList<ByteBuffer> _bufferPool;
// Pending Close
private final NioNetStackList<MMOConnection<T>> _pendingClose;
private boolean _shutdown;
public SelectorThread(SelectorConfig sc, IMMOExecutor<T> executor, IPacketHandler<T> packetHandler, IClientFactory<T> clientFactory, IAcceptFilter acceptFilter) throws IOException
{
super.setName("SelectorThread-" + super.getId());
HELPER_BUFFER_SIZE = sc.HELPER_BUFFER_SIZE;
HELPER_BUFFER_COUNT = sc.HELPER_BUFFER_COUNT;
MAX_SEND_PER_PASS = sc.MAX_SEND_PER_PASS;
MAX_READ_PER_PASS = sc.MAX_READ_PER_PASS;
SLEEP_TIME = sc.SLEEP_TIME;
TCP_NODELAY = sc.TCP_NODELAY;
DIRECT_WRITE_BUFFER = ByteBuffer.allocateDirect(sc.WRITE_BUFFER_SIZE).order(BYTE_ORDER);
WRITE_BUFFER = ByteBuffer.wrap(new byte[sc.WRITE_BUFFER_SIZE]).order(BYTE_ORDER);
READ_BUFFER = ByteBuffer.wrap(new byte[sc.READ_BUFFER_SIZE]).order(BYTE_ORDER);
STRING_BUFFER = new NioNetStringBuffer(64 * 1024);
_pendingClose = new NioNetStackList<>();
_bufferPool = new LinkedList<>();
for (int i = 0; i < HELPER_BUFFER_COUNT; i++)
{
_bufferPool.addLast(ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER));
}
_acceptFilter = acceptFilter;
_packetHandler = packetHandler;
_clientFactory = clientFactory;
_executor = executor;
_selector = Selector.open();
}
public final void openServerSocket(InetAddress address, int tcpPort) throws IOException
{
final ServerSocketChannel selectable = ServerSocketChannel.open();
selectable.configureBlocking(false);
final ServerSocket ss = selectable.socket();
if (address != null)
{
ss.bind(new InetSocketAddress(address, tcpPort));
}
else
{
ss.bind(new InetSocketAddress(tcpPort));
}
selectable.register(_selector, SelectionKey.OP_ACCEPT);
}
final ByteBuffer getPooledBuffer()
{
if (_bufferPool.isEmpty())
{
return ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER);
}
return _bufferPool.removeFirst();
}
final void recycleBuffer(ByteBuffer buf)
{
if (_bufferPool.size() < HELPER_BUFFER_COUNT)
{
buf.clear();
_bufferPool.addLast(buf);
}
}
@SuppressWarnings("unchecked")
@Override
public final void run()
{
int selectedKeysCount = 0;
SelectionKey key;
MMOConnection<T> con;
Iterator<SelectionKey> selectedKeys;
while (!_shutdown)
{
try
{
selectedKeysCount = _selector.selectNow();
}
catch (IOException e)
{
e.printStackTrace();
}
if (selectedKeysCount > 0)
{
selectedKeys = _selector.selectedKeys().iterator();
while (selectedKeys.hasNext())
{
key = selectedKeys.next();
selectedKeys.remove();
con = (MMOConnection<T>) key.attachment();
switch (key.readyOps())
{
case SelectionKey.OP_CONNECT:
{
finishConnection(key, con);
break;
}
case SelectionKey.OP_ACCEPT:
{
acceptConnection(key, con);
break;
}
case SelectionKey.OP_READ:
{
readPacket(key, con);
break;
}
case SelectionKey.OP_WRITE:
{
writePacket(key, con);
break;
}
case SelectionKey.OP_READ | SelectionKey.OP_WRITE:
{
writePacket(key, con);
if (key.isValid())
{
readPacket(key, con);
}
break;
}
}
}
}
synchronized (_pendingClose)
{
while (!_pendingClose.isEmpty())
{
try
{
con = _pendingClose.removeFirst();
writeClosePacket(con);
closeConnectionImpl(con.getSelectionKey(), con);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
try
{
Thread.sleep(SLEEP_TIME);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
closeSelectorThread();
}
private final void finishConnection(SelectionKey key, MMOConnection<T> con)
{
try
{
((SocketChannel) key.channel()).finishConnect();
}
catch (IOException e)
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
}
// key might have been invalidated on finishConnect()
if (key.isValid())
{
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
}
}
private final void acceptConnection(SelectionKey key, MMOConnection<T> con)
{
final ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc;
try
{
while ((sc = ssc.accept()) != null)
{
if ((_acceptFilter == null) || _acceptFilter.accept(sc))
{
sc.configureBlocking(false);
final SelectionKey clientKey = sc.register(_selector, SelectionKey.OP_READ);
con = new MMOConnection<>(this, sc.socket(), clientKey, TCP_NODELAY);
con.setClient(_clientFactory.create(con));
clientKey.attach(con);
}
else
{
sc.socket().close();
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private final void readPacket(SelectionKey key, MMOConnection<T> con)
{
if (con.isClosed())
{
return;
}
ByteBuffer buf = con.getReadBuffer();
if (buf == null)
{
buf = READ_BUFFER;
}
// if we try to to do a read with no space in the buffer it will read 0 bytes going into infinite loop
if (buf.position() == buf.limit())
{
System.exit(0);
}
int result = -2;
try
{
result = con.read(buf);
}
catch (IOException e)
{
// error handling goes bellow
}
if (result > 0)
{
buf.flip();
final T client = con.getClient();
for (int i = 0; i < MAX_READ_PER_PASS; i++)
{
if (!tryReadPacket(key, client, buf, con))
{
return;
}
}
// only reachable if MAX_READ_PER_PASS has been reached
// check if there are some more bytes in buffer
// and allocate/compact to prevent content lose.
if (buf.remaining() > 0)
{
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
// move the first byte to the beginning :)
buf.compact();
}
}
}
else
{
switch (result)
{
case 0:
case -1:
{
closeConnectionImpl(key, con);
break;
}
case -2:
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
break;
}
}
}
}
private final boolean tryReadPacket(SelectionKey key, T client, ByteBuffer buf, MMOConnection<T> con)
{
switch (buf.remaining())
{
case 0:
{
// buffer is full nothing to read
return false;
}
case 1:
{
// we don`t have enough data for header so we need to read
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
// move the first byte to the beginning :)
buf.compact();
}
return false;
}
default:
{
// data size excluding header size :>
final int dataPending = (buf.getShort() & 0xFFFF) - HEADER_SIZE;
// do we got enough bytes for the packet?
if (dataPending <= buf.remaining())
{
// avoid parsing dummy packets (packets without body)
if (dataPending > 0)
{
final int pos = buf.position();
parseClientPacket(pos, buf, dataPending, client);
buf.position(pos + dataPending);
}
if (buf.hasRemaining())
{
return true;
}
if (buf != READ_BUFFER)
{
con.setReadBuffer(null);
recycleBuffer(buf);
}
else
{
READ_BUFFER.clear();
}
return false;
}
// we don`t have enough bytes for the dataPacket so we need to read
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
// move it`s position
buf.position(buf.position() - HEADER_SIZE);
// did we use the READ_BUFFER ?
if (buf == READ_BUFFER)
{
// move the pending byte to the connections READ_BUFFER
allocateReadBuffer(con);
}
else
{
buf.compact();
}
return false;
}
}
}
private final void allocateReadBuffer(MMOConnection<T> con)
{
con.setReadBuffer(getPooledBuffer().put(READ_BUFFER));
READ_BUFFER.clear();
}
private final void parseClientPacket(int pos, ByteBuffer buf, int dataSize, T client)
{
if (!client.decrypt(buf, dataSize) || !buf.hasRemaining())
{
return;
}
// apply limit
final int limit = buf.limit();
buf.limit(pos + dataSize);
final ReceivablePacket<T> cp = _packetHandler.handlePacket(buf, client);
if (cp != null)
{
cp._buf = buf;
cp._sbuf = STRING_BUFFER;
cp._client = client;
if (cp.read())
{
_executor.execute(cp);
}
cp._buf = null;
cp._sbuf = null;
}
buf.limit(limit);
}
private final void writeClosePacket(MMOConnection<T> con)
{
SendablePacket<T> sp;
synchronized (con.getSendQueue())
{
if (con.getSendQueue().isEmpty())
{
return;
}
while ((sp = con.getSendQueue().removeFirst()) != null)
{
WRITE_BUFFER.clear();
putPacketIntoWriteBuffer(con.getClient(), sp);
WRITE_BUFFER.flip();
try
{
con.write(WRITE_BUFFER);
}
catch (IOException e)
{
// error handling goes on the if bellow
}
}
}
}
protected final void writePacket(SelectionKey key, MMOConnection<T> con)
{
if (!prepareWriteBuffer(con))
{
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
return;
}
DIRECT_WRITE_BUFFER.flip();
final int size = DIRECT_WRITE_BUFFER.remaining();
int result = -1;
try
{
result = con.write(DIRECT_WRITE_BUFFER);
}
catch (IOException e)
{
// error handling goes on the if bellow
}
// check if no error happened
if (result >= 0)
{
// check if we written everything
if (result == size)
{
// complete write
synchronized (con.getSendQueue())
{
if (con.getSendQueue().isEmpty() && !con.hasPendingWriteBuffer())
{
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
}
}
}
else
{
// incomplete write
con.createWriteBuffer(DIRECT_WRITE_BUFFER);
}
}
else
{
con.getClient().onForcedDisconnection();
closeConnectionImpl(key, con);
}
}
private final boolean prepareWriteBuffer(MMOConnection<T> con)
{
boolean hasPending = false;
DIRECT_WRITE_BUFFER.clear();
// if there is pending content add it
if (con.hasPendingWriteBuffer())
{
con.movePendingWriteBufferTo(DIRECT_WRITE_BUFFER);
hasPending = true;
}
if ((DIRECT_WRITE_BUFFER.remaining() > 1) && !con.hasPendingWriteBuffer())
{
final NioNetStackList<SendablePacket<T>> sendQueue = con.getSendQueue();
final T client = con.getClient();
SendablePacket<T> sp;
for (int i = 0; i < MAX_SEND_PER_PASS; i++)
{
synchronized (con.getSendQueue())
{
if (sendQueue.isEmpty())
{
sp = null;
}
else
{
sp = sendQueue.removeFirst();
}
}
if (sp == null)
{
break;
}
hasPending = true;
// put into WriteBuffer
putPacketIntoWriteBuffer(client, sp);
WRITE_BUFFER.flip();
if (DIRECT_WRITE_BUFFER.remaining() < WRITE_BUFFER.limit())
{
con.createWriteBuffer(WRITE_BUFFER);
break;
}
DIRECT_WRITE_BUFFER.put(WRITE_BUFFER);
}
}
return hasPending;
}
private final void putPacketIntoWriteBuffer(T client, SendablePacket<T> sp)
{
WRITE_BUFFER.clear();
// reserve space for the size
final int headerPos = WRITE_BUFFER.position();
final int dataPos = headerPos + HEADER_SIZE;
WRITE_BUFFER.position(dataPos);
// set the write buffer
sp._buf = WRITE_BUFFER;
// set the client.
sp._client = client;
// write content to buffer
sp.write();
// delete the write buffer
sp._buf = null;
// size (inclusive header)
int dataSize = WRITE_BUFFER.position() - dataPos;
WRITE_BUFFER.position(dataPos);
client.encrypt(WRITE_BUFFER, dataSize);
// recalculate size after encryption
dataSize = WRITE_BUFFER.position() - dataPos;
WRITE_BUFFER.position(headerPos);
// write header
WRITE_BUFFER.putShort((short) (dataSize + HEADER_SIZE));
WRITE_BUFFER.position(dataPos + dataSize);
}
final void closeConnection(MMOConnection<T> con)
{
synchronized (_pendingClose)
{
_pendingClose.addLast(con);
}
}
private final void closeConnectionImpl(SelectionKey key, MMOConnection<T> con)
{
try
{
// notify connection
con.getClient().onDisconnection();
}
finally
{
try
{
// close socket and the SocketChannel
con.close();
}
catch (IOException e)
{
// ignore, we are closing anyway
}
finally
{
con.releaseBuffers();
// clear attachment
key.attach(null);
// cancel key
key.cancel();
}
}
}
public final void shutdown()
{
_shutdown = true;
}
protected void closeSelectorThread()
{
for (SelectionKey key : _selector.keys())
{
try
{
key.channel().close();
}
catch (IOException e)
{
// ignore
}
}
try
{
_selector.close();
}
catch (IOException e)
{
// Ignore
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.mmocore;
/**
* @author KenM
* @param <T>
*/
public abstract class SendablePacket<T extends MMOClient<?>>extends AbstractPacket<T>
{
protected final void putInt(int value)
{
_buf.putInt(value);
}
protected final void putDouble(double value)
{
_buf.putDouble(value);
}
protected final void putFloat(float value)
{
_buf.putFloat(value);
}
/**
* Write <B>byte</B> to the buffer. <BR>
* 8bit integer (00)
* @param data
*/
protected final void writeC(boolean data)
{
_buf.put((byte) (data ? 0x01 : 0x00));
}
/**
* Write <B>byte</B> to the buffer. <BR>
* 8bit integer (00)
* @param data
*/
protected final void writeC(int data)
{
_buf.put((byte) data);
}
/**
* Write <B>double</B> to the buffer. <BR>
* 64bit double precision float (00 00 00 00 00 00 00 00)
* @param value
*/
protected final void writeF(double value)
{
_buf.putDouble(value);
}
/**
* Write <B>short</B> to the buffer. <BR>
* 16bit integer (00 00)
* @param value
*/
protected final void writeH(int value)
{
_buf.putShort((short) value);
}
/**
* Write <B>int</B> to the buffer. <BR>
* 32bit integer (00 00 00 00)
* @param value
*/
protected final void writeD(int value)
{
_buf.putInt(value);
}
/**
* Write <B>int</B> to the buffer. <BR>
* 32bit integer (00 00 00 00)
* @param value
*/
protected final void writeD(boolean value)
{
_buf.putInt(value ? 0x01 : 0x00);
}
/**
* Write <B>long</B> to the buffer. <BR>
* 64bit integer (00 00 00 00 00 00 00 00)
* @param value
*/
protected final void writeQ(long value)
{
_buf.putLong(value);
}
/**
* Write <B>byte[]</B> to the buffer. <BR>
* 8bit integer array (00 ...)
* @param data
*/
protected final void writeB(byte[] data)
{
_buf.put(data);
}
/**
* Write <B>String</B> to the buffer.
* @param text
*/
protected final void writeS(String text)
{
if (text != null)
{
final int len = text.length();
for (int i = 0; i < len; i++)
{
_buf.putChar(text.charAt(i));
}
}
_buf.putChar('\000');
}
protected abstract void write();
}

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author KenM * @author KenM
*/ */
public final class AccountKicked extends L2LoginServerPacket public final class AccountKicked implements IOutgoingPacket
{ {
public enum AccountKickedReason public enum AccountKickedReason
{ {
@@ -52,9 +56,11 @@ public final class AccountKicked extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x02); OutgoingPackets.ACCOUNT_KICKED.writeId(packet);
writeD(_reason.getCode()); packet.writeD(_reason.getCode());
return true;
} }
} }

View File

@@ -16,16 +16,15 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import java.util.logging.Logger; import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* Fromat: d d: response * Fromat: d d: response
*/ */
public final class GGAuth extends L2LoginServerPacket public final class GGAuth implements IOutgoingPacket
{ {
static final Logger _log = Logger.getLogger(GGAuth.class.getName());
public static final int SKIP_GG_AUTH_REQUEST = 0x0b;
private final int _response; private final int _response;
public GGAuth(int response) public GGAuth(int response)
@@ -34,13 +33,14 @@ public final class GGAuth extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x0b); OutgoingPackets.GG_AUTH.writeId(packet);
writeD(_response); packet.writeD(_response);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
return true;
} }
} }

View File

@@ -16,7 +16,9 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* <pre> * <pre>
@@ -32,18 +34,13 @@ import com.l2jmobius.loginserver.network.L2LoginClient;
* s: blowfish key * s: blowfish key
* </pre> * </pre>
*/ */
public final class Init extends L2LoginServerPacket public final class Init implements IOutgoingPacket
{ {
private final int _sessionId; private final int _sessionId;
private final byte[] _publicKey; private final byte[] _publicKey;
private final byte[] _blowfishKey; private final byte[] _blowfishKey;
public Init(L2LoginClient client)
{
this(client.getScrambledModulus(), client.getBlowfishKey(), client.getSessionId());
}
public Init(byte[] publickey, byte[] blowfishkey, int sessionId) public Init(byte[] publickey, byte[] blowfishkey, int sessionId)
{ {
_sessionId = sessionId; _sessionId = sessionId;
@@ -52,22 +49,24 @@ public final class Init extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x00); // init packet id OutgoingPackets.INIT.writeId(packet);
writeD(_sessionId); // session id packet.writeD(_sessionId); // session id
writeD(0x0000c621); // protocol revision packet.writeD(0x0000c621); // protocol revision
writeB(_publicKey); // RSA Public Key packet.writeB(_publicKey); // RSA Public Key
// unk GG related? // unk GG related?
writeD(0x29DD954E); packet.writeD(0x29DD954E);
writeD(0x77C39CFC); packet.writeD(0x77C39CFC);
writeD(0x97ADB620); packet.writeD(0x97ADB620);
writeD(0x07BDE0F7); packet.writeD(0x07BDE0F7);
writeB(_blowfishKey); // BlowFish key packet.writeB(_blowfishKey); // BlowFish key
writeC(0x00); // null termination ;) packet.writeC(0x00); // null termination ;)
return true;
} }
} }

View File

@@ -1,27 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.mmocore.SendablePacket;
/**
* @author KenM
*/
public abstract class L2LoginServerPacket extends SendablePacket<L2LoginClient>
{
}

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* Fromat: d d: the failure reason * Fromat: d d: the failure reason
*/ */
public final class LoginFail extends L2LoginServerPacket public final class LoginFail implements IOutgoingPacket
{ {
public enum LoginFailReason public enum LoginFailReason
{ {
@@ -84,9 +88,10 @@ public final class LoginFail extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x01); OutgoingPackets.LOGIN_FAIL.writeId(packet);
writeC(_reason.getCode()); packet.writeC(_reason.getCode());
return true;
} }
} }

View File

@@ -16,7 +16,10 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* <pre> * <pre>
@@ -31,7 +34,7 @@ import com.l2jmobius.loginserver.SessionKey;
* b: 16 bytes - unknown * b: 16 bytes - unknown
* </pre> * </pre>
*/ */
public final class LoginOk extends L2LoginServerPacket public final class LoginOk implements IOutgoingPacket
{ {
private final int _loginOk1, _loginOk2; private final int _loginOk1, _loginOk2;
@@ -42,17 +45,18 @@ public final class LoginOk extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x03); OutgoingPackets.LOGIN_OK.writeId(packet);
writeD(_loginOk1); packet.writeD(_loginOk1);
writeD(_loginOk2); packet.writeD(_loginOk2);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x000003ea); packet.writeD(0x000003ea);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeD(0x00); packet.writeD(0x00);
writeB(new byte[16]); packet.writeB(new byte[16]);
return true;
} }
} }

View File

@@ -16,14 +16,19 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class LoginOtpFail extends L2LoginServerPacket public class LoginOtpFail implements IOutgoingPacket
{ {
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x0D); OutgoingPackets.LOGIN_OPT_FAIL.writeId(packet);
return true;
} }
} }

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class PIAgreementAck extends L2LoginServerPacket public class PIAgreementAck implements IOutgoingPacket
{ {
private final int _accountId; private final int _accountId;
private final int _status; private final int _status;
@@ -31,10 +35,11 @@ public class PIAgreementAck extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x12); OutgoingPackets.PI_AGREEMENT_ACK.writeId(packet);
writeD(_accountId); packet.writeD(_accountId);
writeC(_status); packet.writeC(_status);
return true;
} }
} }

View File

@@ -16,10 +16,14 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* @author UnAfraid * @author UnAfraid
*/ */
public class PIAgreementCheck extends L2LoginServerPacket public class PIAgreementCheck implements IOutgoingPacket
{ {
private final int _accountId; private final int _accountId;
private final int _status; private final int _status;
@@ -31,10 +35,11 @@ public class PIAgreementCheck extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x11); OutgoingPackets.PI_AGREEMENT_CHECK.writeId(packet);
writeD(_accountId); packet.writeD(_accountId);
writeC(_status); packet.writeC(_status);
return true;
} }
} }

View File

@@ -16,11 +16,15 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** /**
* This class ... * This class ...
* @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:11 $ * @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:11 $
*/ */
public final class PlayFail extends L2LoginServerPacket public final class PlayFail implements IOutgoingPacket
{ {
public enum PlayFailReason public enum PlayFailReason
{ {
@@ -85,9 +89,10 @@ public final class PlayFail extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x06); OutgoingPackets.PLAY_FAIL.writeId(packet);
writeC(_reason.getCode()); packet.writeC(_reason.getCode());
return true;
} }
} }

View File

@@ -16,12 +16,12 @@
*/ */
package com.l2jmobius.loginserver.network.serverpackets; package com.l2jmobius.loginserver.network.serverpackets;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.OutgoingPackets;
/** public final class PlayOk implements IOutgoingPacket
*
*/
public final class PlayOk extends L2LoginServerPacket
{ {
private final int _playOk1, _playOk2; private final int _playOk1, _playOk2;
@@ -32,10 +32,11 @@ public final class PlayOk extends L2LoginServerPacket
} }
@Override @Override
protected void write() public boolean write(PacketWriter packet)
{ {
writeC(0x07); OutgoingPackets.PLAY_OK.writeId(packet);
writeD(_playOk1); packet.writeD(_playOk1);
writeD(_playOk2); packet.writeD(_playOk2);
return true;
} }
} }

View File

@@ -23,9 +23,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.loginserver.GameServerTable; import com.l2jmobius.loginserver.GameServerTable;
import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; import com.l2jmobius.loginserver.GameServerTable.GameServerInfo;
import com.l2jmobius.loginserver.network.L2LoginClient; import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.OutgoingPackets;
import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus;
/** /**
@@ -56,7 +59,7 @@ import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus;
* is less than half the maximum. as Normal between half and 4/5<br> * is less than half the maximum. as Normal between half and 4/5<br>
* and Full when there's more than 4/5 of the maximum number of players. * and Full when there's more than 4/5 of the maximum number of players.
*/ */
public final class ServerList extends L2LoginServerPacket public final class ServerList implements IOutgoingPacket
{ {
protected static final Logger _log = Logger.getLogger(ServerList.class.getName()); protected static final Logger _log = Logger.getLogger(ServerList.class.getName());
@@ -82,7 +85,7 @@ public final class ServerList extends L2LoginServerPacket
{ {
try try
{ {
_ip = InetAddress.getByName(gsi.getServerAddress(client.getConnection().getInetAddress())).getAddress(); _ip = InetAddress.getByName(gsi.getServerAddress(client.getConnectionAddress())).getAddress();
} }
catch (UnknownHostException e) catch (UnknownHostException e)
{ {
@@ -119,37 +122,39 @@ public final class ServerList extends L2LoginServerPacket
} }
@Override @Override
public void write() public boolean write(PacketWriter packet)
{ {
writeC(0x04); OutgoingPackets.SERVER_LIST.writeId(packet);
writeC(_servers.size()); packet.writeC(_servers.size());
writeC(_lastServer); packet.writeC(_lastServer);
for (ServerData server : _servers) for (ServerData server : _servers)
{ {
writeC(server._serverId); // server id packet.writeC(server._serverId); // server id
writeC(server._ip[0] & 0xff); packet.writeC(server._ip[0] & 0xff);
writeC(server._ip[1] & 0xff); packet.writeC(server._ip[1] & 0xff);
writeC(server._ip[2] & 0xff); packet.writeC(server._ip[2] & 0xff);
writeC(server._ip[3] & 0xff); packet.writeC(server._ip[3] & 0xff);
writeD(server._port); packet.writeD(server._port);
writeC(server._ageLimit); // Age Limit 0, 15, 18 packet.writeC(server._ageLimit); // Age Limit 0, 15, 18
writeC(server._pvp ? 0x01 : 0x00); packet.writeC(server._pvp ? 0x01 : 0x00);
writeH(server._currentPlayers); packet.writeH(server._currentPlayers);
writeH(server._maxPlayers); packet.writeH(server._maxPlayers);
writeC(server._status == ServerStatus.STATUS_DOWN ? 0x00 : 0x01); packet.writeC(server._status == ServerStatus.STATUS_DOWN ? 0x00 : 0x01);
writeD(server._serverType); // 1: Normal, 2: Relax, 4: Public Test, 8: No Label, 16: Character Creation Restricted, 32: Event, 64: Free packet.writeD(server._serverType); // 1: Normal, 2: Relax, 4: Public Test, 8: No Label, 16: Character Creation Restricted, 32: Event, 64: Free
writeC(server._brackets ? 0x01 : 0x00); packet.writeC(server._brackets ? 0x01 : 0x00);
} }
writeH(0xA4); // unknown packet.writeH(0xA4); // unknown
if (_charsOnServers != null) if (_charsOnServers != null)
{ {
for (ServerData server : _servers) for (ServerData server : _servers)
{ {
writeC(server._serverId); packet.writeC(server._serverId);
writeC(_charsOnServers.getOrDefault(server._serverId, 0)); packet.writeC(_charsOnServers.getOrDefault(server._serverId, 0));
} }
} }
return true;
} }
} }

View File

@@ -24,13 +24,11 @@ import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.l2jmobius.loginserver.network.mmocore.IAcceptFilter;
/** /**
* IPv4 filter. * IPv4 filter.
* @author Forsaiken * @author Forsaiken
*/ */
public class IPv4Filter implements IAcceptFilter, Runnable public class IPv4Filter implements Runnable
{ {
protected final Logger _log = Logger.getLogger(getClass().getName()); protected final Logger _log = Logger.getLogger(getClass().getName());
@@ -66,7 +64,6 @@ public class IPv4Filter implements IAcceptFilter, Runnable
} }
} }
@Override
public boolean accept(SocketChannel sc) public boolean accept(SocketChannel sc)
{ {
final InetAddress addr = sc.socket().getInetAddress(); final InetAddress addr = sc.socket().getInetAddress();

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -12,11 +12,11 @@
# Networking # Networking
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Bind ip of the LoginServer, use * to bind on all available IPs # Bind ip of the LoginServer, use 0.0.0.0 to bind on all available IPs
# WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u> # WARNING: <u><b><font color="red">Please don't change default IPs here if you don't know what are you doing!</font></b></u>
# WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u> # WARNING: <u><b><font color="red">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u>
# Default: * (0.0.0.0) # Default: 0.0.0.0
LoginserverHostname = * LoginserverHostname = 0.0.0.0
# Default: 2106 # Default: 2106
LoginserverPort = 2106 LoginserverPort = 2106

View File

@@ -1,26 +0,0 @@
#---------------------------------------------------------------
# MMO
#---------------------------------------------------------------
# Sleep time for all Selectors
# After he finished his job the Selector waits the given time in milliseconds
# Lower values will speed up the loop and the Ping is smaller
SleepTime = 20
# Every loop it send a maximum of the given packages to each connection
# Lower values will speed up the loop and the Ping is smaller but cause less output
# Default: 12
MaxSendPerPass = 60
# Every loop it read a maximum of the given packages from each connection
# Lower values will speed up the loop and the Ping is smaller but cause less input
# Default: 12
MaxReadPerPass = 60
# Each unfinished read/write need a TEMP storage Buffer
# on large player amount we need more Buffers
# if there are not enough buffers new ones are generated but not stored for future usage
HelperBufferCount = 20
# Setting this to True will lower your ping, at the cost of an increase in bandwidth consumption.
TcpNoDelay = True

View File

@@ -92,7 +92,6 @@ public final class Config
public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; public static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini"; public static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; public static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
public static final String MMO_CONFIG_FILE = "./config/MMO.ini";
public static final String NPC_CONFIG_FILE = "./config/NPC.ini"; public static final String NPC_CONFIG_FILE = "./config/NPC.ini";
public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini"; public static final String OLYMPIAD_CONFIG_FILE = "./config/Olympiad.ini";
public static final String PVP_CONFIG_FILE = "./config/PVP.ini"; public static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -1785,15 +1784,6 @@ public final class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
// Load IdFactory config file (if exists) // Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE); final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
@@ -2885,7 +2875,7 @@ public final class Config
GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1"); GAME_SERVER_LOGIN_HOST = ServerSettings.getString("LoginHostname", "127.0.0.1");
GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013); GAME_SERVER_LOGIN_PORT = ServerSettings.getInt("LoginPort", 9013);
LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "*"); LOGIN_BIND_ADDRESS = ServerSettings.getString("LoginserverHostname", "0.0.0.0");
PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106); PORT_LOGIN = ServerSettings.getInt("LoginserverPort", 2106);
try try
@@ -2923,15 +2913,6 @@ public final class Config
NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700); NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700);
FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350); FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350);
MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50); MAX_CONNECTION_PER_IP = ServerSettings.getInt("MaxConnectionPerIP", 50);
// MMO
final PropertiesParser mmoSettings = new PropertiesParser(MMO_CONFIG_FILE);
MMO_SELECTOR_SLEEP_TIME = mmoSettings.getInt("SleepTime", 20);
MMO_MAX_SEND_PER_PASS = mmoSettings.getInt("MaxSendPerPass", 12);
MMO_MAX_READ_PER_PASS = mmoSettings.getInt("MaxReadPerPass", 12);
MMO_HELPER_BUFFER_COUNT = mmoSettings.getInt("HelperBufferCount", 20);
MMO_TCP_NODELAY = mmoSettings.getBoolean("TcpNoDelay", false);
} }
else else
{ {

Some files were not shown because too many files have changed in this diff Show More