khanat-opennel-code/code/nelns/login_service/login_service.cpp

483 lines
12 KiB
C++

// NeLNS - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// 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 <http://www.gnu.org/licenses/>.
#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 <cstdio>
#include <ctype.h>
#include <cmath>
#include <vector>
#include <map>
#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<CUser> Users;
//vector<CShard> Shards;
vector<CShard> 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;
}