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
# ---------------------------------------------------------------------------
# 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">External/Internal IPs are now inside "ipconfig.xml" file.</font></b></u>
# Default: * (0.0.0.0)
LoginserverHostname = *
# Default: 0.0.0.0
LoginserverHostname = 0.0.0.0
# Default: 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 IDFACTORY_CONFIG_FILE = "./config/IdFactory.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 OLYMPIAD_CONFIG_FILE = "./config/Olympiad.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_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)
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_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);
try
@@ -2906,15 +2896,6 @@ public final class Config
NORMAL_CONNECTION_TIME = ServerSettings.getInt("NormalConnectionTime", 700);
FAST_CONNECTION_TIME = ServerSettings.getInt("FastConnectionTime", 350);
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
{

View File

@@ -16,14 +16,17 @@
*/
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 io.netty.buffer.ByteBuf;
/**
* @author KenM
* @author NosBit
*/
public class LoginCrypt
public class LoginCrypt implements ICrypt
{
private static final byte[] STATIC_BLOWFISH_KEY =
{
@@ -45,82 +48,102 @@ public class LoginCrypt
(byte) 0x6c
};
private static final NewCrypt _STATIC_CRYPT = new NewCrypt(STATIC_BLOWFISH_KEY);
private NewCrypt _crypt = null;
private static final BlowfishEngine STATIC_BLOWFISH_ENGINE = new BlowfishEngine();
static
{
STATIC_BLOWFISH_ENGINE.init(STATIC_BLOWFISH_KEY);
}
private final BlowfishEngine _blowfishEngine = new BlowfishEngine();
private boolean _static = true;
/**
* 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)
public LoginCrypt(SecretKey blowfishKey)
{
_crypt = new NewCrypt(key);
_blowfishEngine.init(blowfishKey.getEncoded());
}
/**
* Method to decrypt an incoming login client packet.
* @param raw array with encrypted data
* @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
/*
* (non-Javadoc)
* @see com.l2jserver.commons.network.ICrypt#encrypt(io.netty.buffer.ByteBuf)
*/
public boolean decrypt(byte[] raw, int offset, int size) throws IOException
@Override
public void encrypt(ByteBuf buf)
{
if ((size % 8) != 0)
{
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");
}
// Checksum & XOR Key or Checksum only
buf.writeZero(_static ? 16 : 12);
_crypt.decrypt(raw, offset, size);
return NewCrypt.verifyChecksum(raw, offset, size);
}
/**
* 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;
// Padding
buf.writeZero(8 - (buf.readableBytes() % 8));
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;
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
{
// padding
size += 8 - (size % 8);
if ((offset + size) > raw.length)
int checksum = 0;
while (buf.isReadable(8))
{
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;
}
public byte[] getScrambledModulus()
{
return _scrambledModulus;
}
}

View File

@@ -65,7 +65,7 @@ public final class GameServerTable implements IGameXmlReader
load();
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();
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();
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

View File

@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.logging.Level;
@@ -32,10 +31,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.Server;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.L2LoginPacketHandler;
import com.l2jmobius.loginserver.network.mmocore.SelectorConfig;
import com.l2jmobius.loginserver.network.mmocore.SelectorThread;
import com.l2jmobius.loginserver.network.ClientNetworkManager;
/**
* @author KenM
@@ -47,10 +43,9 @@ public final class L2LoginServer
public static final int PROTOCOL_REV = 0x0106;
private static L2LoginServer _instance;
private GameServerListener _gameServerListener;
private SelectorThread<L2LoginClient> _selectorThread;
private Thread _restartLoginServer;
public static void main(String[] args)
public static void main(String[] args) throws Exception
{
new L2LoginServer();
}
@@ -60,7 +55,7 @@ public final class L2LoginServer
return _instance;
}
private L2LoginServer()
private L2LoginServer() throws Exception
{
_instance = this;
Server.serverMode = Server.MODE_LOGINSERVER;
@@ -105,37 +100,6 @@ public final class L2LoginServer
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
{
_gameServerListener = new GameServerListener();
@@ -148,17 +112,7 @@ public final class L2LoginServer
System.exit(1);
}
try
{
_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);
}
ClientNetworkManager.getInstance().start();
}
public GameServerListener getGameServerListener()

View File

@@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAKeyGenParameterSpec;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -37,7 +36,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import com.l2jmobius.Config;
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, Long> _bannedIps = new ConcurrentHashMap<>();
protected ScrambledKeyPair[] _keyPairs;
protected byte[][] _blowfishKeys;
private static final int BLOWFISH_KEYS = 20;
private final ScrambledKeyPair[] _keyPairs;
private final KeyGenerator _blowfishKeyGenerator;
// 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=?";
@@ -83,62 +81,26 @@ public class LoginController
_log.info("Loading LoginController...");
_keyPairs = new ScrambledKeyPair[10];
final KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
_blowfishKeyGenerator = KeyGenerator.getInstance("Blowfish");
final KeyPairGenerator rsaKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
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 < 10; i++)
for (int i = 0; i < _keyPairs.length; 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());
// Store keys for blowfish communication
generateBlowFishKeys();
_log.info("Cached 10 KeyPairs for RSA communication.");
final Thread purge = new PurgeThread();
purge.setDaemon(true);
purge.start();
}
/**
* 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
public SecretKey generateBlowfishKey()
{
// avoid worst-case execution, KenM
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)];
return _blowfishKeyGenerator.generateKey();
}
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
* 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.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
* 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;
private final int _size;
private int _len;
public NioNetStringBuffer(int size)
protected ClientNetworkManager()
{
_buf = new char[size];
_size = size;
_len = 0;
super(EventLoopGroupManager.getInstance().getBossGroup(), EventLoopGroupManager.getInstance().getWorkerGroup(), new ClientInitializer(), Config.LOGIN_BIND_ADDRESS, Config.PORT_LOGIN);
}
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)
{
_buf[_len++] = c;
}
else
{
throw new BufferOverflowException();
}
}
@Override
public final String toString()
{
return new String(_buf, 0, _len);
protected static final ClientNetworkManager _instance = new ClientNetworkManager();
}
}

View File

@@ -14,13 +14,16 @@
* 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;
package com.l2jmobius.loginserver.network;
import com.l2jmobius.commons.network.IConnectionState;
/**
* @author KenM
* @param <T>
* @author Mobius
*/
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;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.net.InetSocketAddress;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;
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.crypt.LoginCrypt;
import com.l2jmobius.commons.util.crypt.ScrambledKeyPair;
import com.l2jmobius.loginserver.LoginController;
import com.l2jmobius.loginserver.SessionKey;
import com.l2jmobius.loginserver.network.mmocore.MMOClient;
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.Init;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail;
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
* @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());
public enum LoginClientState
{
CONNECTED,
AUTHED_GG,
AUTHED_LOGIN
}
private LoginClientState _state;
// Crypt
private final LoginCrypt _loginCrypt;
private final ScrambledKeyPair _scrambledPair;
private final byte[] _blowfishKey;
private final SecretKey _blowfishKey;
private InetAddress _addr;
private Channel _channel;
private String _account;
private int _accessLevel;
private int _lastServer;
private SessionKey _sessionKey;
private final int _sessionId;
private int _sessionId;
private boolean _joinedGS;
private Map<Integer, Integer> _charsOnServers;
private Map<Integer, long[]> _charsToDelete;
private final long _connectionStartTime;
private long _connectionStartTime;
/**
* @param con
*/
public L2LoginClient(MMOConnection<L2LoginClient> con)
public L2LoginClient(SecretKey blowfishKey)
{
super(con);
_state = LoginClientState.CONNECTED;
super();
_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();
_connectionStartTime = System.currentTimeMillis();
_loginCrypt = new LoginCrypt();
_loginCrypt.setKey(_blowfishKey);
sendPacket(new Init(_scrambledPair.getScrambledModulus(), _blowfishKey.getEncoded(), _sessionId));
}
@Override
public boolean decrypt(ByteBuffer buf, int size)
public void channelInactive(ChannelHandlerContext ctx)
{
boolean isChecksumValid = false;
try
if (!hasJoinedGS() || ((getConnectionStartTime() + LoginController.LOGIN_TIMEOUT) < System.currentTimeMillis()))
{
isChecksumValid = _loginCrypt.decrypt(buf.array(), buf.position(), size);
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;
LoginController.getInstance().removeAuthedLoginClient(getAccount());
}
}
@Override
public boolean encrypt(ByteBuffer buf, int size)
protected void channelRead0(ChannelHandlerContext ctx, IIncomingPacket<L2LoginClient> packet)
{
final int offset = buf.position();
try
{
size = _loginCrypt.encrypt(buf.array(), offset, size);
packet.run(this);
}
catch (IOException e)
catch (Exception e)
{
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
return false;
}
buf.position(offset + size);
return true;
}
public LoginClientState getState()
public InetAddress getConnectionAddress()
{
return _state;
}
public void setState(LoginClientState state)
{
_state = state;
}
public byte[] getBlowfishKey()
{
return _blowfishKey;
return _addr;
}
public byte[] getScrambledModulus()
@@ -209,24 +185,39 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
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)
{
getConnection().close(new LoginFail(reason));
close(new LoginFail(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)
@@ -256,30 +247,4 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
{
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;
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.LoginFail.LoginFailReason;
@@ -24,65 +27,39 @@ import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason
* Format: ddddd
* @author -Wooden-
*/
public class AuthGameGuard extends L2LoginClientPacket
public class AuthGameGuard implements IIncomingPacket<L2LoginClient>
{
private int _sessionId;
private int _data1;
private int _data2;
private int _data3;
private int _data4;
public int getSessionId()
{
return _sessionId;
}
public int getData1()
{
return _data1;
}
public int getData2()
{
return _data2;
}
public int getData3()
{
return _data3;
}
public int getData4()
{
return _data4;
}
@SuppressWarnings("unused")
private int _data1, _data2, _data3, _data4;
@Override
protected boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
if (super._buf.remaining() >= 20)
if (packet.getReadableBytes() >= 20)
{
_sessionId = readD();
_data1 = readD();
_data2 = readD();
_data3 = readD();
_data4 = readD();
_sessionId = packet.readD();
_data1 = packet.readD();
_data2 = packet.readD();
_data3 = packet.readD();
_data4 = packet.readD();
return true;
}
return false;
}
@Override
public void run()
public void run(L2LoginClient client)
{
if (_sessionId == getClient().getSessionId())
if (_sessionId == client.getSessionId())
{
getClient().setState(LoginClientState.AUTHED_GG);
getClient().sendPacket(new GGAuth(getClient().getSessionId()));
client.setConnectionState(ConnectionState.AUTHED_GG);
client.sendPacket(new GGAuth(client.getSessionId()));
}
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 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.LoginController;
import com.l2jmobius.loginserver.LoginController.AuthLoginResult;
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.LoginClientState;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked;
import com.l2jmobius.loginserver.network.serverpackets.AccountKicked.AccountKickedReason;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
@@ -42,7 +44,7 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
*
* <pre>
*/
public class RequestAuthLogin extends L2LoginClientPacket
public class RequestAuthLogin implements IIncomingPacket<L2LoginClient>
{
private static Logger _log = Logger.getLogger(RequestAuthLogin.class.getName());
@@ -53,45 +55,28 @@ public class RequestAuthLogin extends L2LoginClientPacket
private String _user;
private String _password;
/**
* @return
*/
public String getPassword()
{
return _password;
}
/**
* @return
*/
public String getUser()
{
return _user;
}
@Override
public boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
if (super._buf.remaining() >= 256)
if (packet.getReadableBytes() >= 256)
{
_newAuthMethod = true;
readB(_raw1);
readB(_raw2);
packet.readB(_raw1, 0, _raw1.length);
packet.readB(_raw2, 0, _raw2.length);
return true;
}
else if (super._buf.remaining() >= 128)
else if (packet.getReadableBytes() >= 128)
{
readB(_raw1);
packet.readB(_raw1, 0, _raw1.length);
return true;
}
return false;
}
@Override
public void run()
public void run(L2LoginClient client)
{
final L2LoginClient client = getClient();
final byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
byte[] decrypted = new byte[_newAuthMethod ? 256 : 128];
try
{
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
@@ -127,7 +112,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
return;
}
final InetAddress clientAddr = client.getConnection().getInetAddress();
final InetAddress clientAddr = client.getConnectionAddress();
final LoginController lc = LoginController.getInstance();
final AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password);
if (info == null)
@@ -143,7 +128,7 @@ public class RequestAuthLogin extends L2LoginClientPacket
case AUTH_SUCCESS:
{
client.setAccount(info.getLogin());
client.setState(LoginClientState.AUTHED_LOGIN);
client.setConnectionState(ConnectionState.AUTHED_LOGIN);
client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client));
lc.getCharactersOnAccount(info.getLogin());
if (Config.SHOW_LICENCE)

View File

@@ -16,27 +16,30 @@
*/
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;
/**
* @author UnAfraid
*/
public class RequestPIAgreement extends L2LoginClientPacket
public class RequestPIAgreement implements IIncomingPacket<L2LoginClient>
{
private int _accountId;
private int _status;
@Override
protected boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
_accountId = readD();
_status = readC();
_accountId = packet.readD();
_status = packet.readC();
return true;
}
@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;
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;
/**
* @author UnAfraid
*/
public class RequestPIAgreementCheck extends L2LoginClientPacket
public class RequestPIAgreementCheck implements IIncomingPacket<L2LoginClient>
{
private int _accountId;
@Override
protected boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
_accountId = readD();
final byte[] padding0 = new byte[3];
final byte[] checksum = new byte[4];
final byte[] padding1 = new byte[12];
readB(padding0);
readB(checksum);
readB(padding1);
_accountId = packet.readD();
byte[] padding0 = new byte[3];
byte[] checksum = new byte[4];
byte[] padding1 = new byte[12];
packet.readB(padding0, 0, padding0.length);
packet.readB(checksum, 0, checksum.length);
packet.readB(padding1, 0, padding1.length);
return true;
}
@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;
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.ServerList;
@@ -27,58 +30,35 @@ import com.l2jmobius.loginserver.network.serverpackets.ServerList;
* c: ?
* </pre>
*/
public class RequestServerList extends L2LoginClientPacket
public class RequestServerList implements IIncomingPacket<L2LoginClient>
{
private int _skey1;
private int _skey2;
@SuppressWarnings("unused")
private int _data3;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getData3()
{
return _data3;
}
@Override
public boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
if (super._buf.remaining() >= 8)
if (packet.getReadableBytes() >= 8)
{
_skey1 = readD(); // loginOk 1
_skey2 = readD(); // loginOk 2
_skey1 = packet.readD(); // loginOk 1
_skey2 = packet.readD(); // loginOk 2
return true;
}
return false;
}
@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
{
getClient().close(LoginFailReason.REASON_ACCESS_FAILED);
client.close(LoginFailReason.REASON_ACCESS_FAILED);
}
}
}

View File

@@ -17,8 +17,11 @@
package com.l2jmobius.loginserver.network.clientpackets;
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.SessionKey;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason;
import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
@@ -31,70 +34,46 @@ import com.l2jmobius.loginserver.network.serverpackets.PlayOk;
* c: server ID
* </pre>
*/
public class RequestServerLogin extends L2LoginClientPacket
public class RequestServerLogin implements IIncomingPacket<L2LoginClient>
{
private int _skey1;
private int _skey2;
private int _serverId;
/**
* @return
*/
public int getSessionKey1()
{
return _skey1;
}
/**
* @return
*/
public int getSessionKey2()
{
return _skey2;
}
/**
* @return
*/
public int getServerID()
{
return _serverId;
}
@Override
public boolean readImpl()
public boolean read(L2LoginClient client, PacketReader packet)
{
if (super._buf.remaining() >= 9)
if (packet.getReadableBytes() >= 9)
{
_skey1 = readD();
_skey2 = readD();
_serverId = readC();
_skey1 = packet.readD();
_skey2 = packet.readD();
_serverId = packet.readC();
return true;
}
return false;
}
@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 (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2))
{
if (LoginController.getInstance().isLoginPossible(getClient(), _serverId))
if (LoginController.getInstance().isLoginPossible(client, _serverId))
{
getClient().setJoinedGS(true);
getClient().sendPacket(new PlayOk(sk));
client.setJoinedGS(true);
client.sendPacket(new PlayOk(sk));
}
else
{
getClient().close(PlayFailReason.REASON_SERVER_OVERLOADED);
client.close(PlayFailReason.REASON_SERVER_OVERLOADED);
}
}
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,26 +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 interface IMMOExecutor<T extends MMOClient<?>>
{
void execute(ReceivablePacket<T> packet);
}

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

View File

@@ -16,16 +16,15 @@
*/
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
*/
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;
public GGAuth(int response)
@@ -34,13 +33,14 @@ public final class GGAuth extends L2LoginServerPacket
}
@Override
protected void write()
public boolean write(PacketWriter packet)
{
writeC(0x0b);
writeD(_response);
writeD(0x00);
writeD(0x00);
writeD(0x00);
writeD(0x00);
OutgoingPackets.GG_AUTH.writeId(packet);
packet.writeD(_response);
packet.writeD(0x00);
packet.writeD(0x00);
packet.writeD(0x00);
packet.writeD(0x00);
return true;
}
}

View File

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

View File

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

View File

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

View File

@@ -16,10 +16,14 @@
*/
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
*/
public class PIAgreementCheck extends L2LoginServerPacket
public class PIAgreementCheck implements IOutgoingPacket
{
private final int _accountId;
private final int _status;
@@ -31,10 +35,11 @@ public class PIAgreementCheck extends L2LoginServerPacket
}
@Override
protected void write()
public boolean write(PacketWriter packet)
{
writeC(0x11);
writeD(_accountId);
writeC(_status);
OutgoingPackets.PI_AGREEMENT_CHECK.writeId(packet);
packet.writeD(_accountId);
packet.writeC(_status);
return true;
}
}

View File

@@ -16,11 +16,15 @@
*/
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 ...
* @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
{
@@ -85,9 +89,10 @@ public final class PlayFail extends L2LoginServerPacket
}
@Override
protected void write()
public boolean write(PacketWriter packet)
{
writeC(0x06);
writeC(_reason.getCode());
OutgoingPackets.PLAY_FAIL.writeId(packet);
packet.writeC(_reason.getCode());
return true;
}
}

View File

@@ -16,12 +16,12 @@
*/
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.network.OutgoingPackets;
/**
*
*/
public final class PlayOk extends L2LoginServerPacket
public final class PlayOk implements IOutgoingPacket
{
private final int _playOk1, _playOk2;
@@ -32,10 +32,11 @@ public final class PlayOk extends L2LoginServerPacket
}
@Override
protected void write()
public boolean write(PacketWriter packet)
{
writeC(0x07);
writeD(_playOk1);
writeD(_playOk2);
OutgoingPackets.PLAY_OK.writeId(packet);
packet.writeD(_playOk1);
packet.writeD(_playOk2);
return true;
}
}

View File

@@ -23,9 +23,12 @@ import java.util.List;
import java.util.Map;
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.GameServerInfo;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.OutgoingPackets;
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>
* 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());
@@ -82,7 +85,7 @@ public final class ServerList extends L2LoginServerPacket
{
try
{
_ip = InetAddress.getByName(gsi.getServerAddress(client.getConnection().getInetAddress())).getAddress();
_ip = InetAddress.getByName(gsi.getServerAddress(client.getConnectionAddress())).getAddress();
}
catch (UnknownHostException e)
{
@@ -119,37 +122,39 @@ public final class ServerList extends L2LoginServerPacket
}
@Override
public void write()
public boolean write(PacketWriter packet)
{
writeC(0x04);
writeC(_servers.size());
writeC(_lastServer);
OutgoingPackets.SERVER_LIST.writeId(packet);
packet.writeC(_servers.size());
packet.writeC(_lastServer);
for (ServerData server : _servers)
{
writeC(server._serverId); // server id
packet.writeC(server._serverId); // server id
writeC(server._ip[0] & 0xff);
writeC(server._ip[1] & 0xff);
writeC(server._ip[2] & 0xff);
writeC(server._ip[3] & 0xff);
packet.writeC(server._ip[0] & 0xff);
packet.writeC(server._ip[1] & 0xff);
packet.writeC(server._ip[2] & 0xff);
packet.writeC(server._ip[3] & 0xff);
writeD(server._port);
writeC(server._ageLimit); // Age Limit 0, 15, 18
writeC(server._pvp ? 0x01 : 0x00);
writeH(server._currentPlayers);
writeH(server._maxPlayers);
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
writeC(server._brackets ? 0x01 : 0x00);
packet.writeD(server._port);
packet.writeC(server._ageLimit); // Age Limit 0, 15, 18
packet.writeC(server._pvp ? 0x01 : 0x00);
packet.writeH(server._currentPlayers);
packet.writeH(server._maxPlayers);
packet.writeC(server._status == ServerStatus.STATUS_DOWN ? 0x00 : 0x01);
packet.writeD(server._serverType); // 1: Normal, 2: Relax, 4: Public Test, 8: No Label, 16: Character Creation Restricted, 32: Event, 64: Free
packet.writeC(server._brackets ? 0x01 : 0x00);
}
writeH(0xA4); // unknown
packet.writeH(0xA4); // unknown
if (_charsOnServers != null)
{
for (ServerData server : _servers)
{
writeC(server._serverId);
writeC(_charsOnServers.getOrDefault(server._serverId, 0));
packet.writeC(server._serverId);
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.logging.Logger;
import com.l2jmobius.loginserver.network.mmocore.IAcceptFilter;
/**
* IPv4 filter.
* @author Forsaiken
*/
public class IPv4Filter implements IAcceptFilter, Runnable
public class IPv4Filter implements Runnable
{
protected final Logger _log = Logger.getLogger(getClass().getName());
@@ -66,7 +64,6 @@ public class IPv4Filter implements IAcceptFilter, Runnable
}
}
@Override
public boolean accept(SocketChannel sc)
{
final InetAddress addr = sc.socket().getInetAddress();