1 // NeLNS - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #endif // HAVE_CONFIG_H
22 #define NELNS_CONFIG ""
23 #endif // NELNS_CONFIG
30 #define NELNS_STATE ""
33 #include "nel/misc/types_nl.h"
42 #include "nel/misc/debug.h"
43 #include "nel/misc/config_file.h"
44 #include "nel/misc/displayer.h"
45 #include "nel/misc/command.h"
46 #include "nel/misc/log.h"
47 #include "nel/misc/window_displayer.h"
48 #include "nel/misc/path.h"
50 #include "nel/net/service.h"
51 #include "nel/net/login_cookie.h"
53 #include "login_service.h"
54 #include "connection_client.h"
55 #include "connection_ws.h"
56 #include "connection_web.h"
57 #include "mysql_helper.h"
65 using namespace NLMISC
;
66 using namespace NLNET
;
74 // store specific user information
75 NLMISC::CFileDisplayer
*Fd
= NULL
;
76 NLMISC::CStdDisplayer Sd
;
77 NLMISC::CLog
*Output
= NULL
;
79 //uint32 CUser::NextUserId = 1; // 0 is reserved
81 //vector<CUser> Users;
82 //vector<CShard> Shards;
84 vector
<CShard
> Shards
;
91 sint
findShard (sint32 shardId
)
93 for (sint i
= 0; i
< (sint
) Shards
.size (); i
++)
95 if (Shards
[i
].ShardId
== shardId
)
104 sint
findShardWithSId (TServiceId sid
)
106 for (sint i
= 0; i
< (sint
) Shards
.size (); i
++)
108 if (Shards
[i
].SId
== sid
)
118 // transform "192.168.1.1:80" into "192.168.1.1"
119 string
removePort (const string
&addr
)
121 return addr
.substr (0, addr
.find (":"));
126 nldebug ("checkClients ()");
127 /*for (uint i = 0; i < Users.size (); i++)
129 switch (Users[i].State)
132 nlassert (Users[i].SockId == NULL);
133 nlassert (!Users[i].Cookie.isValid());
134 nlassert (Users[i].ShardId == NULL);
136 case CUser::Authorized:
137 nlassert (Users[i].SockId != NULL);
138 nlassert (Users[i].Cookie.isValid());
139 nlassert (Users[i].ShardId == NULL);
141 case CUser::Awaiting:
142 nlassert (Users[i].SockId == NULL);
143 nlassert (!Users[i].Cookie.isValid());
144 nlassert (Users[i].ShardId == NULL);
147 nlassert (Users[i].SockId == NULL);
148 nlassert (!Users[i].Cookie.isValid());
149 nlassert (Users[i].ShardId != NULL);
158 /*void disconnectClient (CUser &user, bool disconnectClient, bool disconnectShard)
160 nlinfo ("User %d '%s' need to be disconnect (%d %d %d)", user.Id, user.Login.c_str(), user.State, disconnectClient, disconnectShard);
167 case CUser::Authorized:
168 if (disconnectClient)
170 CNetManager::getNetBase("LS")->disconnect(user.SockId);
172 user.Cookie.clear ();
175 case CUser::Awaiting:
181 // ask the WS to disconnect the player from the shard
182 CMessage msgout (CNetManager::getNetBase("WSLS")->getSIDA (), "DC");
183 msgout.serial (user.Id);
184 CNetManager::send ("WSLS", msgout, user.ShardId);
195 user.State = CUser::Offline;
198 sint
findUser (uint32 Id
)
200 /* for (sint i = 0; i < (sint) Users.size (); i++)
202 if (Users[i].Id == Id)
211 string CUser::Authorize (TSockId sender, CCallbackNetBase &netbase)
220 Cookie = CLoginCookie(netbase.hostAddress(sender).internalIPAddress(), Id);
224 nlwarning ("user %d already authorized! disconnect him and the other one", Id);
225 reason = "You are already authorized (another user uses your account?)";
226 disconnectClient (*this, true, true);
227 disconnectClient (Users[findUser(Id)], true, true);
231 nlwarning ("user %d already awaiting! disconnect the new user and the other one", Id);
232 reason = "You are already awaiting (another user uses your account?)";
233 disconnectClient (*this, true, true);
234 disconnectClient (Users[findUser(Id)], true, true);
238 nlwarning ("user %d already online! disconnect the new user and the other one", Id);
239 reason = "You are already online (another user uses your account?)";
240 disconnectClient (*this, true, true);
241 disconnectClient (Users[findUser(Id)], true, true);
245 reason = "default case should never occurs, there's a bug in the login_service.cpp";
252 void displayShards ()
254 ICommand::execute ("shards", *InfoLog
);
259 ICommand::execute ("users", *InfoLog
);
264 ////////////////////////////////////////////////////////////////////////////////////////////////
265 ////////////////////////////////////////////////////////////////////////////////////////////////
266 /////////////// SERVICE IMPLEMENTATION /////////////////////////////////////////////////////////
267 ////////////////////////////////////////////////////////////////////////////////////////////////
268 ////////////////////////////////////////////////////////////////////////////////////////////////
270 void beep (uint freq
, uint nb
, uint beepDuration
, uint pauseDuration
)
275 if (IService::getInstance()->ConfigFile
.getVar ("Beep").asInt() == 1)
277 for (uint i
= 0; i
< nb
; i
++)
279 Beep (freq
, beepDuration
);
280 nlSleep (pauseDuration
);
287 #endif // NL_OS_WINDOWS
290 class CLoginService
: public IService
294 bool UseDirectClient
;
296 CLoginService () : UseDirectClient(false) { }
298 /// Init the service, load the universal time.
305 if(ConfigFile
.exists("UseDirectClient"))
306 UseDirectClient
= ConfigFile
.getVar("UseDirectClient").asBool();
308 string fn
= IService::getInstance()->SaveFilesDirectory
;
309 fn
+= "login_service.stat";
310 nlinfo("Login stat in directory '%s'", fn
.c_str());
311 Fd
= new NLMISC::CFileDisplayer(fn
);
312 Output
->addDisplayer (Fd
);
313 if (WindowDisplayer
) Output
->addDisplayer (WindowDisplayer
);
315 // Initialize the database access
321 connectionClientInit ();
323 connectionWebInit ();
325 Output
->displayNL ("Login Service initialized");
330 connectionWSUpdate ();
332 connectionClientUpdate ();
334 connectionWebUpdate ();
338 /// release the service, save the universal time
341 connectionWSRelease ();
343 connectionClientRelease ();
345 connectionWebRelease ();
347 Output
->displayNL ("Login Service released");
351 // Service instantiation
352 NLNET_SERVICE_MAIN (CLoginService
, "LS", "login_service", 49999, EmptyCallbackArray
, NELNS_CONFIG
, NELNS_LOGS
);
358 NLMISC_DYNVARIABLE(uint
, OnlineUsersNumber
, "number of actually connected users")
360 // we can only read the value
363 //uint32 nbusers = 0;
364 //for (uint i = 0; i < Users.size(); i++)
366 // if (Users[i].State == CUser::Online)
369 *pointer
= NbPlayers
;
377 NLMISC_COMMAND (shards
, "displays the list of all registered shards", "")
379 if(args
.size() != 0) return false;
381 log
.displayNL ("Display the %d registered shards :", Shards
.size());
382 for (uint i
= 0; i
< Shards
.size(); i
++)
384 log
.displayNL ("* ShardId: %d SId: %d NbPlayers: %d", Shards
[i
].ShardId
, Shards
[i
].SId
.get(), Shards
[i
].NbPlayers
);
385 CUnifiedNetwork::getInstance()->displayUnifiedConnection (Shards
[i
].SId
, &log
);
387 log
.displayNL ("End of the list");
392 NLMISC_COMMAND (shardDatabase
, "displays the list of all shards in the database", "")
394 if(args
.size() != 0) return false;
400 string reason
= sqlQuery("select ShardId, WsAddr, NbPlayers, Name, Online, ClientApplication, Version, DynPatchURL from shard", nbrow
, row
, result
);
401 if(!reason
.empty()) { log
.displayNL("Display registered users failed; '%s'", reason
.c_str()); return true; }
403 log
.displayNL("Display the %d shards in the database :", nbrow
);
404 log
.displayNL(" > ShardId, WsAddr, NbPlayers, Name, Online, ClientApplication, Version, DynPatchURL");
406 if (nbrow
!= 0) while(row
!= 0)
408 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]);
409 row
= mysql_fetch_row(result
);
412 log
.displayNL("End of the list");
417 NLMISC_COMMAND (registeredUsers
, "displays the list of all registered users", "")
419 if(args
.size() != 0) return false;
425 string reason
= sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user", nbrow
, row
, result
);
426 if(!reason
.empty()) { log
.displayNL("Display registered users failed; '%s'", reason
.c_str()); return true; }
428 log
.displayNL("Display the %d registered users :", nbrow
);
429 log
.displayNL(" > UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie");
431 if (nbrow
!= 0) while(row
!= 0)
433 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]);
434 row
= mysql_fetch_row(result
);
437 log
.displayNL("End of the list");
442 NLMISC_COMMAND (onlineUsers
, "displays the list of online users", "")
444 if(args
.size() != 0) return false;
450 uint32 nbusers
= 0, nbwait
= 0;
451 log
.displayNL ("Display the online users :");
453 string reason
= sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Online'", nbrow
, row
, result
);
454 if(!reason
.empty()) { log
.displayNL("Display online users failed; '%s'", reason
.c_str()); return true; }
455 if (nbrow
!= 0) while(row
!= 0)
457 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]);
458 row
= mysql_fetch_row(result
);
462 reason
= sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Waiting'", nbrow
, row
, result
);
463 if(!reason
.empty()) { log
.displayNL("Display waiting users failed; '%s'", reason
.c_str()); return true; }
464 if (nbrow
!= 0) while(row
!= 0)
466 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]);
467 row
= mysql_fetch_row(result
);
471 reason
= sqlQuery("select UId, Login, Password, ShardId, State, Privilege, ExtendedPrivilege, Cookie from user where State='Authorized'", nbrow
, row
, result
);
472 if(!reason
.empty()) { log
.displayNL("Display authorized users failed; '%s'", reason
.c_str()); return true; }
473 if (nbrow
!= 0) while(row
!= 0)
475 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]);
476 row
= mysql_fetch_row(result
);
479 log
.displayNL ("End of the list (%d online users, %d waiting, %d authorized)", nbusers
, nbwait
, nbrow
);