483 lines
12 KiB
C++
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;
|
|
}
|
|
|