Files
l2j_mobius/L2J_Mobius_C4/java/com/l2jmobius/loginserver/GameServerTable.java

595 lines
13 KiB
Java

/*
* 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.io.FileInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.spec.RSAKeyGenParameterSpec;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.L2DatabaseFactory;
import com.l2jmobius.loginserver.network.L2LoginClient;
import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus;
import com.l2jmobius.loginserver.network.serverpackets.ServerList;
import com.l2jmobius.util.Rnd;
import com.l2jmobius.util.Util;
import javolution.io.UTF8StreamReader;
import javolution.xml.stream.XMLStreamConstants;
import javolution.xml.stream.XMLStreamReaderImpl;
public class GameServerTable
{
protected static Logger _log = Logger.getLogger(GameServerTable.class.getName());
private static GameServerTable _instance;
private final List<GameServer> _gameServerList = new ArrayList<>();
public Map<Integer, String> serverNames = new HashMap<>();
private static final int KEYS_SIZE = 10;
private KeyPair[] _keyPairs;
public static void load() throws GeneralSecurityException
{
synchronized (GameServerTable.class)
{
if (_instance == null)
{
_instance = new GameServerTable();
}
else
{
throw new IllegalStateException("Load can only be invoked a single time.");
}
}
}
public static GameServerTable getInstance()
{
return _instance;
}
public GameServerTable() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
{
loadServerNames();
loadRegisteredGameServers();
loadRSAKeys();
}
public void shutDown()
{
for (final GameServer gs : _gameServerList)
{
if (gs.gst != null)
{
gs.gst.interrupt();
}
}
}
private void loadRSAKeys() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
{
final KeyPairGenerator _keyGen = KeyPairGenerator.getInstance("RSA");
final RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(512, RSAKeyGenParameterSpec.F4);
_keyGen.initialize(spec);
_keyPairs = new KeyPair[KEYS_SIZE];
for (int i = 0; i < 10; i++)
{
_keyPairs[i] = _keyGen.generateKeyPair();
}
_log.info("Cached " + _keyPairs.length + " RSA keys for Game Server communication.");
}
public void loadRegisteredGameServers()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM gameservers");
ResultSet rset = statement.executeQuery())
{
while (rset.next())
{
_gameServerList.add(new GameServer(stringToHex(rset.getString("hexid")), rset.getInt("server_id")));
}
_log.info("Loaded " + _gameServerList.size() + " registered Game Servers.");
}
catch (final Exception e)
{
_log.warning("Error while loading Server List from gameservers table.");
e.printStackTrace();
}
}
/**
*
*/
private void loadServerNames()
{
try (InputStream in = new FileInputStream("data/servername.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"))
{
final Integer id = new Integer(xpp.getAttributeValue(null, "id").toString());
final String name = xpp.getAttributeValue(null, "name").toString();
serverNames.put(id, name);
}
}
}
xpp.close();
_log.info("Loaded " + serverNames.size() + " server names.");
}
catch (final Exception e)
{
_log.info(getClass().getSimpleName() + ": Cannot load servername.xml!");
}
}
/**
* @param string
* @return
*/
private byte[] stringToHex(String string)
{
return new BigInteger(string, 16).toByteArray();
}
private String hexToString(byte[] hex)
{
if (hex == null)
{
return null;
}
return new BigInteger(hex).toString(16);
}
public void setServerReallyDown(int id)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == id)
{
gs.ip = null;
gs.internal_ip = null;
gs.port = 0;
gs.gst = null;
}
}
}
public GameServerThread getGameServerThread(int ServerID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == ServerID)
{
return gs.gst;
}
}
return null;
}
public int getGameServerStatus(int ServerID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == ServerID)
{
return gs.status;
}
}
return -1;
}
public void addServer(GameServerThread gst)
{
final GameServer gameServer = new GameServer(gst);
GameServer toReplace = null;
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == gst.getServerID())
{
toReplace = gs;
}
}
if (toReplace != null)
{
_gameServerList.remove(toReplace);
}
_gameServerList.add(gameServer);
orderList();
if (Config.DEBUG)
{
for (final GameServer gs : _gameServerList)
{
_log.info(gs.toString());
}
}
gst.setAuthed(true);
}
public int getServerIDforHex(byte[] hex)
{
for (final GameServer gs : _gameServerList)
{
if (Arrays.equals(hex, gs.hexID))
{
return gs.server_id;
}
}
return 0;
}
public boolean isIDfree(int id)
{
for (final GameServer gs : _gameServerList)
{
if ((gs.server_id == id) && (gs.hexID != null))
{
return false;
}
}
return true;
}
public void createServer(GameServer gs)
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO gameservers (hexid,server_id,host) values (?,?,?)"))
{
statement.setString(1, hexToString(gs.hexID));
statement.setInt(2, gs.server_id);
if (gs.gst != null)
{
statement.setString(3, gs.gst.getGameExternalHost());
}
else
{
statement.setString(3, "*");
}
statement.executeUpdate();
}
catch (final SQLException e)
{
_log.warning("SQL error while saving gameserver :" + e);
}
}
public boolean isARegisteredServer(byte[] hex)
{
for (final GameServer gs : _gameServerList)
{
if (Arrays.equals(hex, gs.hexID))
{
return true;
}
}
return false;
}
public int findFreeID()
{
for (int i = 0; i < 128; i++)
{
if (isIDfree(i))
{
return i;
}
}
return 0;
}
public void deleteServer(int id)
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM gameservers WHERE gameservers.server_id=?"))
{
statement.setInt(1, id);
statement.executeUpdate();
}
catch (final SQLException e)
{
_log.warning("SQL error while deleting gameserver :" + e);
}
}
public void createServerList(L2LoginClient client)
{
orderList();
final ServerList list = new ServerList(client.getLastServer());
for (final GameServer gs : _gameServerList)
{
int status = gs.status;
String gameIp = gs.ip;
if (Util.isInternalIP(client.getSocket().getInetAddress().getHostAddress()))
{
gameIp = gs.internal_ip;
}
if (status == ServerStatus.STATUS_AUTO)
{
if (gameIp == null)
{
status = ServerStatus.STATUS_DOWN;
}
}
else if (status == ServerStatus.STATUS_GM_ONLY)
{
if (client.getAccessLevel() < Config.GM_MIN)
{
status = ServerStatus.STATUS_DOWN;
}
else
{
if (gameIp == null)
{
status = ServerStatus.STATUS_DOWN;
}
}
}
list.addServer(gameIp, gs, status);
}
// send server list to client
client.sendPacket(list);
}
/**
*
*/
private void orderList()
{
Collections.sort(_gameServerList, gsComparator);
}
private final Comparator<GameServer> gsComparator = (gs1, gs2) -> (gs1.server_id < gs2.server_id ? -1 : gs1.server_id == gs2.server_id ? 0 : 1);
/**
* @param thread
*/
public void createServer(GameServerThread thread)
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO gameservers (hexid,server_id,host) values (?,?,?)"))
{
statement.setString(1, hexToString(thread.getHexID()));
statement.setInt(2, thread.getServerID());
statement.setString(3, thread.getGameExternalHost());
statement.executeUpdate();
}
catch (final SQLException e)
{
_log.warning("SQL error while saving gameserver :" + e);
}
}
/**
* @param value
* @param serverID
*/
public void setMaxPlayers(int value, int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
gs.maxPlayers = value;
gs.gst.setMaxPlayers(value);
}
}
}
/**
* @param b
* @param serverID
*/
public void setBracket(boolean b, int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
gs.brackets = b;
}
}
}
/**
* @param b
* @param serverID
*/
public void setClock(boolean b, int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
gs.clock = b;
}
}
}
/**
* @param b
* @param serverID
*/
public void setTestServer(boolean b, int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
gs.testServer = b;
}
}
}
/**
* @param value
* @param serverID
*/
public void setStatus(int value, int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
gs.status = value;
if (Config.DEBUG)
{
_log.info("Status Changed for server " + serverID);
}
}
}
}
public boolean isServerAuthed(int serverID)
{
for (final GameServer gs : _gameServerList)
{
if (gs.server_id == serverID)
{
if ((gs.ip != null) && (gs.gst != null) && gs.gst.isAuthed())
{
return true;
}
}
}
return false;
}
public List<String> status()
{
final List<String> str = new ArrayList<>();
str.add("There are " + _gameServerList.size() + " GameServers");
for (final GameServer gs : _gameServerList)
{
str.add(gs.toString());
}
return str;
}
public KeyPair getKeyPair()
{
return _keyPairs[Rnd.nextInt(10)];
}
public List<GameServer> getGameServerList()
{
return _gameServerList;
}
public class GameServer
{
public String ip;
public int server_id;
public int port;
public boolean pvp = true;
public boolean testServer = false;
public int maxPlayers;
public byte[] hexID;
public GameServerThread gst;
public boolean brackets = false;
public boolean clock = false;
public int status = ServerStatus.STATUS_AUTO;
public String internal_ip;
GameServer(GameServerThread gamest)
{
gst = gamest;
ip = gst.getGameExternalIP();
port = gst.getPort();
pvp = gst.getPvP();
testServer = gst.isTestServer();
maxPlayers = gst.getMaxPlayers();
hexID = gst.getHexID();
server_id = gst.getServerID();
internal_ip = gst.getGameInternalIP();
}
@Override
public String toString()
{
return "GameServer: " + serverNames.get(server_id) + " id:" + server_id + " hex:" + hexToString(hexID) + " ip:" + ip + ":" + port + " status: " + ServerStatus.statusString[status];
}
private String hexToString(byte[] hex)
{
if (hex == null)
{
return null;
}
return new BigInteger(hex).toString(16);
}
public GameServer(byte[] hex, int id)
{
hexID = hex;
server_id = id;
}
public GameServer(int id)
{
server_id = id;
}
}
}