/* * 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 . */ package com.l2jserver.loginserver; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; 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.sql.SQLException; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import org.mmocore.network.SelectorConfig; import org.mmocore.network.SelectorThread; import com.l2jserver.Config; import com.l2jserver.L2DatabaseFactory; import com.l2jserver.Server; import com.l2jserver.loginserver.mail.MailSystem; import com.l2jserver.loginserver.network.L2LoginClient; import com.l2jserver.loginserver.network.L2LoginPacketHandler; import com.l2jserver.status.Status; /** * * @author KenM */ public class L2LoginServer { public static final int PROTOCOL_REV = 0x0106; private static L2LoginServer _instance; private final Logger _log = Logger.getLogger(L2LoginServer.class.getName()); private GameServerListener _gameServerListener; private SelectorThread _selectorThread; private Status _statusServer; private Thread _restartLoginServer; public static void main(String[] args) { _instance = new L2LoginServer(); } public static L2LoginServer getInstance() { return _instance; } public L2LoginServer() { Server.serverMode = Server.MODE_LOGINSERVER; // Local Constants final String LOG_FOLDER = "log"; // Name of folder for log file final String LOG_NAME = "./log.cfg"; // Name of log file /*** Main ***/ // Create log folder File logFolder = new File(Config.DATAPACK_ROOT, LOG_FOLDER); logFolder.mkdir(); // Create input stream for log file -- or store file data into memory InputStream is = null; try { is = new FileInputStream(new File(LOG_NAME)); LogManager.getLogManager().readConfiguration(is); is.close(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } // Load Config Config.load(); // Prepare Database try { L2DatabaseFactory.getInstance(); } catch (SQLException e) { _log.log(Level.SEVERE, "FATAL: Failed initializing database. Reason: " + e.getMessage(), e); System.exit(1); } try { LoginController.load(); } catch (GeneralSecurityException e) { _log.log(Level.SEVERE, "FATAL: Failed initializing LoginController. Reason: " + e.getMessage(), e); System.exit(1); } try { GameServerTable.load(); } catch (GeneralSecurityException e) { _log.log(Level.SEVERE, "FATAL: Failed to load GameServerTable. Reason: " + e.getMessage(), e); System.exit(1); } catch (SQLException e) { _log.log(Level.SEVERE, "FATAL: Failed to load GameServerTable. Reason: " + e.getMessage(), e); System.exit(1); } loadBanFile(); if (Config.EMAIL_SYS_ENABLED) { MailSystem.getInstance(); } 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(); _gameServerListener.start(); _log.info("Listening for GameServers on " + Config.GAME_SERVER_LOGIN_HOST + ":" + Config.GAME_SERVER_LOGIN_PORT); } catch (IOException e) { _log.log(Level.SEVERE, "FATAL: Failed to start the Game Server Listener. Reason: " + e.getMessage(), e); System.exit(1); } if (Config.IS_TELNET_ENABLED) { try { _statusServer = new Status(Server.serverMode); _statusServer.start(); } catch (IOException e) { _log.log(Level.WARNING, "Failed to start the Telnet Server. Reason: " + e.getMessage(), e); } } else { _log.info("Telnet server is currently disabled."); } try { _selectorThread.openServerSocket(bindAddress, Config.PORT_LOGIN); } catch (IOException e) { _log.log(Level.SEVERE, "FATAL: Failed to open server socket. Reason: " + e.getMessage(), e); System.exit(1); } _selectorThread.start(); _log.info("Login Server ready on " + (bindAddress == null ? "*" : bindAddress.getHostAddress()) + ":" + Config.PORT_LOGIN); } public Status getStatusServer() { return _statusServer; } public GameServerListener getGameServerListener() { return _gameServerListener; } private void loadBanFile() { File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) { FileInputStream fis = null; try { fis = new FileInputStream(bannedFile); } catch (FileNotFoundException e) { _log.log(Level.WARNING, "Failed to load banned IPs file (" + bannedFile.getName() + ") for reading. Reason: " + e.getMessage(), e); return; } LineNumberReader reader = null; String line; String[] parts; try { reader = new LineNumberReader(new InputStreamReader(fis)); while ((line = reader.readLine()) != null) { line = line.trim(); // check if this line isnt a comment line if (line.length() > 0 && line.charAt(0) != '#') { // split comments if any parts = line.split("#", 2); // discard comments in the line, if any line = parts[0]; parts = line.split(" "); String address = parts[0]; long duration = 0; if (parts.length > 1) { try { duration = Long.parseLong(parts[1]); } catch (NumberFormatException e) { _log.warning("Skipped: Incorrect ban duration (" + parts[1] + ") on (" + bannedFile.getName() + "). Line: " + reader.getLineNumber()); continue; } } try { LoginController.getInstance().addBanForAddress(address, duration); } catch (UnknownHostException e) { _log.warning("Skipped: Invalid address (" + parts[0] + ") on (" + bannedFile.getName() + "). Line: " + reader.getLineNumber()); } } } } catch (IOException e) { _log.log(Level.WARNING, "Error while reading the bans file (" + bannedFile.getName() + "). Details: " + e.getMessage(), e); } finally { try { reader.close(); } catch (Exception e) { } try { fis.close(); } catch (Exception e) { } } _log.info("Loaded " + LoginController.getInstance().getBannedIps().size() + " IP Bans."); } else { _log.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } if (Config.LOGIN_SERVER_SCHEDULE_RESTART) { _log.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); _restartLoginServer = new LoginServerRestart(); _restartLoginServer.setDaemon(true); _restartLoginServer.start(); } } class LoginServerRestart extends Thread { public LoginServerRestart() { setName("LoginServerRestart"); } @Override public void run() { while (!isInterrupted()) { try { Thread.sleep(Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME * 60 * 60 * 1000); } catch (InterruptedException e) { return; } shutdown(true); } } } public void shutdown(boolean restart) { Runtime.getRuntime().exit(restart ? 2 : 0); } }