1 // NeL - 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/>.
23 #include "nel/net/naming_client.h"
24 #include "nel/net/callback_client.h"
25 #include "nel/net/service.h"
33 using namespace NLMISC
;
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
;
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
);
91 msgin
.serial( Reason
);
98 static bool QueryPort
;
99 static uint16 QueryPortPort
;
101 static void cbQueryPort (CMessage
&msgin
, TSockId
/* from */, CCallbackNetBase
&/* netbase */)
103 msgin
.serial (QueryPortPort
);
109 //static bool FirstRegisteredBroadcast;
111 void cbRegisterBroadcast (CMessage
&msgin
, TSockId
/* from */, CCallbackNetBase
&/* netbase */)
113 TServiceId::size_type size
;
116 vector
<CInetAddress
> addr
;
120 for (TServiceId::size_type i
= 0; i
< size
; i
++)
124 msgin
.serialCont (addr
);
126 // add it in the list
128 std::vector
<CInetAddress
> addrs
;
129 CNamingClient::find (sid
, addrs
);
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
)
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());
163 // FirstRegisteredBroadcast = true;
165 //CNamingClient::displayRegisteredServices ();
170 void cbUnregisterBroadcast (CMessage
&msgin
, TSockId
/* from */, CCallbackNetBase
&/* netbase */)
174 vector
<CInetAddress
> addrs
;
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
);
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");
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();
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);
259 void CNamingClient::disconnect ()
261 if (_Connection
!= NULL
)
263 if (_Connection
->connected ())
265 _Connection
->disconnect ();
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 ()
281 res
= "connected to ";
282 res
+= _Connection
->remoteAddress().asString();
286 res
= "Not connected";
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
));
301 _Connection
->send (msgout
);
303 // wait the answer of the naming service "RG"
305 RegisteredSID
= &sid
;
308 _Connection
->update (-1);
311 if (RegisteredSuccess
)
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());
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());
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
));
337 _Connection
->send (msgout
);
339 // wait the answer of the naming service "RGI"
341 RegisteredSID
= &sid
;
344 _Connection
->update (-1);
347 if (RegisteredSuccess
)
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());
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
));
369 _Connection
->send (msgout
);
372 void CNamingClient::unregisterService (TServiceId sid
)
374 nlassert (_Connection
!= NULL
&& _Connection
->connected ());
376 CMessage
msgout ("UNI");
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"
407 _Connection
->update (-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
;
426 nlassert (addrs
.size()==1);
432 bool CNamingClient::lookup (TServiceId sid
, CInetAddress
&addr
)
434 nlassert (_Connection
!= NULL
&& _Connection
->connected ());
436 vector
<CInetAddress
> addrs
;
442 nlassert (addrs
.size()==1);
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
);
463 RegisteredServicesMutex
.leave ();
465 vector
<CInetAddress
> addrs
;
471 nlassert (addrs
.size()==1);
477 void CNamingClient::lookupAll (const std::string
&name
, std::vector
<CInetAddress
> &addrs
)
479 nlassert (_Connection
!= NULL
&& _Connection
->connected ());
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
))
499 // try to connect to the server
500 sock
.connect (servaddr
);
502 // connection succeeded
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
))
518 void CNamingClient::update ()
520 // get message for naming service (new registration for example)
521 if (_Connection
!= NULL
&& _Connection
->connected ())
522 _Connection
->update ();
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
);