// NeLNS - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifndef NELNS_CONFIG #define NELNS_CONFIG "" #endif // NELNS_CONFIG #ifndef NELNS_LOGS #define NELNS_LOGS "" #endif // NELNS_LOGS #ifndef NELNS_STATE #define NELNS_STATE "" #endif // NELNS_STATE #include "nel/misc/types_nl.h" #include #include #include #include #include #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/displayer.h" #include "nel/misc/command.h" #include "nel/misc/log.h" #include "nel/misc/window_displayer.h" #include "nel/misc/path.h" #include "nel/net/service.h" #include "nel/net/login_cookie.h" #include "login_service.h" #include "connection_client.h" #include "connection_ws.h" #include "connection_web.h" #include "mysql_helper.h" // // Namespaces // using namespace std; using namespace NLMISC; using namespace NLNET; // // Variables // // store specific user information NLMISC::CFileDisplayer *Fd = NULL; NLMISC::CStdDisplayer Sd; NLMISC::CLog *Output = NULL; //uint32 CUser::NextUserId = 1; // 0 is reserved //vector Users; //vector Shards; vector Shards; // // Functions // sint findShard (sint32 shardId) { for (sint i = 0; i < (sint) Shards.size (); i++) { if (Shards[i].ShardId == shardId) { return i; } } // shard not found return -1; } sint findShardWithSId (TServiceId sid) { for (sint i = 0; i < (sint) Shards.size (); i++) { if (Shards[i].SId == sid) { return i; } } // shard not found return -1; } // transform "192.168.1.1:80" into "192.168.1.1" string removePort (const string &addr) { return addr.substr (0, addr.find (":")); } void checkClients () { nldebug ("checkClients ()"); /*for (uint i = 0; i < Users.size (); i++) { switch (Users[i].State) { case CUser::Offline: nlassert (Users[i].SockId == NULL); nlassert (!Users[i].Cookie.isValid()); nlassert (Users[i].ShardId == NULL); break; case CUser::Authorized: nlassert (Users[i].SockId != NULL); nlassert (Users[i].Cookie.isValid()); nlassert (Users[i].ShardId == NULL); break; case CUser::Awaiting: nlassert (Users[i].SockId == NULL); nlassert (!Users[i].Cookie.isValid()); nlassert (Users[i].ShardId == NULL); break; case CUser::Online: nlassert (Users[i].SockId == NULL); nlassert (!Users[i].Cookie.isValid()); nlassert (Users[i].ShardId != NULL); break; default: nlstop; break; } }*/ } /*void disconnectClient (CUser &user, bool disconnectClient, bool disconnectShard) { nlinfo ("User %d '%s' need to be disconnect (%d %d %d)", user.Id, user.Login.c_str(), user.State, disconnectClient, disconnectShard); switch (user.State) { case CUser::Offline: break; case CUser::Authorized: if (disconnectClient) { CNetManager::getNetBase("LS")->disconnect(user.SockId); } user.Cookie.clear (); break; case CUser::Awaiting: break; case CUser::Online: if (disconnectShard) { // ask the WS to disconnect the player from the shard CMessage msgout (CNetManager::getNetBase("WSLS")->getSIDA (), "DC"); msgout.serial (user.Id); CNetManager::send ("WSLS", msgout, user.ShardId); } user.ShardId = NULL; break; default: nlstop; break; } user.SockId = NULL; user.State = CUser::Offline; } */ sint findUser (uint32 Id) { /* for (sint i = 0; i < (sint) Users.size (); i++) { if (Users[i].Id == Id) { return i; } } // user not found */ return -1; } /* string CUser::Authorize (TSockId sender, CCallbackNetBase &netbase) { string reason; switch (State) { case Offline: State = Authorized; SockId = sender; Cookie = CLoginCookie(netbase.hostAddress(sender).internalIPAddress(), Id); break; case Authorized: nlwarning ("user %d already authorized! disconnect him and the other one", Id); reason = "You are already authorized (another user uses your account?)"; disconnectClient (*this, true, true); disconnectClient (Users[findUser(Id)], true, true); break; case Awaiting: nlwarning ("user %d already awaiting! disconnect the new user and the other one", Id); reason = "You are already awaiting (another user uses your account?)"; disconnectClient (*this, true, true); disconnectClient (Users[findUser(Id)], true, true); break; case Online: nlwarning ("user %d already online! disconnect the new user and the other one", Id); reason = "You are already online (another user uses your account?)"; disconnectClient (*this, true, true); disconnectClient (Users[findUser(Id)], true, true); break; default: reason = "default case should never occurs, there's a bug in the login_service.cpp"; nlstop; break; } return reason; } */ void displayShards () { ICommand::execute ("shards", *InfoLog); } void displayUsers () { ICommand::execute ("users", *InfoLog); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /////////////// SERVICE IMPLEMENTATION ///////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// void beep (uint freq, uint nb, uint beepDuration, uint pauseDuration) { #ifdef NL_OS_WINDOWS try { if (IService::getInstance()->ConfigFile.getVar ("Beep").asInt() == 1) { for (uint i = 0; i < nb; i++) { Beep (freq, beepDuration); nlSleep (pauseDuration); } } } catch (Exception &) { } #endif // NL_OS_WINDOWS } class CLoginService : public IService { public: bool UseDirectClient; CLoginService () : UseDirectClient(false) { } /// Init the service, load the universal time. void init () { beep (); Output = new CLog; if(ConfigFile.exists("UseDirectClient")) UseDirectClient = ConfigFile.getVar("UseDirectClient").asBool(); string fn = IService::getInstance()->SaveFilesDirectory; fn += "login_service.stat"; nlinfo("Login stat in directory '%s'", fn.c_str()); Fd = new NLMISC::CFileDisplayer(fn); Output->addDisplayer (Fd); if (WindowDisplayer) Output->addDisplayer (WindowDisplayer); // Initialize the database access sqlInit(); connectionWSInit (); if(UseDirectClient) connectionClientInit (); else connectionWebInit (); Output->displayNL ("Login Service initialized"); } bool update () { connectionWSUpdate (); if(UseDirectClient) connectionClientUpdate (); else connectionWebUpdate (); return true; } /// release the service, save the universal time void release () { connectionWSRelease (); if(UseDirectClient) connectionClientRelease (); else connectionWebRelease (); Output->displayNL ("Login Service released"); } }; // Service instantiation NLNET_SERVICE_MAIN (CLoginService, "LS", "login_service", 49999, EmptyCallbackArray, NELNS_CONFIG, NELNS_LOGS); // // Variables // NLMISC_DYNVARIABLE(uint, OnlineUsersNumber, "number of actually connected users") { // we can only read the value if (get) { //uint32 nbusers = 0; //for (uint i = 0; i < Users.size(); i++) //{ // if (Users[i].State == CUser::Online) // nbusers++; //} *pointer = NbPlayers; } } // // Commands // NLMISC_COMMAND (shards, "displays the list of all registered shards", "") { if(args.size() != 0) return false; log.displayNL ("Display the %d registered shards :", Shards.size()); for (uint i = 0; i < Shards.size(); i++) { log.displayNL ("* ShardId: %d SId: %d NbPlayers: %d", Shards[i].ShardId, Shards[i].SId.get(), Shards[i].NbPlayers); CUnifiedNetwork::getInstance()->displayUnifiedConnection (Shards[i].SId, &log); } log.displayNL ("End of the list"); return true; } NLMISC_COMMAND (shardDatabase, "displays the list of all shards in the database", "") { if(args.size() != 0) return false; CMysqlResult result; MYSQL_ROW row; sint32 nbrow; string reason = sqlQuery("select ShardId, WsAddr, NbPlayers, Name, Online, ClientApplication, Version, DynPatchURL from shard", nbrow, row, result); if(!reason.empty()) { log.displayNL("Display registered users failed; '%s'", reason.c_str()); return true; } log.displayNL("Display the %d shards in the database :", nbrow); log.displayNL(" > ShardId, WsAddr, NbPlayers, Name, Online, ClientApplication, Version, DynPatchURL"); if (nbrow != 0) while(row != 0) { log.displayNL(" > '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]); row = mysql_fetch_row(result); } log.displayNL("End of the list"); return true; } NLMISC_COMMAND (registeredUsers, "displays the list of all registered users", "") { if(args.size() != 0) return false; CMysqlResult result; MYSQL_ROW row; sint32 nbrow; string reason = sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user", nbrow, row, result); if(!reason.empty()) { log.displayNL("Display registered users failed; '%s'", reason.c_str()); return true; } log.displayNL("Display the %d registered users :", nbrow); log.displayNL(" > UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie"); if (nbrow != 0) while(row != 0) { log.displayNL(" > '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]); row = mysql_fetch_row(result); } log.displayNL("End of the list"); return true; } NLMISC_COMMAND (onlineUsers, "displays the list of online users", "") { if(args.size() != 0) return false; CMysqlResult result; MYSQL_ROW row; sint32 nbrow; uint32 nbusers = 0, nbwait = 0; log.displayNL ("Display the online users :"); string reason = sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Online'", nbrow, row, result); if(!reason.empty()) { log.displayNL("Display online users failed; '%s'", reason.c_str()); return true; } if (nbrow != 0) while(row != 0) { log.displayNL(" > '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]); row = mysql_fetch_row(result); } nbusers = nbrow; reason = sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Waiting'", nbrow, row, result); if(!reason.empty()) { log.displayNL("Display waiting users failed; '%s'", reason.c_str()); return true; } if (nbrow != 0) while(row != 0) { log.displayNL(" > '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]); row = mysql_fetch_row(result); } nbwait = nbrow; reason = sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Authorized'", nbrow, row, result); if(!reason.empty()) { log.displayNL("Display authorized users failed; '%s'", reason.c_str()); return true; } if (nbrow != 0) while(row != 0) { log.displayNL(" > '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'", row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]); row = mysql_fetch_row(result); } log.displayNL ("End of the list (%d online users, %d waiting, %d authorized)", nbusers, nbwait, nbrow); return true; }