Return to naming_client.cpp CVS log | Up to Nevrax / code / nel / src / net |
File: Nevrax / code / nel / src / net / naming_client.cpp (download) Revision 1.48, Thu Jul 18 15:00:43 2002 UTC (10 days, 18 hours ago) by lecroart Branch: MAIN CVS Tags: HEAD Changes since 1.47: +15 -1 lines ADDED: quit if the NS ask it |
/** \file naming_client.cpp * CNamingClient * * $Id: naming_client.cpp,v 1.48 2002/07/18 15:00:43 lecroart Exp $ * */ /* Copyright, 2000 Nevrax Ltd. * * This file is part of NEVRAX NEL. * NEVRAX NEL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * NEVRAX NEL 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 * General Public License for more details. * You should have received a copy of the GNU General Public License * along with NEVRAX NEL; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ // // Includes // #include "stdnet.h" #include "nel/net/naming_client.h" #include "nel/net/callback_client.h" #include "nel/net/service.h" // // Namespaces // using namespace std; using namespace NLMISC; namespace NLNET { // // Variables // CCallbackClient *CNamingClient::_Connection = NULL; CNamingClient::TRegServices CNamingClient::_RegisteredServices; static TBroadcastCallback _RegistrationBroadcastCallback = NULL; static TBroadcastCallback _UnregistrationBroadcastCallback = NULL; uint CNamingClient::_ThreadId = 0xFFFFFFFF; TServiceId CNamingClient::_MySId = 0; std::list<CNamingClient::CServiceEntry> CNamingClient::RegisteredServices; NLMISC::CMutex CNamingClient::RegisteredServicesMutex("CNamingClient::RegisteredServicesMutex"); void CNamingClient::setRegistrationBroadcastCallback (TBroadcastCallback cb) { _RegistrationBroadcastCallback = cb; } void CNamingClient::setUnregistrationBroadcastCallback (TBroadcastCallback cb) { _UnregistrationBroadcastCallback = cb; } // // static bool Registered; static TServiceId RegisteredSuccess; static TServiceId RegisteredSID; static void cbRegister (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { msgin.serial (RegisteredSuccess); if (RegisteredSuccess) msgin.serial (RegisteredSID); Registered = true; } // static bool QueryPort; static uint16 QueryPortPort; static void cbQueryPort (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { msgin.serial (QueryPortPort); QueryPort = true; } // static bool FirstRegisteredBroadcast; void cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { TServiceId size; string name; TServiceId sid; CInetAddress addr; msgin.serial (size); for (TServiceId i = 0; i < size; i++) { msgin.serial (name); msgin.serial (sid); msgin.serial (addr); // add it in the list std::vector<CInetAddress> addrs; CNamingClient::find (sid, addrs); if (addrs.size() == 0) { CNamingClient::RegisteredServicesMutex.enter (); CNamingClient::RegisteredServices.push_back (CNamingClient::CServiceEntry (name, sid, addr)); CNamingClient::RegisteredServicesMutex.leave (); nlinfo ("NC: Registration Broadcast of the service %s-%hu '%s'", name.c_str(), (uint16)sid, addr.asString().c_str()); if (_RegistrationBroadcastCallback != NULL) _RegistrationBroadcastCallback (name, sid, addr); } else if (addrs.size() == 1) { CNamingClient::RegisteredServicesMutex.enter (); for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++) { if (sid == (*it).SId) { (*it).Name = name; (*it).Addr = addr; break; } } CNamingClient::RegisteredServicesMutex.leave (); nlinfo ("NC: Registration Broadcast (update) of the service %s-%hu '%s'", name.c_str(), (uint16)sid, addr.asString().c_str()); } else { nlstop; } } FirstRegisteredBroadcast = true; //CNamingClient::displayRegisteredServices (); } // void cbUnregisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { string name; TServiceId sid; CInetAddress addr; msgin.serial (name); msgin.serial (sid); msgin.serial (addr); // remove it in the list, if the service is not found, ignore it CNamingClient::RegisteredServicesMutex.enter (); for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++) { if ((*it).SId == sid) { // check the structure nlassertex ((*it).Name == name, ("%s %s",(*it).Name.c_str(), name.c_str())); nlassertex ((*it).Addr == addr, ("%d %d",(*it).Addr.asString().c_str(), addr.asString().c_str())); CNamingClient::RegisteredServices.erase (it); break; } } CNamingClient::RegisteredServicesMutex.leave (); nlinfo ("NC: Unregistration Broadcast of the service %s-%hu", name.c_str(), (uint16)sid); // send the ACK to the NS CMessage msgout (CNamingClient::_Connection->getSIDA(), "ACK_UNI"); msgout.serial (sid); CNamingClient::_Connection->send (msgout); // 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! if(CNamingClient::_MySId == sid) { nlwarning ("Naming Service asked me to leave, I leave!"); IService::getInstance()->exit(); return; } if (_UnregistrationBroadcastCallback != NULL) _UnregistrationBroadcastCallback (name, sid, addr); //CNamingClient::displayRegisteredServices (); } // static TCallbackItem NamingClientCallbackArray[] = { { "RG", cbRegister }, { "QP", cbQueryPort }, { "RGB", cbRegisterBroadcast }, { "UNB", cbUnregisterBroadcast }, }; void CNamingClient::connect( const CInetAddress &addr, CCallbackNetBase::TRecordingState rec ) { nlassert (_Connection == NULL || _Connection != NULL && !_Connection->connected ()); _ThreadId = getThreadId (); if (_Connection == NULL) { _Connection = new CCallbackClient( rec, "naming_client.nmr" ); _Connection->addCallbackArray (NamingClientCallbackArray, sizeof (NamingClientCallbackArray) / sizeof (NamingClientCallbackArray[0])); } _Connection->connect (addr); // now we are connected, clear the old registered service table /* CNamingClient::RegisteredServicesMutex.enter (); CNamingClient::RegisteredServices.clear (); CNamingClient::RegisteredServicesMutex.leave (); */ // wait the message that contains all already connected services FirstRegisteredBroadcast = false; while (!FirstRegisteredBroadcast && _Connection->connected ()) { _Connection->update (-1); nlSleep (1); } } void CNamingClient::disconnect () { checkThreadId (); if (_Connection != NULL) { if (_Connection->connected ()) { _Connection->disconnect (); } delete _Connection; _Connection = NULL; } // we don't call unregisterAllServices because when the naming service will see the disconnection, // it'll automatically unregister all services registered by this client. } string CNamingClient::info () { string res; if (connected ()) { res = "connected to "; res += _Connection->remoteAddress().asString(); } else { res = "Not connected"; } return res; } TServiceId CNamingClient::registerService (const std::string &name, const CInetAddress &addr) { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); CMessage msgout (_Connection->getSIDA(), "RG"); msgout.serial (const_cast<std::string&>(name)); msgout.serial (const_cast<CInetAddress&>(addr)); TServiceId sid = 0; msgout.serial (sid); _Connection->send (msgout); // wait the answer of the naming service "RG" Registered = false; while (!Registered) { _Connection->update (-1); nlSleep (1); } if (RegisteredSuccess) { _MySId = RegisteredSID; _RegisteredServices.insert (make_pair (RegisteredSID, name)); nldebug ("NC: Registered service %s-%hu at %s", name.c_str(), (uint16)RegisteredSID, addr.asString().c_str()); } else { nlerror ("NC: Naming service refused to register service %s at %s", name.c_str(), addr.asString().c_str()); } return RegisteredSID; } bool CNamingClient::registerServiceWithSId (const std::string &name, const CInetAddress &addr, TServiceId sid) { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); CMessage msgout (_Connection->getSIDA(), "RG"); msgout.serial (const_cast<std::string&>(name)); msgout.serial (const_cast<CInetAddress&>(addr)); msgout.serial (sid); _Connection->send (msgout); // wait the answer of the naming service "RGI" Registered = false; while (!Registered) { _Connection->update (-1); nlSleep (1); } if (RegisteredSuccess) { _MySId = sid; _RegisteredServices.insert (make_pair (RegisteredSID, name)); nldebug ("NC: Registered service with sid %s-%hu at %s", name.c_str(), (uint16)RegisteredSID, addr.asString().c_str()); } else { nlerror ("NC: Naming service refused to register service with sid %s at %s", name.c_str(), addr.asString().c_str()); } return RegisteredSuccess == 1; } void CNamingClient::resendRegisteration (const std::string &name, const CInetAddress &addr, TServiceId sid) { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); CMessage msgout (_Connection->getSIDA(), "RRG"); msgout.serial (const_cast<std::string&>(name)); msgout.serial (const_cast<CInetAddress&>(addr)); msgout.serial (sid); _Connection->send (msgout); } void CNamingClient::unregisterService (TServiceId sid) { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); CMessage msgout (_Connection->getSIDA(), "UNI"); msgout.serial (sid); _Connection->send (msgout); nldebug ("NC: Unregistering service %s-%hu", _RegisteredServices[sid].c_str(), sid); _RegisteredServices.erase (sid); } void CNamingClient::unregisterAllServices () { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); while (!_RegisteredServices.empty()) { TRegServices::iterator irs = _RegisteredServices.begin(); TServiceId sid = (*irs).first; unregisterService (sid); } } uint16 CNamingClient::queryServicePort () { checkThreadId (); nlassert (_Connection != NULL && _Connection->connected ()); CMessage msgout (_Connection->getSIDA(), "QP"); _Connection->send (msgout); // wait the answer of the naming service "QP" QueryPort = false; while (!QueryPort) { _Connection->update (-1); nlSleep (1); } nlinfo ("NC: Received the answer of the query port (%hu)", QueryPortPort); return QueryPortPort; } bool CNamingClient::lookup (const std::string &name, CInetAddress &addr) { nlassert (_Connection != NULL && _Connection->connected ()); vector<CInetAddress> addrs; find (name, addrs); if (addrs.size()==0) return false; nlassert (addrs.size()==1); addr = addrs[0]; return true; } bool CNamingClient::lookup (TServiceId sid, CInetAddress &addr) { nlassert (_Connection != NULL && _Connection->connected ()); vector<CInetAddress> addrs; find (sid, addrs); if (addrs.size()==0) return false; nlassert (addrs.size()==1); addr = addrs[0]; return true; } /// \todo ace: now the lookupAlternate doesn't say to the naming service that this addr is bad so the NS can't remove it from his list. find a solution bool CNamingClient::lookupAlternate (const std::string &name, CInetAddress &addr) { nlassert (_Connection != NULL && _Connection->connected ()); // remove it from his local list RegisteredServicesMutex.enter (); for (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).Addr == addr) { RegisteredServices.erase (it); break; } } RegisteredServicesMutex.leave (); vector<CInetAddress> addrs; find (name, addrs); if (addrs.size()==0) return false; nlassert (addrs.size()==1); addr = addrs[0]; return true; } void CNamingClient::lookupAll (const std::string &name, std::vector<CInetAddress> &addrs) { nlassert (_Connection != NULL && _Connection->connected ()); find (name, addrs); } bool CNamingClient::lookupAndConnect (const std::string &name, CCallbackClient &sock) { nlassert (_Connection != NULL && _Connection->connected ()); // look up for service CInetAddress servaddr; // if service not found, return false if (!CNamingClient::lookup (name, servaddr)) return false; do { try { // try to connect to the server sock.connect (servaddr); // connection succeeded return true; } catch (ESocketConnectionFailed &e) { nldebug( "Connection to %s failed: %s, tring another service if available", servaddr.asString().c_str(), e.what() ); // try another server and if service is not found, return false if (!CNamingClient::lookupAlternate (name, servaddr)) return false; } } while (true); } void CNamingClient::update () { checkThreadId (); // get message for naming service (new registration for example) if (_Connection != NULL && _Connection->connected ()) _Connection->update (); } void CNamingClient::checkThreadId () { if (getThreadId () != _ThreadId) { nlerror ("You try to access to the CNamingClient with 2 differents thread (%d and %d)", _ThreadId, getThreadId()); } } // // Commands // NLMISC_COMMAND(services, "displays registered services", "") { if(args.size() != 0) return false; log.displayNL ("Display the %d registered services :", CNamingClient::getRegisteredServices().size()); for (std::list<CNamingClient::CServiceEntry>::const_iterator it = CNamingClient::getRegisteredServices().begin(); it != CNamingClient::getRegisteredServices().end(); it++) { log.displayNL (" > %s-%hu '%s'", (*it).Name.c_str(), (uint16)(*it).SId, (*it).Addr.asString().c_str()); } log.displayNL ("End ot the list"); return true; } } // NLNET