GameServerTable.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.loginserver;
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.InputStream;
  19. import java.math.BigInteger;
  20. import java.net.InetAddress;
  21. import java.net.UnknownHostException;
  22. import java.security.KeyPair;
  23. import java.security.KeyPairGenerator;
  24. import java.security.spec.RSAKeyGenParameterSpec;
  25. import java.sql.Connection;
  26. import java.sql.PreparedStatement;
  27. import java.sql.ResultSet;
  28. import java.sql.Statement;
  29. import java.util.ArrayList;
  30. import java.util.HashMap;
  31. import java.util.Map;
  32. import java.util.Map.Entry;
  33. import java.util.logging.Logger;
  34. import javolution.io.UTF8StreamReader;
  35. import javolution.xml.stream.XMLStreamConstants;
  36. import javolution.xml.stream.XMLStreamReaderImpl;
  37. import com.l2jserver.Config;
  38. import com.l2jserver.L2DatabaseFactory;
  39. import com.l2jserver.loginserver.network.gameserverpackets.ServerStatus;
  40. import com.l2jserver.util.IPSubnet;
  41. import com.l2jserver.util.Rnd;
  42. /**
  43. * The Class GameServerTable loads the game server names and initialize the game server tables.
  44. * @author KenM, Zoey76
  45. */
  46. public final class GameServerTable
  47. {
  48. private static final Logger _log = Logger.getLogger(GameServerTable.class.getName());
  49. // Server Names Config
  50. private static final Map<Integer, String> _serverNames = new HashMap<>();
  51. // Game Server Table
  52. private static final Map<Integer, GameServerInfo> _gameServerTable = new HashMap<>();
  53. // RSA Config
  54. private static final int KEYS_SIZE = 10;
  55. private KeyPair[] _keyPairs;
  56. /**
  57. * Instantiates a new game server table.
  58. */
  59. public GameServerTable()
  60. {
  61. loadGameServerNames();
  62. _log.info(getClass().getSimpleName() + ": Loaded " + _serverNames.size() + " server names");
  63. loadRegisteredGameServers();
  64. _log.info(getClass().getSimpleName() + ": Loaded " + _gameServerTable.size() + " registered Game Servers");
  65. initRSAKeys();
  66. _log.info(getClass().getSimpleName() + ": Cached " + _keyPairs.length + " RSA keys for Game Server communication.");
  67. }
  68. /**
  69. * Load game server names.
  70. */
  71. private void loadGameServerNames()
  72. {
  73. final File xml = new File(Config.DATAPACK_ROOT, "data/servername.xml");
  74. try (InputStream in = new FileInputStream(xml);
  75. UTF8StreamReader utf8 = new UTF8StreamReader())
  76. {
  77. final XMLStreamReaderImpl xpp = new XMLStreamReaderImpl();
  78. xpp.setInput(utf8.setInput(in));
  79. for (int e = xpp.getEventType(); e != XMLStreamConstants.END_DOCUMENT; e = xpp.next())
  80. {
  81. if (e == XMLStreamConstants.START_ELEMENT)
  82. {
  83. if (xpp.getLocalName().toString().equals("server"))
  84. {
  85. Integer id = Integer.valueOf(xpp.getAttributeValue(null, "id").toString());
  86. String name = xpp.getAttributeValue(null, "name").toString();
  87. _serverNames.put(id, name);
  88. }
  89. }
  90. }
  91. xpp.close();
  92. }
  93. catch (Exception e)
  94. {
  95. _log.info(getClass().getSimpleName() + ": Cannot load " + xml.getAbsolutePath() + "!");
  96. }
  97. }
  98. /**
  99. * Inits the RSA keys.
  100. */
  101. private void initRSAKeys()
  102. {
  103. try
  104. {
  105. final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
  106. keyGen.initialize(new RSAKeyGenParameterSpec(512, RSAKeyGenParameterSpec.F4));
  107. _keyPairs = new KeyPair[KEYS_SIZE];
  108. for (int i = 0; i < KEYS_SIZE; i++)
  109. {
  110. _keyPairs[i] = keyGen.genKeyPair();
  111. }
  112. }
  113. catch (Exception e)
  114. {
  115. _log.severe(getClass().getSimpleName() + ": Error loading RSA keys for Game Server communication!");
  116. }
  117. }
  118. /**
  119. * Load registered game servers.
  120. */
  121. private void loadRegisteredGameServers()
  122. {
  123. Connection con = null;
  124. try
  125. {
  126. con = L2DatabaseFactory.getInstance().getConnection();
  127. try (Statement ps = con.createStatement();
  128. ResultSet rs = ps.executeQuery("SELECT * FROM gameservers"))
  129. {
  130. int id;
  131. while (rs.next())
  132. {
  133. id = rs.getInt("server_id");
  134. _gameServerTable.put(id, new GameServerInfo(id, stringToHex(rs.getString("hexid"))));
  135. }
  136. }
  137. }
  138. catch (Exception e)
  139. {
  140. _log.severe(getClass().getSimpleName() + ": Error loading registered game servers!");
  141. }
  142. finally
  143. {
  144. L2DatabaseFactory.close(con);
  145. }
  146. }
  147. /**
  148. * Gets the registered game servers.
  149. * @return the registered game servers
  150. */
  151. public Map<Integer, GameServerInfo> getRegisteredGameServers()
  152. {
  153. return _gameServerTable;
  154. }
  155. /**
  156. * Gets the registered game server by id.
  157. * @param id the game server Id
  158. * @return the registered game server by id
  159. */
  160. public GameServerInfo getRegisteredGameServerById(int id)
  161. {
  162. return _gameServerTable.get(id);
  163. }
  164. /**
  165. * Checks for registered game server on id.
  166. * @param id the id
  167. * @return true, if successful
  168. */
  169. public boolean hasRegisteredGameServerOnId(int id)
  170. {
  171. return _gameServerTable.containsKey(id);
  172. }
  173. /**
  174. * Register with first available id.
  175. * @param gsi the game server information DTO
  176. * @return true, if successful
  177. */
  178. public boolean registerWithFirstAvaliableId(GameServerInfo gsi)
  179. {
  180. // avoid two servers registering with the same "free" id
  181. synchronized (_gameServerTable)
  182. {
  183. for (Entry<Integer, String> entry : _serverNames.entrySet())
  184. {
  185. if (!_gameServerTable.containsKey(entry.getKey()))
  186. {
  187. _gameServerTable.put(entry.getKey(), gsi);
  188. gsi.setId(entry.getKey());
  189. return true;
  190. }
  191. }
  192. }
  193. return false;
  194. }
  195. /**
  196. * Register a game server.
  197. * @param id the id
  198. * @param gsi the gsi
  199. * @return true, if successful
  200. */
  201. public boolean register(int id, GameServerInfo gsi)
  202. {
  203. // avoid two servers registering with the same id
  204. synchronized (_gameServerTable)
  205. {
  206. if (!_gameServerTable.containsKey(id))
  207. {
  208. _gameServerTable.put(id, gsi);
  209. gsi.setId(id);
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. /**
  216. * Wrapper method.
  217. * @param gsi the game server info DTO.
  218. */
  219. public void registerServerOnDB(GameServerInfo gsi)
  220. {
  221. registerServerOnDB(gsi.getHexId(), gsi.getId(), gsi.getExternalHost());
  222. }
  223. /**
  224. * Register server on db.
  225. * @param hexId the hex id
  226. * @param id the id
  227. * @param externalHost the external host
  228. */
  229. public void registerServerOnDB(byte[] hexId, int id, String externalHost)
  230. {
  231. Connection con = null;
  232. try
  233. {
  234. con = L2DatabaseFactory.getInstance().getConnection();
  235. try (PreparedStatement ps = con.prepareStatement("INSERT INTO gameservers (hexid,server_id,host) values (?,?,?)"))
  236. {
  237. ps.setString(1, hexToString(hexId));
  238. ps.setInt(2, id);
  239. ps.setString(3, externalHost);
  240. ps.executeUpdate();
  241. }
  242. register(id, new GameServerInfo(id, hexId));
  243. }
  244. catch (Exception e)
  245. {
  246. _log.severe(getClass().getSimpleName() + ": Error while saving gameserver!");
  247. }
  248. finally
  249. {
  250. L2DatabaseFactory.close(con);
  251. }
  252. }
  253. /**
  254. * Gets the server name by id.
  255. * @param id the id
  256. * @return the server name by id
  257. */
  258. public String getServerNameById(int id)
  259. {
  260. return _serverNames.get(id);
  261. }
  262. /**
  263. * Gets the server names.
  264. * @return the game server names map.
  265. */
  266. public Map<Integer, String> getServerNames()
  267. {
  268. return _serverNames;
  269. }
  270. /**
  271. * Gets the key pair.
  272. * @return a random key pair.
  273. */
  274. public KeyPair getKeyPair()
  275. {
  276. return _keyPairs[Rnd.nextInt(10)];
  277. }
  278. /**
  279. * String to hex.
  280. * @param string the string to convert.
  281. * @return return the hex representation.
  282. */
  283. private byte[] stringToHex(String string)
  284. {
  285. return new BigInteger(string, 16).toByteArray();
  286. }
  287. /**
  288. * Hex to string.
  289. * @param hex the hex value to convert.
  290. * @return the string representation.
  291. */
  292. private String hexToString(byte[] hex)
  293. {
  294. if (hex == null)
  295. {
  296. return "null";
  297. }
  298. return new BigInteger(hex).toString(16);
  299. }
  300. /**
  301. * The Class GameServerInfo.
  302. */
  303. public static class GameServerInfo
  304. {
  305. // auth
  306. private int _id;
  307. private final byte[] _hexId;
  308. private boolean _isAuthed;
  309. // status
  310. private GameServerThread _gst;
  311. private int _status;
  312. // network
  313. private final ArrayList<GameServerAddress> _addrs = new ArrayList<>(5);
  314. private int _port;
  315. // config
  316. private final boolean _isPvp = true;
  317. private int _serverType;
  318. private int _ageLimit;
  319. private boolean _isShowingBrackets;
  320. private int _maxPlayers;
  321. /**
  322. * Instantiates a new game server info.
  323. * @param id the id
  324. * @param hexId the hex id
  325. * @param gst the gst
  326. */
  327. public GameServerInfo(int id, byte[] hexId, GameServerThread gst)
  328. {
  329. _id = id;
  330. _hexId = hexId;
  331. _gst = gst;
  332. _status = ServerStatus.STATUS_DOWN;
  333. }
  334. /**
  335. * Instantiates a new game server info.
  336. * @param id the id
  337. * @param hexId the hex id
  338. */
  339. public GameServerInfo(int id, byte[] hexId)
  340. {
  341. this(id, hexId, null);
  342. }
  343. /**
  344. * Sets the id.
  345. * @param id the new id
  346. */
  347. public void setId(int id)
  348. {
  349. _id = id;
  350. }
  351. /**
  352. * Gets the id.
  353. * @return the id
  354. */
  355. public int getId()
  356. {
  357. return _id;
  358. }
  359. /**
  360. * Gets the hex id.
  361. * @return the hex id
  362. */
  363. public byte[] getHexId()
  364. {
  365. return _hexId;
  366. }
  367. /**
  368. * Sets the authed.
  369. * @param isAuthed the new authed
  370. */
  371. public void setAuthed(boolean isAuthed)
  372. {
  373. _isAuthed = isAuthed;
  374. }
  375. /**
  376. * Checks if is authed.
  377. * @return true, if is authed
  378. */
  379. public boolean isAuthed()
  380. {
  381. return _isAuthed;
  382. }
  383. /**
  384. * Sets the game server thread.
  385. * @param gst the new game server thread
  386. */
  387. public void setGameServerThread(GameServerThread gst)
  388. {
  389. _gst = gst;
  390. }
  391. /**
  392. * Gets the game server thread.
  393. * @return the game server thread
  394. */
  395. public GameServerThread getGameServerThread()
  396. {
  397. return _gst;
  398. }
  399. /**
  400. * Sets the status.
  401. * @param status the new status
  402. */
  403. public void setStatus(int status)
  404. {
  405. _status = status;
  406. }
  407. /**
  408. * Gets the status.
  409. * @return the status
  410. */
  411. public int getStatus()
  412. {
  413. return _status;
  414. }
  415. /**
  416. * Gets the current player count.
  417. * @return the current player count
  418. */
  419. public int getCurrentPlayerCount()
  420. {
  421. if (_gst == null)
  422. {
  423. return 0;
  424. }
  425. return _gst.getPlayerCount();
  426. }
  427. /**
  428. * Gets the external host.
  429. * @return the external host
  430. */
  431. public String getExternalHost()
  432. {
  433. try
  434. {
  435. return getServerAddress(InetAddress.getByName("0.0.0.0"));
  436. }
  437. catch (Exception e)
  438. {
  439. }
  440. return null;
  441. }
  442. /**
  443. * Gets the port.
  444. * @return the port
  445. */
  446. public int getPort()
  447. {
  448. return _port;
  449. }
  450. /**
  451. * Sets the port.
  452. * @param port the new port
  453. */
  454. public void setPort(int port)
  455. {
  456. _port = port;
  457. }
  458. /**
  459. * Sets the max players.
  460. * @param maxPlayers the new max players
  461. */
  462. public void setMaxPlayers(int maxPlayers)
  463. {
  464. _maxPlayers = maxPlayers;
  465. }
  466. /**
  467. * Gets the max players.
  468. * @return the max players
  469. */
  470. public int getMaxPlayers()
  471. {
  472. return _maxPlayers;
  473. }
  474. /**
  475. * Checks if is pvp.
  476. * @return true, if is pvp
  477. */
  478. public boolean isPvp()
  479. {
  480. return _isPvp;
  481. }
  482. /**
  483. * Sets the age limit.
  484. * @param val the new age limit
  485. */
  486. public void setAgeLimit(int val)
  487. {
  488. _ageLimit = val;
  489. }
  490. /**
  491. * Gets the age limit.
  492. * @return the age limit
  493. */
  494. public int getAgeLimit()
  495. {
  496. return _ageLimit;
  497. }
  498. /**
  499. * Sets the server type.
  500. * @param val the new server type
  501. */
  502. public void setServerType(int val)
  503. {
  504. _serverType = val;
  505. }
  506. /**
  507. * Gets the server type.
  508. * @return the server type
  509. */
  510. public int getServerType()
  511. {
  512. return _serverType;
  513. }
  514. /**
  515. * Sets the showing brackets.
  516. * @param val the new showing brackets
  517. */
  518. public void setShowingBrackets(boolean val)
  519. {
  520. _isShowingBrackets = val;
  521. }
  522. /**
  523. * Checks if is showing brackets.
  524. * @return true, if is showing brackets
  525. */
  526. public boolean isShowingBrackets()
  527. {
  528. return _isShowingBrackets;
  529. }
  530. /**
  531. * Sets the down.
  532. */
  533. public void setDown()
  534. {
  535. setAuthed(false);
  536. setPort(0);
  537. setGameServerThread(null);
  538. setStatus(ServerStatus.STATUS_DOWN);
  539. }
  540. /**
  541. * Adds the server address.
  542. * @param subnet the subnet
  543. * @param addr the addr
  544. * @throws UnknownHostException the unknown host exception
  545. */
  546. public void addServerAddress(String subnet, String addr) throws UnknownHostException
  547. {
  548. _addrs.add(new GameServerAddress(subnet, addr));
  549. }
  550. /**
  551. * Gets the server address.
  552. * @param addr the addr
  553. * @return the server address
  554. */
  555. public String getServerAddress(InetAddress addr)
  556. {
  557. for (GameServerAddress a : _addrs)
  558. {
  559. if (a.equals(addr))
  560. {
  561. return a.getServerAddress();
  562. }
  563. }
  564. return null; // should not happens
  565. }
  566. /**
  567. * Gets the server addresses.
  568. * @return the server addresses
  569. */
  570. public String[] getServerAddresses()
  571. {
  572. String[] result = new String[_addrs.size()];
  573. for (int i = 0; i < result.length; i++)
  574. {
  575. result[i] = _addrs.get(i).toString();
  576. }
  577. return result;
  578. }
  579. /**
  580. * Clear server addresses.
  581. */
  582. public void clearServerAddresses()
  583. {
  584. _addrs.clear();
  585. }
  586. /**
  587. * The Class GameServerAddress.
  588. */
  589. private class GameServerAddress extends IPSubnet
  590. {
  591. private final String _serverAddress;
  592. /**
  593. * Instantiates a new game server address.
  594. * @param subnet the subnet
  595. * @param address the address
  596. * @throws UnknownHostException the unknown host exception
  597. */
  598. public GameServerAddress(String subnet, String address) throws UnknownHostException
  599. {
  600. super(subnet);
  601. _serverAddress = address;
  602. }
  603. /**
  604. * Gets the server address.
  605. * @return the server address
  606. */
  607. public String getServerAddress()
  608. {
  609. return _serverAddress;
  610. }
  611. @Override
  612. public String toString()
  613. {
  614. return _serverAddress + super.toString();
  615. }
  616. }
  617. }
  618. /**
  619. * Gets the single instance of GameServerTable.
  620. * @return single instance of GameServerTable
  621. */
  622. public static GameServerTable getInstance()
  623. {
  624. return SingletonHolder._instance;
  625. }
  626. /**
  627. * The Class SingletonHolder.
  628. */
  629. private static class SingletonHolder
  630. {
  631. protected static final GameServerTable _instance = new GameServerTable();
  632. }
  633. }