# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

login_server.cpp

Go to the documentation of this file.
00001 
00008 /* Copyright, 2000 Nevrax Ltd.
00009  *
00010  * This file is part of NEVRAX NEL.
00011  * NEVRAX NEL is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2, or (at your option)
00014  * any later version.
00015 
00016  * NEVRAX NEL is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00019  * General Public License for more details.
00020 
00021  * You should have received a copy of the GNU General Public License
00022  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00023  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00024  * MA 02111-1307, USA.
00025  */
00026 
00027 #include "stdnet.h"
00028 
00029 #include "nel/net/callback_client.h"
00030 #include "nel/net/service.h"
00031 
00032 #include "nel/net/login_cookie.h"
00033 #include "nel/net/login_server.h"
00034 
00035 #include "nel/net/udp_sock.h"
00036 
00037 using namespace std;
00038 using namespace NLMISC;
00039 
00040 namespace NLNET {
00041 
00042 struct CPendingUser
00043 {
00044         CPendingUser (const CLoginCookie &cookie) : Cookie (cookie) { }
00045         CLoginCookie Cookie;
00046 };
00047 
00048 static list<CPendingUser> PendingUsers;
00049 
00050 static CCallbackServer *Server;
00051 static string ListenAddr;
00052 
00053 static TDisconnectClientCallback DisconnectClientCallback = NULL;
00054 
00056 map<uint32, TSockId> UserIdSockAssociations;
00057 
00058 TNewClientCallback NewClientCallback = NULL;
00059 
00065 
00066 void cbWSChooseShard (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00067 {
00068         // the WS call me that a new client want to come in my shard
00069         string reason;
00070         CLoginCookie cookie;
00071         
00072         //
00073         // S08: receive "CS" message from WS and send "SCS" message to WS
00074         //
00075 
00076         msgin.serial (cookie);
00077 
00078         list<CPendingUser>::iterator it;
00079         for (it = PendingUsers.begin(); it != PendingUsers.end (); it++)
00080         {
00081                 if ((*it).Cookie == cookie)
00082                 {
00083                         // the cookie already exists, erase it and return false
00084                         nlwarning ("cookie %s is already in the pending user list", cookie.toString().c_str());
00085                         PendingUsers.erase (it);
00086                         reason = "cookie already exists";
00087                         break;
00088                 }
00089         }
00090         if (it == PendingUsers.end ())
00091         {
00092                 // add it to the awaiting client
00093                 PendingUsers.push_back (CPendingUser (cookie));
00094                 reason = "";
00095         }
00096 
00097         CMessage msgout (CNetManager::getSIDA ("WS"), "SCS");
00098         msgout.serial (reason);
00099         msgout.serial (cookie);
00100         msgout.serial (ListenAddr);
00101         CNetManager::send ("WS", msgout);
00102 }
00103 
00104 void cbWSChooseShard5 (CMessage &msgin, const std::string &serviceName, uint16 sid)
00105 {
00106         // the WS call me that a new client want to come in my shard
00107         string reason;
00108         CLoginCookie cookie;
00109         
00110         //
00111         // S08: receive "CS" message from WS and send "SCS" message to WS
00112         //
00113 
00114         msgin.serial (cookie);
00115 
00116         list<CPendingUser>::iterator it;
00117         for (it = PendingUsers.begin(); it != PendingUsers.end (); it++)
00118         {
00119                 if ((*it).Cookie == cookie)
00120                 {
00121                         // the cookie already exists, erase it and return false
00122                         nlwarning ("cookie %s is already in the pending user list", cookie.toString().c_str());
00123                         PendingUsers.erase (it);
00124                         reason = "cookie already exists";
00125                         break;
00126                 }
00127         }
00128         if (it == PendingUsers.end ())
00129         {
00130                 // add it to the awaiting client
00131                 nlinfo ("New cookie %s inserted in the pending user list (awaiting new client)", cookie.toString().c_str());
00132                 PendingUsers.push_back (CPendingUser (cookie));
00133                 reason = "";
00134         }
00135 
00136         CMessage msgout ("SCS");
00137         msgout.serial (reason);
00138         msgout.serial (cookie);
00139         msgout.serial (ListenAddr);
00140         CUnifiedNetwork::getInstance()->send ("WS", msgout);
00141 }
00142 
00143 void cbWSDisconnectClient5 (CMessage &msgin, const std::string &serviceName, uint16 sid)
00144 {
00145         // the WS tells me that i have to disconnect a client
00146 
00147         uint32 userid;
00148         msgin.serial (userid);
00149 
00150         map<uint32, TSockId>::iterator it = UserIdSockAssociations.find (userid);
00151         if (it == UserIdSockAssociations.end ())
00152         {
00153                 nlwarning ("Can't disconnect the user %d, he is not found", userid);
00154         }
00155         else
00156         {
00157                 nlinfo ("Disconnect the user %d", userid);
00158                 Server->disconnect ((*it).second);
00159         }
00160 
00161         if (DisconnectClientCallback != NULL)
00162         {
00163                 DisconnectClientCallback (userid);
00164         }
00165 }
00166 
00167 void cbWSDisconnectClient (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00168 {
00169         cbWSDisconnectClient5 (msgin, "", 0);
00170 }
00171 
00172 static TCallbackItem WSCallbackArray[] =
00173 {
00174         { "CS", cbWSChooseShard },
00175         { "DC", cbWSDisconnectClient },
00176 };
00177 
00178 static TUnifiedCallbackItem WSCallbackArray5[] =
00179 {
00180         { "CS", cbWSChooseShard5 },
00181         { "DC", cbWSDisconnectClient5 },
00182 };
00183 
00189 
00190 void cbShardValidation (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00191 {
00192         //
00193         // S13: receive "SV" message from client
00194         //
00195 
00196         // the client send me a cookie
00197         CLoginCookie cookie;
00198         string reason;
00199         msgin.serial (cookie);
00200 
00201         // verify that the user was pending
00202         reason = CLoginServer::isValidCookie (cookie);
00203 
00204         CMessage msgout2 (netbase.getSIDA (), "SV");
00205         msgout2.serial (reason);
00206         netbase.send (msgout2, from);
00207         
00208         if (!reason.empty())
00209         {
00210                 nlwarning ("User (%s) is not in the pending user list (cookie:%s)", netbase.hostAddress(from).asString().c_str(), cookie.toString().c_str());
00211                 // deconnect him
00212                 netbase.disconnect (from);
00213         }
00214         else
00215         {
00216                 // add the user association
00217                 uint32 userid = cookie.getUserId();
00218                 UserIdSockAssociations.insert (make_pair(userid, from));
00219 
00220                 // identification OK, let's call the user callback
00221                 if (NewClientCallback != NULL)
00222                         NewClientCallback (from, cookie);
00223 
00224                 // ok, now, he can call all callback
00225                 Server->authorizeOnly (NULL, from);
00226         }
00227 }
00228 
00229 void ClientConnection (TSockId from, void *arg)
00230 {
00231         nldebug("new client connection: %s", from->asString ().c_str ());
00232 
00233         // the client could only call "SV" message
00234         Server->authorizeOnly ("SV", from);
00235 }
00236 
00237 
00238 static const TCallbackItem ClientCallbackArray[] =
00239 {
00240         { "SV", cbShardValidation },
00241 };
00242 
00243 void cfcbListenAddress (CConfigFile::CVar &var)
00244 {
00245         // set the new ListenAddr
00246         ListenAddr = var.asString();
00247         
00248         // is the var is empty or not found, take it from the listenAddress()
00249         if (ListenAddr.empty())
00250         {
00251                 ListenAddr = Server->listenAddress ().asIPString();
00252         }
00253 
00254         nlinfo("Listen Address trapped '%s'", ListenAddr.c_str());
00255 }
00256 
00257 
00263 
00264 void CLoginServer::init (CCallbackServer &server, TNewClientCallback ncl)
00265 {
00266         // connect to the welcome service
00267         connectToWS ();
00268 
00269         // add callback to the server
00270         server.addCallbackArray (ClientCallbackArray, sizeof (ClientCallbackArray) / sizeof (ClientCallbackArray[0]));
00271         server.setConnectionCallback (ClientConnection, NULL);
00272 
00273         try
00274         {
00275                 cfcbListenAddress (IService::getInstance()->ConfigFile.getVar("ListenAddress"));
00276                 IService::getInstance()->ConfigFile.setCallback("ListenAddress", cfcbListenAddress);
00277         }
00278         catch(Exception &)
00279         {
00280         }
00281 
00282         // if the listen addr is not in the config file, try to find it dynamically
00283         if (ListenAddr.empty())
00284         {
00285                 ListenAddr = server.listenAddress ().asIPString();
00286         }
00287 
00288         nlinfo("Listen Address trapped '%s'", ListenAddr.c_str());
00289 
00290         NewClientCallback = ncl;
00291         Server = &server;
00292 }
00293 
00294 void CLoginServer::init (CUdpSock &server, TDisconnectClientCallback dc)
00295 {
00296         // connect to the welcome service
00297         connectToWS ();
00298 
00299         try
00300         {
00301                 cfcbListenAddress (IService::getInstance()->ConfigFile.getVar("ListenAddress"));
00302                 IService::getInstance()->ConfigFile.setCallback("ListenAddress", cfcbListenAddress);
00303         }
00304         catch(Exception &)
00305         {
00306         }
00307         
00308         // if the listen addr is not in the config file, try to find it dynamically
00309         if (ListenAddr.empty())
00310         {
00311                 ListenAddr = server.localAddr ().asIPString();
00312         }
00313 
00314         nlinfo("Listen Addresss trapped '%s'", ListenAddr.c_str());
00315 
00316         DisconnectClientCallback = dc;
00317 }
00318 
00319 string CLoginServer::isValidCookie (const CLoginCookie &lc)
00320 {
00321         // verify that the user was pending
00322         list<CPendingUser>::iterator it;
00323         for (it = PendingUsers.begin(); it != PendingUsers.end (); it++)
00324         {
00325                 if ((*it).Cookie == lc)
00326                 {
00327                         // ok, it was validate, remove it
00328                         PendingUsers.erase (it);
00329 
00330                         // warn the WS that the client effectively connected
00331                         uint8 con = 1;
00332                         CMessage msgout ("CC");
00333                         uint32 userid = lc.getUserId();
00334                         msgout.serial (userid);
00335                         msgout.serial (con);
00336 
00337                         if (CUnifiedNetwork::isUsed ())
00338                         {
00339                                 CUnifiedNetwork::getInstance()->send("WS", msgout);
00340                         }
00341                         else
00342                         {
00343                                 CNetManager::send("WS", msgout);
00344                         }
00345 
00346                         return "";
00347                 }
00348         }
00349         return "I didn't receive the cookie from WS";
00350 }
00351 
00352 void CLoginServer::connectToWS ()
00353 {
00354         if (CUnifiedNetwork::isUsed ())
00355         {
00356                 CUnifiedNetwork::getInstance()->addCallbackArray(WSCallbackArray5, sizeof(WSCallbackArray5)/sizeof(WSCallbackArray5[0]));
00357         }
00358         else
00359         {
00360                 CNetManager::addClient ("WS");
00361                 CNetManager::addCallbackArray ("WS", WSCallbackArray, sizeof (WSCallbackArray) / sizeof (WSCallbackArray[0]));
00362 
00363                 CMessage        msg("UN_SIDENT");
00364                 nlassert (IService::getInstance());
00365                 uint16          ssid = IService::getInstance()->getServiceId();
00366                 string name = IService::getInstance()->getServiceShortName();
00367                 msg.serial(name);
00368                 msg.serial(ssid);       // serializes a 16 bits service id
00369                 CNetManager::send("WS", msg);
00370         }
00371 }
00372 
00373 void CLoginServer::clientDisconnected (uint32 userId)
00374 {
00375         uint8 con = 0;
00376         CMessage msgout ("CC");
00377         msgout.serial (userId);
00378         msgout.serial (con);
00379 
00380         if (CUnifiedNetwork::isUsed ())
00381         {
00382                 CUnifiedNetwork::getInstance()->send("WS", msgout);
00383         }
00384         else
00385         {
00386                 CNetManager::send("WS", msgout);
00387         }
00388 
00389         // remove the user association
00390         UserIdSockAssociations.erase (userId);
00391 }
00392 
00393 //
00394 // Commands
00395 //
00396 
00397 NLMISC_COMMAND (lsUsers, "displays the list of all connected users", "")
00398 {
00399         if(args.size() != 0) return false;
00400 
00401         log.displayNL ("Display the %d connected users :", UserIdSockAssociations.size());
00402         for (map<uint32, TSockId>::iterator it = UserIdSockAssociations.begin(); it != UserIdSockAssociations.end (); it++)
00403         {
00404                 log.displayNL ("> %u %s", (*it).first, (*it).second->asString().c_str());
00405         }
00406         log.displayNL ("End ot the list");
00407 
00408         return true;
00409 }
00410 
00411 NLMISC_COMMAND (lsPending, "displays the list of all pending users", "")
00412 {
00413         if(args.size() != 0) return false;
00414 
00415         log.displayNL ("Display the %d pending users :", PendingUsers.size());
00416         for (list<CPendingUser>::iterator it = PendingUsers.begin(); it != PendingUsers.end (); it++)
00417         {
00418                 log.displayNL ("> %s", (*it).Cookie.toString().c_str());
00419         }
00420         log.displayNL ("End ot the list");
00421 
00422         return true;
00423 }
00424 
00425 
00426 NLMISC_DYNVARIABLE(string, LSListenAddress, "the listen address sended to the client to connect on this front_end")
00427 {
00428         if (get)
00429         {
00430                 *pointer = ListenAddr;
00431         }
00432         else
00433         {
00434                 if ((*pointer).find (":") == string::npos)
00435                 {
00436                         log.displayNL ("You must set the address + port (ie: \"itsalive.nevrax.org:38000\")");
00437                         return;
00438                 }
00439                 else if ((*pointer).empty())
00440                 {
00441                         ListenAddr = Server->listenAddress ().asIPString();
00442                 }
00443                 else
00444                 {
00445                         ListenAddr = *pointer;
00446                 }
00447                 log.displayNL ("Listen Address trapped '%s'", ListenAddr.c_str());
00448         }
00449 }
00450 
00451 
00452 } // NLNET
00453 
00454 
00458 /*
00459 #include "v2/service.h"
00460 
00461 using namespace std;
00462 using namespace NLNET;
00463 
00464 void ClientConnection (TSockId from, const CLoginCookie &cookie)
00465 {
00466         nlinfo("player (%d) comes in", cookie.getUserId());
00467         from->setAppId (cookie.getUserId());
00468 }
00469 
00470 void ClientDisconnection (TSockId from, void *arg)
00471 {
00472         nlinfo("player (%d) leaves", from->appId());
00473         CLoginServer::clientDisconnected (from->appId());
00474 
00475 }
00476 
00477 class CFrontEndService : public NLNET::IService
00478 {
00479 public:
00480 
00482         void init ()
00483         {
00484                 CLoginServer::init (dynamic_cast<CCallbackServer&>(*CNetManager::getNetBase ("FES")), ClientConnection);
00485                 CNetManager::getNetBase ("FES")->setDisconnectionCallback (ClientDisconnection, NULL);
00486         }
00487 };
00488 
00489 
00491 NLNET_SERVICE_MAIN (CFrontEndService, "FES", "front_end_service", 0);
00492 */