This commit is contained in:
681
trunk/java/com/l2jserver/loginserver/GameServerTable.java
Normal file
681
trunk/java/com/l2jserver/loginserver/GameServerTable.java
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2014 L2J Server
|
||||
*
|
||||
* This file is part of L2J Server.
|
||||
*
|
||||
* L2J Server 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.
|
||||
*
|
||||
* L2J Server 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.l2jserver.loginserver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javolution.io.UTF8StreamReader;
|
||||
import javolution.xml.stream.XMLStreamConstants;
|
||||
import javolution.xml.stream.XMLStreamReaderImpl;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.L2DatabaseFactory;
|
||||
import com.l2jserver.loginserver.network.gameserverpackets.ServerStatus;
|
||||
import com.l2jserver.util.IPSubnet;
|
||||
import com.l2jserver.util.Rnd;
|
||||
|
||||
/**
|
||||
* The Class GameServerTable loads the game server names and initialize the game server tables.
|
||||
* @author KenM, Zoey76
|
||||
*/
|
||||
public final class GameServerTable
|
||||
{
|
||||
private static final Logger _log = Logger.getLogger(GameServerTable.class.getName());
|
||||
// Server Names Config
|
||||
private static final Map<Integer, String> _serverNames = new HashMap<>();
|
||||
// Game Server Table
|
||||
private static final Map<Integer, GameServerInfo> _gameServerTable = new HashMap<>();
|
||||
// RSA Config
|
||||
private static final int KEYS_SIZE = 10;
|
||||
private KeyPair[] _keyPairs;
|
||||
|
||||
/**
|
||||
* Instantiates a new game server table.
|
||||
*/
|
||||
public GameServerTable()
|
||||
{
|
||||
loadGameServerNames();
|
||||
_log.info(getClass().getSimpleName() + ": Loaded " + _serverNames.size() + " server names");
|
||||
|
||||
loadRegisteredGameServers();
|
||||
_log.info(getClass().getSimpleName() + ": Loaded " + _gameServerTable.size() + " registered Game Servers");
|
||||
|
||||
initRSAKeys();
|
||||
_log.info(getClass().getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load game server names.
|
||||
*/
|
||||
private void loadGameServerNames()
|
||||
{
|
||||
final File xml = new File(Config.DATAPACK_ROOT, "data/servername.xml");
|
||||
try (InputStream in = new FileInputStream(xml);
|
||||
UTF8StreamReader utf8 = new UTF8StreamReader())
|
||||
{
|
||||
final XMLStreamReaderImpl xpp = new XMLStreamReaderImpl();
|
||||
xpp.setInput(utf8.setInput(in));
|
||||
for (int e = xpp.getEventType(); e != XMLStreamConstants.END_DOCUMENT; e = xpp.next())
|
||||
{
|
||||
if (e == XMLStreamConstants.START_ELEMENT)
|
||||
{
|
||||
if (xpp.getLocalName().toString().equals("server"))
|
||||
{
|
||||
Integer id = Integer.valueOf(xpp.getAttributeValue(null, "id").toString());
|
||||
String name = xpp.getAttributeValue(null, "name").toString();
|
||||
_serverNames.put(id, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
xpp.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.info(getClass().getSimpleName() + ": Cannot load " + xml.getAbsolutePath() + "!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits the RSA keys.
|
||||
*/
|
||||
private void initRSAKeys()
|
||||
{
|
||||
try
|
||||
{
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyGen.initialize(new RSAKeyGenParameterSpec(512, RSAKeyGenParameterSpec.F4));
|
||||
_keyPairs = new KeyPair[KEYS_SIZE];
|
||||
for (int i = 0; i < KEYS_SIZE; i++)
|
||||
{
|
||||
_keyPairs[i] = keyGen.genKeyPair();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.severe(getClass().getSimpleName() + ": Error loading RSA keys for Game Server communication!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load registered game servers.
|
||||
*/
|
||||
private void loadRegisteredGameServers()
|
||||
{
|
||||
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
||||
Statement ps = con.createStatement();
|
||||
ResultSet rs = ps.executeQuery("SELECT * FROM gameservers"))
|
||||
{
|
||||
int id;
|
||||
while (rs.next())
|
||||
{
|
||||
id = rs.getInt("server_id");
|
||||
_gameServerTable.put(id, new GameServerInfo(id, stringToHex(rs.getString("hexid"))));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.severe(getClass().getSimpleName() + ": Error loading registered game servers!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered game servers.
|
||||
* @return the registered game servers
|
||||
*/
|
||||
public Map<Integer, GameServerInfo> getRegisteredGameServers()
|
||||
{
|
||||
return _gameServerTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered game server by id.
|
||||
* @param id the game server Id
|
||||
* @return the registered game server by id
|
||||
*/
|
||||
public GameServerInfo getRegisteredGameServerById(int id)
|
||||
{
|
||||
return _gameServerTable.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for registered game server on id.
|
||||
* @param id the id
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean hasRegisteredGameServerOnId(int id)
|
||||
{
|
||||
return _gameServerTable.containsKey(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with first available id.
|
||||
* @param gsi the game server information DTO
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean registerWithFirstAvaliableId(GameServerInfo gsi)
|
||||
{
|
||||
// avoid two servers registering with the same "free" id
|
||||
synchronized (_gameServerTable)
|
||||
{
|
||||
for (Entry<Integer, String> entry : _serverNames.entrySet())
|
||||
{
|
||||
if (!_gameServerTable.containsKey(entry.getKey()))
|
||||
{
|
||||
_gameServerTable.put(entry.getKey(), gsi);
|
||||
gsi.setId(entry.getKey());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a game server.
|
||||
* @param id the id
|
||||
* @param gsi the gsi
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean register(int id, GameServerInfo gsi)
|
||||
{
|
||||
// avoid two servers registering with the same id
|
||||
synchronized (_gameServerTable)
|
||||
{
|
||||
if (!_gameServerTable.containsKey(id))
|
||||
{
|
||||
_gameServerTable.put(id, gsi);
|
||||
gsi.setId(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method.
|
||||
* @param gsi the game server info DTO.
|
||||
*/
|
||||
public void registerServerOnDB(GameServerInfo gsi)
|
||||
{
|
||||
registerServerOnDB(gsi.getHexId(), gsi.getId(), gsi.getExternalHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register server on db.
|
||||
* @param hexId the hex id
|
||||
* @param id the id
|
||||
* @param externalHost the external host
|
||||
*/
|
||||
public void registerServerOnDB(byte[] hexId, int id, String externalHost)
|
||||
{
|
||||
register(id, new GameServerInfo(id, hexId));
|
||||
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO gameservers (hexid,server_id,host) values (?,?,?)"))
|
||||
{
|
||||
ps.setString(1, hexToString(hexId));
|
||||
ps.setInt(2, id);
|
||||
ps.setString(3, externalHost);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.severe(getClass().getSimpleName() + ": Error while saving gameserver!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server name by id.
|
||||
* @param id the id
|
||||
* @return the server name by id
|
||||
*/
|
||||
public String getServerNameById(int id)
|
||||
{
|
||||
return _serverNames.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server names.
|
||||
* @return the game server names map.
|
||||
*/
|
||||
public Map<Integer, String> getServerNames()
|
||||
{
|
||||
return _serverNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key pair.
|
||||
* @return a random key pair.
|
||||
*/
|
||||
public KeyPair getKeyPair()
|
||||
{
|
||||
return _keyPairs[Rnd.nextInt(10)];
|
||||
}
|
||||
|
||||
/**
|
||||
* String to hex.
|
||||
* @param string the string to convert.
|
||||
* @return return the hex representation.
|
||||
*/
|
||||
private byte[] stringToHex(String string)
|
||||
{
|
||||
return new BigInteger(string, 16).toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex to string.
|
||||
* @param hex the hex value to convert.
|
||||
* @return the string representation.
|
||||
*/
|
||||
private String hexToString(byte[] hex)
|
||||
{
|
||||
if (hex == null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
return new BigInteger(hex).toString(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class GameServerInfo.
|
||||
*/
|
||||
public static class GameServerInfo
|
||||
{
|
||||
// auth
|
||||
private int _id;
|
||||
private final byte[] _hexId;
|
||||
private boolean _isAuthed;
|
||||
// status
|
||||
private GameServerThread _gst;
|
||||
private int _status;
|
||||
// network
|
||||
private final ArrayList<GameServerAddress> _addrs = new ArrayList<>(5);
|
||||
private int _port;
|
||||
// config
|
||||
private final boolean _isPvp = true;
|
||||
private int _serverType;
|
||||
private int _ageLimit;
|
||||
private boolean _isShowingBrackets;
|
||||
private int _maxPlayers;
|
||||
|
||||
/**
|
||||
* Instantiates a new game server info.
|
||||
* @param id the id
|
||||
* @param hexId the hex id
|
||||
* @param gst the gst
|
||||
*/
|
||||
public GameServerInfo(int id, byte[] hexId, GameServerThread gst)
|
||||
{
|
||||
_id = id;
|
||||
_hexId = hexId;
|
||||
_gst = gst;
|
||||
_status = ServerStatus.STATUS_DOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new game server info.
|
||||
* @param id the id
|
||||
* @param hexId the hex id
|
||||
*/
|
||||
public GameServerInfo(int id, byte[] hexId)
|
||||
{
|
||||
this(id, hexId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id.
|
||||
* @param id the new id
|
||||
*/
|
||||
public void setId(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
* @return the id
|
||||
*/
|
||||
public int getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hex id.
|
||||
* @return the hex id
|
||||
*/
|
||||
public byte[] getHexId()
|
||||
{
|
||||
return _hexId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authed.
|
||||
* @param isAuthed the new authed
|
||||
*/
|
||||
public void setAuthed(boolean isAuthed)
|
||||
{
|
||||
_isAuthed = isAuthed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is authed.
|
||||
* @return true, if is authed
|
||||
*/
|
||||
public boolean isAuthed()
|
||||
{
|
||||
return _isAuthed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game server thread.
|
||||
* @param gst the new game server thread
|
||||
*/
|
||||
public void setGameServerThread(GameServerThread gst)
|
||||
{
|
||||
_gst = gst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the game server thread.
|
||||
* @return the game server thread
|
||||
*/
|
||||
public GameServerThread getGameServerThread()
|
||||
{
|
||||
return _gst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status.
|
||||
* @param status the new status
|
||||
*/
|
||||
public void setStatus(int status)
|
||||
{
|
||||
_status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status.
|
||||
* @return the status
|
||||
*/
|
||||
public int getStatus()
|
||||
{
|
||||
return _status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current player count.
|
||||
* @return the current player count
|
||||
*/
|
||||
public int getCurrentPlayerCount()
|
||||
{
|
||||
if (_gst == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _gst.getPlayerCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the external host.
|
||||
* @return the external host
|
||||
*/
|
||||
public String getExternalHost()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getServerAddress(InetAddress.getByName("0.0.0.0"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the port.
|
||||
* @return the port
|
||||
*/
|
||||
public int getPort()
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port.
|
||||
* @param port the new port
|
||||
*/
|
||||
public void setPort(int port)
|
||||
{
|
||||
_port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max players.
|
||||
* @param maxPlayers the new max players
|
||||
*/
|
||||
public void setMaxPlayers(int maxPlayers)
|
||||
{
|
||||
_maxPlayers = maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max players.
|
||||
* @return the max players
|
||||
*/
|
||||
public int getMaxPlayers()
|
||||
{
|
||||
return _maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is pvp.
|
||||
* @return true, if is pvp
|
||||
*/
|
||||
public boolean isPvp()
|
||||
{
|
||||
return _isPvp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the age limit.
|
||||
* @param val the new age limit
|
||||
*/
|
||||
public void setAgeLimit(int val)
|
||||
{
|
||||
_ageLimit = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the age limit.
|
||||
* @return the age limit
|
||||
*/
|
||||
public int getAgeLimit()
|
||||
{
|
||||
return _ageLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the server type.
|
||||
* @param val the new server type
|
||||
*/
|
||||
public void setServerType(int val)
|
||||
{
|
||||
_serverType = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server type.
|
||||
* @return the server type
|
||||
*/
|
||||
public int getServerType()
|
||||
{
|
||||
return _serverType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the showing brackets.
|
||||
* @param val the new showing brackets
|
||||
*/
|
||||
public void setShowingBrackets(boolean val)
|
||||
{
|
||||
_isShowingBrackets = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is showing brackets.
|
||||
* @return true, if is showing brackets
|
||||
*/
|
||||
public boolean isShowingBrackets()
|
||||
{
|
||||
return _isShowingBrackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the down.
|
||||
*/
|
||||
public void setDown()
|
||||
{
|
||||
setAuthed(false);
|
||||
setPort(0);
|
||||
setGameServerThread(null);
|
||||
setStatus(ServerStatus.STATUS_DOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the server address.
|
||||
* @param subnet the subnet
|
||||
* @param addr the addr
|
||||
* @throws UnknownHostException the unknown host exception
|
||||
*/
|
||||
public void addServerAddress(String subnet, String addr) throws UnknownHostException
|
||||
{
|
||||
_addrs.add(new GameServerAddress(subnet, addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server address.
|
||||
* @param addr the addr
|
||||
* @return the server address
|
||||
*/
|
||||
public String getServerAddress(InetAddress addr)
|
||||
{
|
||||
for (GameServerAddress a : _addrs)
|
||||
{
|
||||
if (a.equals(addr))
|
||||
{
|
||||
return a.getServerAddress();
|
||||
}
|
||||
}
|
||||
return null; // should not happens
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server addresses.
|
||||
* @return the server addresses
|
||||
*/
|
||||
public String[] getServerAddresses()
|
||||
{
|
||||
String[] result = new String[_addrs.size()];
|
||||
for (int i = 0; i < result.length; i++)
|
||||
{
|
||||
result[i] = _addrs.get(i).toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear server addresses.
|
||||
*/
|
||||
public void clearServerAddresses()
|
||||
{
|
||||
_addrs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class GameServerAddress.
|
||||
*/
|
||||
private class GameServerAddress extends IPSubnet
|
||||
{
|
||||
private final String _serverAddress;
|
||||
|
||||
/**
|
||||
* Instantiates a new game server address.
|
||||
* @param subnet the subnet
|
||||
* @param address the address
|
||||
* @throws UnknownHostException the unknown host exception
|
||||
*/
|
||||
public GameServerAddress(String subnet, String address) throws UnknownHostException
|
||||
{
|
||||
super(subnet);
|
||||
_serverAddress = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server address.
|
||||
* @return the server address
|
||||
*/
|
||||
public String getServerAddress()
|
||||
{
|
||||
return _serverAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _serverAddress + super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single instance of GameServerTable.
|
||||
* @return single instance of GameServerTable
|
||||
*/
|
||||
public static GameServerTable getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Class SingletonHolder.
|
||||
*/
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final GameServerTable _instance = new GameServerTable();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user