Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / naming_client.cpp
blob7e2fd5ec9f1d7169440c4f2ec93f6604bdc644f7
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
18 // Includes
21 #include "stdnet.h"
23 #include "nel/net/naming_client.h"
24 #include "nel/net/callback_client.h"
25 #include "nel/net/service.h"
29 // Namespaces
32 using namespace std;
33 using namespace NLMISC;
36 namespace NLNET {
39 // Variables
42 CCallbackClient *CNamingClient::_Connection = NULL;
43 CNamingClient::TRegServices CNamingClient::_RegisteredServices;
45 static TBroadcastCallback _RegistrationBroadcastCallback = NULL;
46 static TBroadcastCallback _UnregistrationBroadcastCallback = NULL;
48 TServiceId CNamingClient::_MySId(0);
50 std::list<CNamingClient::CServiceEntry> CNamingClient::RegisteredServices;
51 NLMISC::CMutex CNamingClient::RegisteredServicesMutex("CNamingClient::RegisteredServicesMutex");
57 void CNamingClient::setRegistrationBroadcastCallback (TBroadcastCallback cb)
59 _RegistrationBroadcastCallback = cb;
62 void CNamingClient::setUnregistrationBroadcastCallback (TBroadcastCallback cb)
64 _UnregistrationBroadcastCallback = cb;
71 static bool Registered;
72 static bool RegisteredSuccess;
73 static TServiceId *RegisteredSID = NULL;
74 static string Reason;
75 void cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);
77 static void cbRegister (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
79 nlassert(RegisteredSID != NULL);
81 msgin.serial (RegisteredSuccess);
82 if (RegisteredSuccess)
84 msgin.serial (*RegisteredSID);
86 // decode the registered services at the register process
87 cbRegisterBroadcast (msgin, from, netbase);
89 else
91 msgin.serial( Reason );
93 Registered = true;
98 static bool QueryPort;
99 static uint16 QueryPortPort;
101 static void cbQueryPort (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)
103 msgin.serial (QueryPortPort);
104 QueryPort = true;
109 //static bool FirstRegisteredBroadcast;
111 void cbRegisterBroadcast (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)
113 TServiceId::size_type size;
114 string name;
115 TServiceId sid;
116 vector<CInetAddress> addr;
118 msgin.serial (size);
120 for (TServiceId::size_type i = 0; i < size; i++)
122 msgin.serial (name);
123 msgin.serial (sid);
124 msgin.serialCont (addr);
126 // add it in the list
128 std::vector<CInetAddress> addrs;
129 CNamingClient::find (sid, addrs);
131 if (addrs.empty())
133 CNamingClient::RegisteredServicesMutex.enter ();
134 CNamingClient::RegisteredServices.push_back (CNamingClient::CServiceEntry (name, sid, addr));
135 CNamingClient::RegisteredServicesMutex.leave ();
137 nlinfo ("NC: Registration Broadcast of the service %s-%hu '%s'", name.c_str(), sid.get(), vectorCInetAddressToString(addr).c_str());
139 if (_RegistrationBroadcastCallback != NULL)
140 _RegistrationBroadcastCallback (name, sid, addr);
142 else if (addrs.size() == 1)
144 CNamingClient::RegisteredServicesMutex.enter ();
145 for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)
147 if (sid == (*it).SId)
149 (*it).Name = name;
150 (*it).Addr = addr;
151 break;
154 CNamingClient::RegisteredServicesMutex.leave ();
155 nlinfo ("NC: Registration Broadcast (update) of the service %s-%hu '%s'", name.c_str(), sid.get(), addr[0].asString().c_str());
157 else
159 nlstop;
163 // FirstRegisteredBroadcast = true;
165 //CNamingClient::displayRegisteredServices ();
170 void cbUnregisterBroadcast (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)
172 string name;
173 TServiceId sid;
174 vector<CInetAddress> addrs;
176 msgin.serial (name);
177 msgin.serial (sid);
179 // remove it in the list, if the service is not found, ignore it
181 CNamingClient::RegisteredServicesMutex.enter ();
182 for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)
184 CNamingClient::CServiceEntry &serviceEntry = *it;
185 if (serviceEntry.SId == sid)
187 // check the structure
188 nlassertex (serviceEntry.Name == name, ("%s %s",serviceEntry.Name.c_str(), name.c_str()));
190 addrs = serviceEntry.Addr;
192 CNamingClient::RegisteredServices.erase (it);
193 break;
196 CNamingClient::RegisteredServicesMutex.leave ();
198 nlinfo ("NC: Unregistration Broadcast of the service %s-%hu", name.c_str(), sid.get());
200 // send the ACK to the NS
202 CMessage msgout ("ACK_UNI");
203 msgout.serial (sid);
204 CNamingClient::_Connection->send (msgout);
206 // 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!
207 if(CNamingClient::_MySId == sid)
209 nlwarning ("NC: Naming Service asked me to leave, I leave!");
210 IService::getInstance()->exit();
211 return;
214 if (_UnregistrationBroadcastCallback != NULL)
215 _UnregistrationBroadcastCallback (name, sid, addrs);
217 //CNamingClient::displayRegisteredServices ();
223 static TCallbackItem NamingClientCallbackArray[] =
225 { "RG", cbRegister },
226 { "QP", cbQueryPort },
228 { "RGB", cbRegisterBroadcast },
229 { "UNB", cbUnregisterBroadcast }
232 void CNamingClient::connect( const CInetAddress &addr, CCallbackNetBase::TRecordingState rec, const vector<CInetAddress> &/* addresses */ )
234 nlassert (_Connection == NULL || (_Connection != NULL && !_Connection->connected ()));
236 if (_Connection == NULL)
238 _Connection = new CCallbackClient( rec, "naming_client.nmr" );
239 _Connection->addCallbackArray (NamingClientCallbackArray, sizeof (NamingClientCallbackArray) / sizeof (NamingClientCallbackArray[0]));
242 _Connection->connect (addr);
244 /* // send the available addresses
245 CMessage msgout ("RS");
246 msgout.serialCont (const_cast<vector<CInetAddress>&>(addresses));
247 _Connection->send (msgout);
249 // wait the message that contains all already connected services
250 FirstRegisteredBroadcast = false;
251 while (!FirstRegisteredBroadcast && _Connection->connected ())
253 _Connection->update (-1);
254 nlSleep (1);
259 void CNamingClient::disconnect ()
261 if (_Connection != NULL)
263 if (_Connection->connected ())
265 _Connection->disconnect ();
267 delete _Connection;
268 _Connection = NULL;
271 // we don't call unregisterAllServices because when the naming service will see the disconnection,
272 // it'll automatically unregister all services registered by this client.
275 string CNamingClient::info ()
277 string res;
279 if (connected ())
281 res = "connected to ";
282 res += _Connection->remoteAddress().asString();
284 else
286 res = "Not connected";
289 return res;
292 bool CNamingClient::registerService (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId &sid)
294 nlassert (_Connection != NULL && _Connection->connected ());
296 CMessage msgout ("RG");
297 msgout.serial (const_cast<std::string&>(name));
298 msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
299 sid.set(0);
300 msgout.serial (sid);
301 _Connection->send (msgout);
303 // wait the answer of the naming service "RG"
304 Registered = false;
305 RegisteredSID = &sid;
306 while (!Registered)
308 _Connection->update (-1);
309 nlSleep (1);
311 if (RegisteredSuccess)
313 _MySId = sid;
314 _RegisteredServices.insert (make_pair (*RegisteredSID, name));
315 nldebug ("NC: Registered service %s-%hu at %s", name.c_str(), sid.get(), addr[0].asString().c_str());
317 else
319 nldebug ("NC: Naming service refused to register service %s at %s", name.c_str(), addr[0].asString().c_str());
320 nlwarning ("NC: Startup denied: %s", Reason.c_str());
321 Reason.clear();
324 RegisteredSID = NULL;
326 return RegisteredSuccess;
329 bool CNamingClient::registerServiceWithSId (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)
331 nlassert (_Connection != NULL && _Connection->connected ());
333 CMessage msgout ("RG");
334 msgout.serial (const_cast<std::string&>(name));
335 msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
336 msgout.serial (sid);
337 _Connection->send (msgout);
339 // wait the answer of the naming service "RGI"
340 Registered = false;
341 RegisteredSID = &sid;
342 while (!Registered)
344 _Connection->update (-1);
345 nlSleep (1);
347 if (RegisteredSuccess)
349 _MySId = sid;
350 _RegisteredServices.insert (make_pair (*RegisteredSID, name));
351 nldebug ("NC: Registered service with sid %s-%hu at %s", name.c_str(), RegisteredSID->get(), addr[0].asString().c_str());
353 else
355 nlerror ("NC: Naming service refused to register service with sid %s at %s", name.c_str(), addr[0].asString().c_str());
358 return RegisteredSuccess == 1;
361 void CNamingClient::resendRegisteration (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)
363 nlassert (_Connection != NULL && _Connection->connected ());
365 CMessage msgout ("RRG");
366 msgout.serial (const_cast<std::string&>(name));
367 msgout.serialCont (const_cast<vector<CInetAddress>&>(addr));
368 msgout.serial (sid);
369 _Connection->send (msgout);
372 void CNamingClient::unregisterService (TServiceId sid)
374 nlassert (_Connection != NULL && _Connection->connected ());
376 CMessage msgout ("UNI");
377 msgout.serial (sid);
378 _Connection->send (msgout);
380 nldebug ("NC: Unregistering service %s-%hu", _RegisteredServices[sid].c_str(), sid.get());
381 _RegisteredServices.erase (sid);
384 void CNamingClient::unregisterAllServices ()
386 nlassert (_Connection != NULL && _Connection->connected ());
388 while (!_RegisteredServices.empty())
390 TRegServices::iterator irs = _RegisteredServices.begin();
391 TServiceId sid = (*irs).first;
392 unregisterService (sid);
396 uint16 CNamingClient::queryServicePort ()
398 nlassert (_Connection != NULL && _Connection->connected ());
400 CMessage msgout ("QP");
401 _Connection->send (msgout);
403 // wait the answer of the naming service "QP"
404 QueryPort = false;
405 while (!QueryPort)
407 _Connection->update (-1);
408 nlSleep (1);
411 nlinfo ("NC: Received the answer of the query port (%hu)", QueryPortPort);
413 return QueryPortPort;
416 bool CNamingClient::lookup (const std::string &name, CInetAddress &addr)
418 nlassert (_Connection != NULL && _Connection->connected ());
420 vector<CInetAddress> addrs;
421 find (name, addrs);
423 if (addrs.empty())
424 return false;
426 nlassert (addrs.size()==1);
427 addr = addrs[0];
429 return true;
432 bool CNamingClient::lookup (TServiceId sid, CInetAddress &addr)
434 nlassert (_Connection != NULL && _Connection->connected ());
436 vector<CInetAddress> addrs;
437 find (sid, addrs);
439 if (addrs.empty())
440 return false;
442 nlassert (addrs.size()==1);
443 addr = addrs[0];
445 return true;
448 bool CNamingClient::lookupAlternate (const std::string &name, CInetAddress &addr)
450 nlassert (_Connection != NULL && _Connection->connected ());
452 // remove it from his local list
454 RegisteredServicesMutex.enter ();
455 for (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
457 if ((*it).Addr[0] == addr)
459 RegisteredServices.erase (it);
460 break;
463 RegisteredServicesMutex.leave ();
465 vector<CInetAddress> addrs;
466 find (name, addrs);
468 if (addrs.empty())
469 return false;
471 nlassert (addrs.size()==1);
472 addr = addrs[0];
474 return true;
477 void CNamingClient::lookupAll (const std::string &name, std::vector<CInetAddress> &addrs)
479 nlassert (_Connection != NULL && _Connection->connected ());
481 find (name, addrs);
484 bool CNamingClient::lookupAndConnect (const std::string &name, CCallbackClient &sock)
486 nlassert (_Connection != NULL && _Connection->connected ());
488 // look up for service
489 CInetAddress servaddr;
491 // if service not found, return false
492 if (!CNamingClient::lookup (name, servaddr))
493 return false;
495 for(;;)
499 // try to connect to the server
500 sock.connect (servaddr);
502 // connection succeeded
503 return true;
505 catch (const ESocketConnectionFailed &e)
507 nldebug( "NC: Connection to %s failed: %s, tring another service if available", servaddr.asString().c_str(), e.what() );
509 // try another server and if service is not found, return false
510 if (!CNamingClient::lookupAlternate (name, servaddr))
511 return false;
518 void CNamingClient::update ()
520 // get message for naming service (new registration for example)
521 if (_Connection != NULL && _Connection->connected ())
522 _Connection->update ();
526 // Commands
529 NLMISC_CATEGORISED_COMMAND(nel, services, "displays registered services", "")
531 nlunreferenced(rawCommandString);
532 nlunreferenced(quiet);
533 nlunreferenced(human);
535 if(args.size() != 0) return false;
537 CNamingClient::displayRegisteredServices (&log);
539 return true;
542 } // NLNET