# 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  

naming_client.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 //
00028 // Includes
00029 //
00030 
00031 #include "stdnet.h"
00032 
00033 #include "nel/net/naming_client.h"
00034 #include "nel/net/callback_client.h"
00035 #include "nel/net/service.h"
00036 
00037 
00038 //
00039 // Namespaces
00040 //
00041 
00042 using namespace std;
00043 using namespace NLMISC;
00044 
00045 
00046 namespace NLNET {
00047 
00048 //
00049 // Variables
00050 //
00051 
00052 CCallbackClient *CNamingClient::_Connection = NULL;
00053 CNamingClient::TRegServices CNamingClient::_RegisteredServices;
00054 
00055 static TBroadcastCallback _RegistrationBroadcastCallback = NULL;
00056 static TBroadcastCallback _UnregistrationBroadcastCallback = NULL;
00057 
00058 uint    CNamingClient::_ThreadId = 0xFFFFFFFF;
00059 
00060 TServiceId CNamingClient::_MySId = 0;
00061 
00062 
00063 std::list<CNamingClient::CServiceEntry> CNamingClient::RegisteredServices;
00064 NLMISC::CMutex CNamingClient::RegisteredServicesMutex("CNamingClient::RegisteredServicesMutex");
00065 
00066 void CNamingClient::setRegistrationBroadcastCallback (TBroadcastCallback cb)
00067 {
00068         _RegistrationBroadcastCallback = cb;    
00069 }
00070 
00071 void CNamingClient::setUnregistrationBroadcastCallback (TBroadcastCallback cb)
00072 {
00073         _UnregistrationBroadcastCallback = cb;  
00074 }
00075 
00076 //
00077 
00078 //
00079 
00080 static bool Registered;
00081 static TServiceId RegisteredSuccess;
00082 static TServiceId *RegisteredSID = NULL;
00083 
00084 static void cbRegister (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00085 {
00086         nlassert(RegisteredSID != NULL);
00087 
00088         msgin.serial (RegisteredSuccess);
00089         if (RegisteredSuccess)
00090         {
00091                 msgin.serial (*RegisteredSID);
00092 
00093                 // decode the registered services at the register process
00094                 cbRegisterBroadcast (msgin, from, netbase);
00095         }
00096         Registered = true;
00097 }
00098 
00099 //
00100 
00101 static bool QueryPort;
00102 static uint16 QueryPortPort;
00103 
00104 static void cbQueryPort (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00105 {
00106         msgin.serial (QueryPortPort);
00107         QueryPort = true;
00108 }
00109 
00110 //
00111 
00112 //static bool FirstRegisteredBroadcast;
00113 
00114 void cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00115 {
00116         TServiceId size;
00117         string name;
00118         TServiceId sid;
00119         vector<CInetAddress> addr;
00120 
00121         msgin.serial (size);
00122 
00123         for (TServiceId i = 0; i < size; i++)
00124         {
00125                 msgin.serial (name);
00126                 msgin.serial (sid);
00127                 msgin.serialCont (addr);
00128 
00129                 // add it in the list
00130 
00131                 std::vector<CInetAddress> addrs;
00132                 CNamingClient::find (sid, addrs);
00133 
00134                 if (addrs.size() == 0)
00135                 {
00136                         CNamingClient::RegisteredServicesMutex.enter ();
00137                         CNamingClient::RegisteredServices.push_back (CNamingClient::CServiceEntry (name, sid, addr));
00138                         CNamingClient::RegisteredServicesMutex.leave ();
00139 
00140                         nlinfo ("NC: Registration Broadcast of the service %s-%hu '%s'", name.c_str(), (uint16)sid, vectorCInetAddressToString(addr).c_str());
00141 
00142                         if (_RegistrationBroadcastCallback != NULL)
00143                                 _RegistrationBroadcastCallback (name, sid, addr);
00144                 }
00145                 else if (addrs.size() == 1)
00146                 {
00147                         CNamingClient::RegisteredServicesMutex.enter ();
00148                         for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)
00149                         {
00150                                 if (sid == (*it).SId)
00151                                 {
00152                                         (*it).Name = name;
00153                                         (*it).Addr = addr;
00154                                         break;
00155                                 }
00156                         }
00157                         CNamingClient::RegisteredServicesMutex.leave ();
00158                         nlinfo ("NC: Registration Broadcast (update) of the service %s-%hu '%s'", name.c_str(), (uint16)sid, addr[0].asString().c_str());
00159                 }
00160                 else
00161                 {
00162                         nlstop;
00163                 }
00164         }
00165 
00166 //      FirstRegisteredBroadcast = true;
00167 
00168         //CNamingClient::displayRegisteredServices ();
00169 }
00170         
00171 //
00172 
00173 void cbUnregisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00174 {
00175         string name;
00176         TServiceId sid;
00177         vector<CInetAddress> addrs;
00178 
00179         msgin.serial (name);
00180         msgin.serial (sid);
00181 
00182         // remove it in the list, if the service is not found, ignore it
00183 
00184         CNamingClient::RegisteredServicesMutex.enter ();
00185         for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)
00186         {
00187                 if ((*it).SId == sid)
00188                 {
00189                         // check the structure
00190                         nlassertex ((*it).Name == name, ("%s %s",(*it).Name.c_str(), name.c_str()));
00191 
00192                         addrs = (*it).Addr;
00193 
00194                         CNamingClient::RegisteredServices.erase (it);
00195                         break;
00196                 }
00197         }
00198         CNamingClient::RegisteredServicesMutex.leave ();
00199 
00200         nlinfo ("NC: Unregistration Broadcast of the service %s-%hu", name.c_str(), (uint16)sid);
00201 
00202         // send the ACK to the NS
00203 
00204         CMessage msgout (CNamingClient::_Connection->getSIDA(), "ACK_UNI");
00205         msgout.serial (sid);
00206         CNamingClient::_Connection->send (msgout);
00207 
00208         // oh my god, it s my sid! but i m alive, why this f*cking naming service want to kill me? ok, i leave it alone!
00209         if(CNamingClient::_MySId == sid)
00210         {
00211                 nlwarning ("Naming Service asked me to leave, I leave!");
00212                 IService::getInstance()->exit();
00213                 return;
00214         }
00215 
00216         if (_UnregistrationBroadcastCallback != NULL)
00217                 _UnregistrationBroadcastCallback (name, sid, addrs);
00218 
00219         //CNamingClient::displayRegisteredServices ();
00220 }
00221 
00222 //
00223 
00224 static TCallbackItem NamingClientCallbackArray[] =
00225 {
00226         { "RG", cbRegister },
00227         { "QP", cbQueryPort },
00228 
00229         { "RGB", cbRegisterBroadcast },
00230         { "UNB", cbUnregisterBroadcast },
00231 };
00232 
00233 void CNamingClient::connect( const CInetAddress &addr, CCallbackNetBase::TRecordingState rec, const vector<CInetAddress> &addresses )
00234 {
00235         nlassert (_Connection == NULL || _Connection != NULL && !_Connection->connected ());
00236         _ThreadId = getThreadId ();
00237 
00238         if (_Connection == NULL)
00239         {
00240                 _Connection = new CCallbackClient( rec, "naming_client.nmr" );
00241                 _Connection->addCallbackArray (NamingClientCallbackArray, sizeof (NamingClientCallbackArray) / sizeof (NamingClientCallbackArray[0]));
00242         }
00243 
00244         _Connection->connect (addr);
00245 
00246 /*      // send the available addresses
00247         CMessage msgout (_Connection->getSIDA(), "RS");
00248         msgout.serialCont (const_cast<vector<CInetAddress>&>(addresses));
00249         _Connection->send (msgout);
00250         
00251         // wait the message that contains all already connected services
00252         FirstRegisteredBroadcast = false;
00253         while (!FirstRegisteredBroadcast && _Connection->connected ())
00254         {
00255                 _Connection->update (-1);
00256                 nlSleep (1);
00257         }
00258 */}
00259 
00260 
00261 void CNamingClient::disconnect ()
00262 {
00263         checkThreadId ();
00264         
00265         if (_Connection != NULL)
00266         {
00267                 if (_Connection->connected ())
00268                 {
00269                         _Connection->disconnect ();
00270                 }
00271                 delete _Connection;
00272                 _Connection = NULL;
00273         }
00274 
00275         // we don't call unregisterAllServices because when the naming service will see the disconnection,
00276         // it'll automatically unregister all services registered by this client.
00277 }
00278 
00279 string CNamingClient::info ()
00280 {
00281         string res;
00282 
00283         if (connected ())
00284         {
00285                 res = "connected to ";
00286                 res += _Connection->remoteAddress().asString();
00287         }
00288         else
00289         {
00290                 res = "Not connected";
00291         }
00292 
00293         return res;
00294 }
00295 
00296 bool CNamingClient::registerService (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId &sid)
00297 {
00298         checkThreadId ();
00299         nlassert (_Connection != NULL && _Connection->connected ());
00300 
00301         CMessage msgout (_Connection->getSIDA(), "RG");
00302         msgout.serial (const_cast<std::string&>(name));
00303         msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
00304         sid = 0;
00305         msgout.serial (sid);
00306         _Connection->send (msgout);
00307 
00308         // wait the answer of the naming service "RG"
00309         Registered = false;
00310         RegisteredSID = &sid;
00311         while (!Registered)
00312         {
00313                 _Connection->update (-1);
00314                 nlSleep (1);
00315         }
00316         if (RegisteredSuccess)
00317         {
00318                 _MySId = sid;
00319                 _RegisteredServices.insert (make_pair (*RegisteredSID, name));
00320                 nldebug ("NC: Registered service %s-%hu at %s", name.c_str(), (uint16)sid, addr[0].asString().c_str());
00321         }
00322         else
00323         {
00324                 nlerror ("NC: Naming service refused to register service %s at %s", name.c_str(), addr[0].asString().c_str());
00325         }
00326 
00327         RegisteredSID = NULL;
00328 
00329         return RegisteredSuccess == 1;
00330 }
00331 
00332 bool CNamingClient::registerServiceWithSId (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)
00333 {
00334         checkThreadId ();
00335         nlassert (_Connection != NULL && _Connection->connected ());
00336 
00337         CMessage msgout (_Connection->getSIDA(), "RG");
00338         msgout.serial (const_cast<std::string&>(name));
00339         msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
00340         msgout.serial (sid);
00341         _Connection->send (msgout);
00342 
00343         // wait the answer of the naming service "RGI"
00344         Registered = false;
00345         RegisteredSID = &sid;
00346         while (!Registered)
00347         {
00348                 _Connection->update (-1);
00349                 nlSleep (1);
00350         }
00351         if (RegisteredSuccess)
00352         {
00353                 _MySId = sid;
00354                 _RegisteredServices.insert (make_pair (*RegisteredSID, name));
00355                 nldebug ("NC: Registered service with sid %s-%hu at %s", name.c_str(), (uint16)RegisteredSID, addr[0].asString().c_str());
00356         }
00357         else
00358         {
00359                 nlerror ("NC: Naming service refused to register service with sid %s at %s", name.c_str(), addr[0].asString().c_str());
00360         }
00361 
00362         return RegisteredSuccess == 1;
00363 }
00364 
00365 void CNamingClient::resendRegisteration (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)
00366 {
00367         checkThreadId ();
00368         nlassert (_Connection != NULL && _Connection->connected ());
00369 
00370         CMessage msgout (_Connection->getSIDA(), "RRG");
00371         msgout.serial (const_cast<std::string&>(name));
00372         msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
00373         msgout.serial (sid);
00374         _Connection->send (msgout);
00375 }
00376 
00377 void CNamingClient::unregisterService (TServiceId sid)
00378 {
00379         checkThreadId ();
00380         nlassert (_Connection != NULL && _Connection->connected ());
00381 
00382         CMessage msgout (_Connection->getSIDA(), "UNI");
00383         msgout.serial (sid);
00384         _Connection->send (msgout);
00385 
00386         nldebug ("NC: Unregistering service %s-%hu", _RegisteredServices[sid].c_str(), sid);
00387         _RegisteredServices.erase (sid);
00388 }
00389 
00390 void CNamingClient::unregisterAllServices ()
00391 {
00392         checkThreadId ();
00393         nlassert (_Connection != NULL && _Connection->connected ());
00394 
00395         while (!_RegisteredServices.empty())
00396         {
00397                 TRegServices::iterator irs = _RegisteredServices.begin();
00398                 TServiceId sid = (*irs).first;
00399                 unregisterService (sid);
00400         }
00401 }
00402 
00403 uint16 CNamingClient::queryServicePort ()
00404 {
00405         checkThreadId ();
00406         nlassert (_Connection != NULL && _Connection->connected ());
00407 
00408         CMessage msgout (_Connection->getSIDA(), "QP");
00409         _Connection->send (msgout);
00410 
00411         // wait the answer of the naming service "QP"
00412         QueryPort = false;
00413         while (!QueryPort)
00414         {
00415                 _Connection->update (-1);
00416                 nlSleep (1);
00417         }
00418 
00419         nlinfo ("NC: Received the answer of the query port (%hu)", QueryPortPort);
00420 
00421         return QueryPortPort;
00422 }
00423 
00424 bool CNamingClient::lookup (const std::string &name, CInetAddress &addr)
00425 {
00426         nlassert (_Connection != NULL && _Connection->connected ());
00427 
00428         vector<CInetAddress> addrs;
00429         find (name, addrs);
00430 
00431         if (addrs.size()==0)
00432                 return false;
00433 
00434         nlassert (addrs.size()==1);
00435         addr = addrs[0];
00436 
00437         return true;
00438 }
00439 
00440 bool CNamingClient::lookup (TServiceId sid, CInetAddress &addr)
00441 {
00442         nlassert (_Connection != NULL && _Connection->connected ());
00443 
00444         vector<CInetAddress> addrs;
00445         find (sid, addrs);
00446 
00447         if (addrs.size()==0)
00448                 return false;
00449 
00450         nlassert (addrs.size()==1);
00451         addr = addrs[0];
00452         
00453         return true;
00454 }
00455 
00457 bool CNamingClient::lookupAlternate (const std::string &name, CInetAddress &addr)
00458 {
00459         nlassert (_Connection != NULL && _Connection->connected ());
00460 
00461         // remove it from his local list
00462         
00463         RegisteredServicesMutex.enter ();
00464         for (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
00465         {
00466                 if ((*it).Addr[0] == addr)
00467                 {
00468                         RegisteredServices.erase (it);
00469                         break;
00470                 }
00471         }
00472         RegisteredServicesMutex.leave ();
00473 
00474         vector<CInetAddress> addrs;
00475         find (name, addrs);
00476 
00477         if (addrs.size()==0)
00478                 return false;
00479 
00480         nlassert (addrs.size()==1);
00481         addr = addrs[0];
00482 
00483         return true;
00484 }
00485 
00486 void CNamingClient::lookupAll (const std::string &name, std::vector<CInetAddress> &addrs)
00487 {
00488         nlassert (_Connection != NULL && _Connection->connected ());
00489 
00490         find (name, addrs);
00491 }
00492 
00493 bool CNamingClient::lookupAndConnect (const std::string &name, CCallbackClient &sock)
00494 {
00495         nlassert (_Connection != NULL && _Connection->connected ());
00496 
00497         // look up for service
00498         CInetAddress servaddr;
00499         
00500         // if service not found, return false
00501         if (!CNamingClient::lookup (name, servaddr))
00502                 return false;
00503 
00504         do
00505         {
00506                 try
00507                 {
00508                         // try to connect to the server
00509                         sock.connect (servaddr);
00510 
00511                         // connection succeeded
00512                         return true;
00513                 }
00514                 catch (ESocketConnectionFailed &e)
00515                 {
00516                         nldebug( "Connection to %s failed: %s, tring another service if available", servaddr.asString().c_str(), e.what() );
00517 
00518                         // try another server and if service is not found, return false
00519                         if (!CNamingClient::lookupAlternate (name, servaddr))
00520                                 return false;
00521                 }
00522         }
00523         while (true);
00524 }
00525 
00526 
00527 
00528 void CNamingClient::update ()
00529 {
00530         checkThreadId ();
00531         // get message for naming service (new registration for example)
00532         if (_Connection != NULL && _Connection->connected ())
00533                 _Connection->update ();
00534 }
00535 
00536 void CNamingClient::checkThreadId ()
00537 {
00538         if (getThreadId () != _ThreadId)
00539         {
00540                 nlerror ("You try to access to the CNamingClient with 2 differents thread (%d and %d)", _ThreadId, getThreadId());
00541         }
00542 }
00543 
00544 
00545 //
00546 // Commands
00547 //
00548 
00549 NLMISC_COMMAND(services, "displays registered services", "")
00550 {
00551         if(args.size() != 0) return false;
00552 
00553         CNamingClient::displayRegisteredServices (&log);
00554 
00555         return true;
00556 }
00557 
00558 } // NLNET