Fix game:addSpawnShapesByZone
[ryzomcore.git] / nelns / naming_service / naming_service.cpp
blob1c0dc465ac998fa05861b32500e1c9b1ceadb7fc
1 // NeLNS - 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/>.
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif // HAVE_CONFIG_H
21 #ifndef NELNS_CONFIG
22 #define NELNS_CONFIG ""
23 #endif // NELNS_CONFIG
25 #ifndef NELNS_LOGS
26 #define NELNS_LOGS ""
27 #endif // NELNS_LOGS
31 // Includes
34 #include "nel/misc/types_nl.h"
36 #include <list>
37 #include <string>
39 #include "nel/misc/debug.h"
40 #include "nel/misc/command.h"
41 #include "nel/misc/variable.h"
42 #include "nel/misc/displayer.h"
44 #include "nel/net/callback_server.h"
45 #include "nel/net/service.h"
46 #include "nel/net/module_manager.h"
49 // Namespaces
52 using namespace std;
54 using namespace NLMISC;
55 using namespace NLNET;
58 NLMISC_COMMAND(test, "none", "none")
60 log.displayNL("Raw cmd line : '%s'", rawCommandString.c_str());
61 log.displayNL("Dumping %u parameters :", args.size());
62 for (uint i=0; i<args.size(); ++i)
64 log.displayNL(" %u : '%s'", i, args[i].c_str());
66 return true;
71 // Structures
74 struct CServiceEntry
76 CServiceEntry (TSockId sock, const vector<CInetAddress> &a, const string &n, TServiceId s) : SockId(sock), Addr(a), Name(n), SId (s), WaitingUnregistration(false) { }
78 TSockId SockId; // the connection between the service and the naming service
79 vector<CInetAddress> Addr; // address to send to the service who wants to lookup this service
80 // it s possible to have more than one addr, anyway, the naming service
81 // will send good address depending of the sub net address of the service
82 string Name; // name of the service
83 TServiceId SId; // id of the service
85 bool WaitingUnregistration; // true if this service is in unregistration process (wait other service ACK)
86 TTime WaitingUnregistrationTime; // time of the beginning of the inregistration process
87 list<TServiceId> WaitingUnregistrationServices; // list of service that we wait the answer
92 // Helper that emulates layer5's send()
93 //void sendToService( uint16 sid, CMessage& msgout );
95 // Helper that emulate layer5's getServiceName()
96 string getServiceName( TServiceId sid );
98 // Helper that returns the first address of a service
99 CInetAddress getHostAddress( TServiceId sid );
101 // Asks a service to stop and tell every one
102 void doUnregisterService (TServiceId sid);
106 * Manager for services instances
107 * (Moved from the TICKS to the NS)
108 * Implementable with layer 5, here implemented in NS (layer 3)
109 * \author Olivier Cado
110 * \author Nevrax France
111 * \date 2003
113 class CServiceInstanceManager
115 public:
117 /// Constructor
118 CServiceInstanceManager();
120 /** Add the name of a service which must not be duplicated
121 * If uniqueOnShard is true, only one service is allowed.
122 * If uniqueOnShard is false, one service is allowed by physical machine.
124 void addUniqueService( const std::string& serviceName, bool uniqueOnShard )
126 _UniqueServices.insert( std::make_pair( serviceName, uniqueOnShard ) );
129 /// Check if a service is allowed to start (if so, add it)
130 bool queryStartService( const std::string& serviceName, TServiceId serviceId, const std::vector<NLNET::CInetAddress> &addr, string& reason );
132 /// Release a service instance
133 void releaseService( NLNET::TServiceId serviceId );
135 /// Display information
136 void displayInfo( NLMISC::CLog *log = NLMISC::InfoLog ) const;
138 /// Make all controlled services quit
139 void killAllServices();
141 private:
143 /// List of restricted services
144 std::map< std::string, bool > _UniqueServices;
146 /// List of granted (online) services
147 std::set< TServiceId > _OnlineServices;
151 CServiceInstanceManager *SIMInstance = NULL;
155 * Constructor
157 CServiceInstanceManager::CServiceInstanceManager()
159 nlassert( ! SIMInstance );
160 SIMInstance = this;
162 // Note: addCallbackArray() done in CRangeMirrorManager::init()
167 * Check if a service is allowed to start. Answer with a GSTS (Grant Start Service) message
169 bool CServiceInstanceManager::queryStartService( const std::string& serviceName, TServiceId serviceId, const vector<CInetAddress> &addr, string& reason )
171 bool grantStarting = true;
172 std::map< std::string, bool >::iterator ius = _UniqueServices.find( serviceName );
173 if ( ius != _UniqueServices.end() )
175 // Service is restricted
176 set< TServiceId >::iterator ios;
177 bool uniqueOnShard = (*ius).second;
178 for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )
180 string name = getServiceName( *ios );
181 if ( name == serviceName )
183 if ( uniqueOnShard )
185 // Only one service by shard is allowed => deny
186 grantStarting = false;
187 reason = toString( "Service %s already found as %hu, must be unique on shard", serviceName.c_str(), ios->get() );
188 nlinfo( reason.c_str() );
189 break;
191 else
193 // Only one service by physical machine is allowed
195 // Implementation for layer5
196 //TSockId hostid1, hostid2;
197 /*CCallbackNetBase *cnb1 = CUnifiedNetwork::getInstance()->getNetBase( serviceId, hostid1 );
198 CCallbackNetBase *cnb2 = CUnifiedNetwork::getInstance()->getNetBase( *ios, hostid2 );
199 if ( cnb1->hostAddress( hostid1 ).internalIPAddress() == cnb2->hostAddress( hostid2 ).internalIPAddress() )*/
201 // Implementation for NS
202 if ( addr[0].internalIPAddress() == getHostAddress( *ios ).internalIPAddress() )
204 grantStarting = false;
205 reason = toString( "Service %s already found as %hu on same machine", serviceName.c_str(), ios->get() );
206 nlinfo( reason.c_str() );
207 break;
214 if ( grantStarting )
216 _OnlineServices.insert( serviceId );
218 return grantStarting;
223 * Release a service instance
225 void CServiceInstanceManager::releaseService( NLNET::TServiceId serviceId )
227 _OnlineServices.erase( serviceId ); // not a problem if not found
232 * Display information
234 void CServiceInstanceManager::displayInfo( NLMISC::CLog *log ) const
236 log->displayNL( "Restricted services:" );
237 std::map< std::string, bool >::const_iterator ius;
238 for ( ius=_UniqueServices.begin(); ius!=_UniqueServices.end(); ++ius )
240 log->displayNL( "%s -> only one per %s", (*ius).first.c_str(), (*ius).second?"shard":"machine" );
242 log->displayNL( "Online registered services:" );
243 std::set< TServiceId >::const_iterator ios;
244 for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )
246 log->displayNL( "%s", CUnifiedNetwork::getInstance()->getServiceUnifiedName( *ios ).c_str() );
252 * Make all controlled services quit
254 void CServiceInstanceManager::killAllServices()
256 // Send to all known online services
257 std::set< TServiceId >::const_iterator ios;
258 for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )
260 doUnregisterService( (TServiceId)(*ios) );
267 // Variables
270 list<CServiceEntry> RegisteredServices; /// List of all registred services
272 uint16 MinBasePort = 51000; /// Ports begin at 51000
273 uint16 MaxBasePort = 52000; /// (note: in this implementation there can be no more than 1000 services)
275 const TServiceId BaseSId(128); /// Allocated SIds begin at 128 (except for Agent Service)
277 const TTime UnregisterTimeout = 10000; /// After 10s we remove an unregister service if every server didn't ACK the message
279 CCallbackServer *CallbackServer = NULL;
282 // Functions
285 bool canAccess (const vector<CInetAddress> &addr, const CServiceEntry &entry, vector<CInetAddress> &accessibleAddr)
287 accessibleAddr.clear ();
289 if (entry.WaitingUnregistration)
290 return false;
292 for (uint i = 0; i < addr.size(); i++)
294 uint32 net = addr[i].internalNetAddress();
295 for (uint j = 0; j < entry.Addr.size(); j++)
297 if (net == entry.Addr[j].internalNetAddress())
299 accessibleAddr.push_back (entry.Addr[j]);
304 if (accessibleAddr.empty())
306 nldebug ("service %s-%hu is not accessible by '%s'", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (addr).c_str ());
308 else
310 nldebug ("service %s-%hu is accessible by '%s'", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (accessibleAddr).c_str ());
313 return !accessibleAddr.empty ();
316 void displayRegisteredServices (CLog *log = InfoLog)
318 log->displayNL ("Display the %d registered services :", RegisteredServices.size());
319 for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
321 TSockId id = (*it).SockId;
322 if (id == NULL)
324 log->displayNL ("> %s-%hu %s '%s' %s %d addr", (*it).Name.c_str(), it->SId.get(), "<NULL>", "<NULL>", (*it).WaitingUnregistration?"WaitUnreg":"", (*it).Addr.size());
325 for(uint i = 0; i < (*it).Addr.size(); i++)
326 log->displayNL (" '%s'", (*it).Addr[i].asString().c_str());
328 else
330 log->displayNL ("> %s-%hu %s '%s' %s %d addr", (*it).Name.c_str(), it->SId.get(), (*it).SockId->asString().c_str(), CallbackServer->hostAddress((*it).SockId).asString().c_str(), (*it).WaitingUnregistration?"WaitUnreg":"", (*it).Addr.size());
331 for(uint i = 0; i < (*it).Addr.size(); i++)
332 log->displayNL (" '%s'", (*it).Addr[i].asString().c_str());
335 log->displayNL ("End of the list");
339 list<CServiceEntry>::iterator effectivelyRemove (list<CServiceEntry>::iterator &it)
341 // remove the service from the registered service list
342 nlinfo ("Effectively remove the service %s-%hu", (*it).Name.c_str(), it->SId.get());
343 return RegisteredServices.erase (it);
347 * Helper procedure for cbLookupAlternate and cbUnregister.
348 * Note: name is used for a LOGS.
350 list<CServiceEntry>::iterator doRemove (list<CServiceEntry>::iterator it)
352 nldebug ("Unregister the service %s-%hu '%s'", (*it).Name.c_str(), it->SId.get(), (*it).Addr[0].asString().c_str());
354 // tell to everybody that this service is unregistered
356 CMessage msgout ("UNB");
357 msgout.serial ((*it).Name);
358 msgout.serial ((*it).SId);
360 vector<CInetAddress> accessibleAddress;
361 nlinfo ("Broadcast the Unregistration of %s-%hu to all registered services", (*it).Name.c_str(), it->SId.get());
362 for (list<CServiceEntry>::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++)
364 if (canAccess((*it).Addr, (*it3), accessibleAddress))
366 CallbackServer->send (msgout, (*it3).SockId);
367 //CNetManager::send ("NS", msgout, (*it3).SockId);
368 nldebug ("Broadcast to %s-%hu", (*it3).Name.c_str(), it3->SId.get());
372 // new system, after the unregistation broadcast, we wait ACK from all services before really remove
373 // the service, before, we tag the service as 'wait before unregister'
374 // if everybody didn't answer before the time out, we remove it
376 (*it).SockId = NULL;
378 (*it).WaitingUnregistration = true;
379 (*it).WaitingUnregistrationTime = CTime::getLocalTime();
381 // we remove all services awaiting his ACK because this service is down so it'll never ACK
382 for (list<CServiceEntry>::iterator itr = RegisteredServices.begin(); itr != RegisteredServices.end (); itr++)
384 for (list<TServiceId>::iterator itw = (*itr).WaitingUnregistrationServices.begin(); itw != (*itr).WaitingUnregistrationServices.end ();)
386 if ((*itw) == (*it).SId)
388 itw = (*itr).WaitingUnregistrationServices.erase (itw);
390 else
392 itw++;
397 string res;
398 for (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)
400 if (!(*it2).WaitingUnregistration)
402 (*it).WaitingUnregistrationServices.push_back ((*it2).SId);
403 res += toString((*it2).SId.get()) + " ";
407 nlinfo ("Before removing the service %s-%hu, we wait the ACK of '%s'", (*it).Name.c_str(), (*it).SId.get(), res.c_str());
409 if ((*it).WaitingUnregistrationServices.empty())
411 return effectivelyRemove (it);
413 else
415 return ++it;
418 // Release from the service instance manager
419 SIMInstance->releaseService( (*it).SId );
422 void doUnregisterService (TServiceId sid)
424 list<CServiceEntry>::iterator it;
425 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
427 if ((*it).SId == sid)
429 // found it, remove it
430 doRemove (it);
431 return;
434 nlwarning ("Service %hu not found", sid.get());
437 void doUnregisterService (TSockId from)
439 list<CServiceEntry>::iterator it;
440 for (it = RegisteredServices.begin(); it != RegisteredServices.end ();)
442 if ((*it).SockId == from)
444 // it's possible that one "from" have more than one registred service, so we have to find in all the list
445 // found it, remove it
446 it = doRemove (it);
448 else
450 it++;
455 /*void doUnregisterService (const CInetAddress &addr)
457 list<CServiceEntry>::iterator it;
458 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
460 if ((*it).Addr == addr)
462 // found it, remove it
463 doRemove (it);
464 return;
467 nlwarning ("Service %s not found", addr.asString().c_str());
471 * Helper function for cbRegister.
472 * If alloc_sid is true, sid is ignored
473 * Returns false in case of failure of sid allocation or bad sid provided
474 * Note: the reply is included in this function, because it must be done before things such as syncUniTime()
476 bool doRegister (const string &name, const vector<CInetAddress> &addr, TServiceId sid, TSockId from, CCallbackNetBase &netbase, bool reconnection = false)
478 // Find if the service is not already registered
479 string reason;
480 uint8 ok = true;
481 bool needRegister = true;
482 /*for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
484 if ((*it).Addr.asIPString() == addr.asIPString() )
486 // we already have a service on this address, remplace it if it's the same name
487 if ((*it).Name == name)
489 // it's the same service, replace it
490 (*it).SockId = from;
491 sid = (*it).SId;
492 nlinfo ("Replace the service %s", name.c_str());
494 else
496 nlwarning ("Try to register %s to %s but the service %s already on this address. ignore it!", name.c_str(), addr.asIPString().c_str(), (*it).Name.c_str());
497 ok = false;
499 needRegister = false;
500 break;
504 if (needRegister)
506 if (sid.get() == 0)
508 // we have to find a sid
509 sid = BaseSId;
510 bool found = false;
511 while (!found)
513 list<CServiceEntry>::iterator it;
514 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
516 if ((*it).SId == sid)
518 break;
521 if (it == RegisteredServices.end ())
523 // ok, we have an empty sid
524 found = true;
526 else
528 sid.set(sid.get()+1);
529 if (sid.get() == 0) // round the clock
531 nlwarning ("Service identifier allocation overflow");
532 ok = false;
533 break;
539 else
541 // we have to check that the user provided sid is available
542 list<CServiceEntry>::iterator it;
543 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
545 if ((*it).SId == sid)
547 nlwarning ("Sid %d already used by another service", sid.get());
548 ok = false;
549 break;
552 if (it != RegisteredServices.end ())
554 ok = true;
558 // if ok, register the service and send a broadcast to other people
559 if (ok)
561 // Check if the instance is allowed to start, according to the restriction in the config file
562 if ( SIMInstance->queryStartService( name, sid, addr, reason ) )
564 // add him in the registered list
565 RegisteredServices.push_back (CServiceEntry(from, addr, name, sid));
567 // tell to everybody but not him that this service is registered
568 if (!reconnection)
570 CMessage msgout ("RGB");
571 TServiceId::size_type s = 1;
572 msgout.serial (s);
573 msgout.serial (const_cast<string &>(name));
574 msgout.serial (sid);
575 // we need to send all addr to all services even if the service can't access because we use the address index
576 // to know which connection comes.
577 msgout.serialCont (const_cast<vector<CInetAddress> &>(addr));
578 nlinfo ("The service is %s-%d, broadcast the Registration to everybody", name.c_str(), sid.get());
580 vector<CInetAddress> accessibleAddress;
581 for (list<CServiceEntry>::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++)
583 // send only services that can be accessed and not itself
584 if ((*it3).SId != sid && canAccess(addr, (*it3), accessibleAddress))
586 CallbackServer->send (msgout, (*it3).SockId);
587 //CNetManager::send ("NS", msgout, (*it3).SockId);
588 nldebug ("Broadcast to %s-%hu", (*it3).Name.c_str(), it3->SId.get());
593 // set the sid only if it s ok
594 from->setAppId (sid.get());
596 else
598 // Reply "startup denied", and do not send registration to other services
599 ok = false;
603 // send the message to the service to say if it s ok or not
604 if (!reconnection)
606 // send the answer to the client
607 CMessage msgout ("RG");
608 msgout.serial (ok);
609 if (ok)
611 msgout.serial (sid);
613 // send him all services available (also itself)
614 TServiceId::size_type nb = 0;
616 vector<CInetAddress> accessibleAddress;
618 for (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)
620 // send only services that are available
621 if (canAccess(addr, (*it2), accessibleAddress))
622 nb++;
624 msgout.serial (nb);
626 for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
628 // send only services that are available
629 if (canAccess(addr, (*it), accessibleAddress))
631 msgout.serial ((*it).Name);
632 msgout.serial ((*it).SId);
633 msgout.serialCont ((*it).Addr);
637 else
639 msgout.serial( reason );
642 netbase.send (msgout, from);
643 netbase.flush (from);
647 //displayRegisteredServices ();
649 return ok!=0;
652 void checkWaitingUnregistrationServices ()
654 for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end ();)
656 if ((*it).WaitingUnregistration && ((*it).WaitingUnregistrationServices.empty() || CTime::getLocalTime() > (*it).WaitingUnregistrationTime + UnregisterTimeout))
658 if ((*it).WaitingUnregistrationServices.empty())
660 nlinfo ("Removing the service %s-%hu because all services ACKd the removal", (*it).Name.c_str(), (*it).SId.get());
662 else
664 string res;
665 for (list<TServiceId>::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++)
667 res += toString(it2->get()) + " ";
669 nlwarning ("Removing the service %s-%hu because time out occurs (service numbers %s didn't ACK)", (*it).Name.c_str(), (*it).SId.get(), res.c_str());
671 it = effectivelyRemove (it);
673 else
675 it++;
682 * Callback for service unregistration ACK. Mean that a service was ACK the unregistration broadcast
684 static void cbACKUnregistration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
686 TServiceId sid;
687 msgin.serial (sid);
689 for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
691 if ((*it).SId == sid && (*it).WaitingUnregistration)
693 for (list<TServiceId>::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++)
695 if (*it2 == TServiceId(uint16(from->appId())))
697 // remove the acked service
698 (*it).WaitingUnregistrationServices.erase (it2);
699 checkWaitingUnregistrationServices ();
700 return;
709 * Callback for service registration when the naming service goes down and up (don't need to broadcast)
711 static void cbResendRegisteration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
713 string name;
714 vector<CInetAddress> addr;
715 TServiceId sid;
716 msgin.serial (name);
717 msgin.serialCont (addr);
718 msgin.serial (sid);
720 doRegister (name, addr, sid, from, netbase, true);
726 * Callback for service registration.
728 * Message expected : RG
729 * - Name of service to register (string)
730 * - Address of service (CInetAddress)
732 * Message emitted : RG
733 * - Allocated service identifier (TServiceId) or 0 if failed
735 static void cbRegister (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
737 string name;
738 vector<CInetAddress> addr;
739 TServiceId sid;
740 msgin.serial (name);
741 msgin.serialCont (addr);
742 msgin.serial (sid);
744 doRegister (name, addr, sid, from, netbase);
749 * Callback for service unregistration.
751 * Message expected : UNI
752 * - Service identifier (TServiceId)
754 static void cbUnregisterSId (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
756 TServiceId sid;
757 msgin.serial( sid );
759 doUnregisterService (sid);
760 //displayRegisteredServices ();
765 * Helper function for cbQueryPort
767 * \warning QueryPort + Registration is not atomic so more than one service could ask a port before register
769 uint16 doAllocatePort (const CInetAddress &addr)
771 static uint16 nextAvailablePort = MinBasePort;
773 // check if nextavailableport is free
775 if (nextAvailablePort >= MaxBasePort) nextAvailablePort = MinBasePort;
777 bool ok;
780 ok = true;
781 list<CServiceEntry>::iterator it;
782 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
784 if ((*it).Addr[0].port () == nextAvailablePort)
786 nextAvailablePort++;
787 ok = false;
788 break;
792 while (!ok);
794 return nextAvailablePort++;
799 * Callback for port allocation
800 * Note: if a service queries a port but does not register itself to the naming service, the
801 * port will remain allocated and unused.
803 * Message expected : QP
804 * - Name of service to register (string)
805 * - Address of service (CInetAddress) (its port can be 0)
807 * Message emitted : QP
808 * - Allocated port number (uint16)
810 static void cbQueryPort (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
812 // Allocate port
813 uint16 port = doAllocatePort (netbase.hostAddress (from));
815 // Send port back
816 CMessage msgout ("QP");
817 msgout.serial (port);
818 netbase.send (msgout, from);
820 nlinfo ("The service got port %hu", port);
825 * Unregisters a service if it has not been done before.
826 * Note: this callback is called whenever someone disconnects from the NS.
827 * May be there are too many calls if many clients perform many transactional lookups.
829 static void cbDisconnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg )
831 doUnregisterService (from);
832 //displayRegisteredServices ();
836 * a service is connected, send him all services infos
838 static void cbConnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg )
840 // we have to wait the registred services message to send all services because it this points, we can't know which sub net
841 // the service can use
843 //displayRegisteredServices ();
845 // set the appid with a bad id (-1)
846 from->setAppId (~0);
849 /*// returns the list of accessible services with a list of address
850 static void cbRegisteredServices(CMessage& msgin, TSockId from, CCallbackNetBase &netbase)
852 vector<CInetAddress> addr;
853 msgin.serialCont (addr);
855 nlinfo ("New service ask me the available services, sending him all services available");
856 // send to the new service the list of all services that this service can access (depending of his sub net)
858 CMessage msgout ("RGB");
860 uint8 nb = 0;
862 vector<CInetAddress> accessibleAddress;
864 for (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)
866 // send only services that are available
867 if (canAccess(addr, (*it2), accessibleAddress))
868 nb++;
871 msgout.serial (nb);
873 for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
875 // send only services that are available
876 if (canAccess(addr, (*it), accessibleAddress))
878 msgout.serial ((*it).Name);
879 msgout.serial ((*it).SId);
880 msgout.serialCont (accessibleAddress);
884 CNetManager::send ("NS", msgout, from);
889 * Helper that emulates layer5 send()
891 /*void sendToService( uint16 sid, CMessage& msgout )
893 list<CServiceEntry>::iterator it;
894 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
896 if ((*it).SId == sid)
898 CallbackServer->send (msgout, (*it).SockId);
905 * Helper that emulate layer5's getServiceName()
907 string getServiceName( TServiceId sid )
909 list<CServiceEntry>::iterator it;
910 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
912 if ((*it).SId == sid)
914 return (*it).Name;
917 return ""; // not found
922 * Helper that returns the first address of a service
924 CInetAddress getHostAddress( TServiceId sid )
926 list<CServiceEntry>::iterator it;
927 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
929 if ((*it).SId == sid)
931 return (*it).Addr[0];
934 return CInetAddress();
939 // Callback array
942 TCallbackItem CallbackArray[] =
944 { "RG", cbRegister },
945 { "RRG", cbResendRegisteration },
946 { "QP", cbQueryPort },
947 { "UNI", cbUnregisterSId },
948 { "ACK_UNI", cbACKUnregistration },
949 // { "RS", cbRegisteredServices },
954 // Service
957 class CNamingService : public NLNET::IService
959 public:
962 * Init
964 void init()
966 // if a baseport is available in the config file, get it
967 CConfigFile::CVar *var;
968 if ((var = ConfigFile.getVarPtr ("BasePort")) != NULL)
970 uint16 newBasePort = var->asInt ();
971 nlinfo ("Changing the MinBasePort number from %hu to %hu", MinBasePort, newBasePort);
972 sint32 delta = MaxBasePort - MinBasePort;
973 nlassert (delta > 0);
974 MinBasePort = newBasePort;
975 MaxBasePort = MinBasePort + uint16 (delta);
978 // Parameters for the service instance manager
981 CConfigFile::CVar& uniqueServices = ConfigFile.getVar("UniqueOnShardServices");
982 for ( uint i=0; i!=uniqueServices.size(); ++i )
984 _ServiceInstances.addUniqueService( uniqueServices.asString(i), true );
987 catch(Exception &)
991 CConfigFile::CVar& uniqueServicesM = ConfigFile.getVar("UniqueByMachineServices");
992 for ( uint i=0; i!=uniqueServicesM.size(); ++i )
994 _ServiceInstances.addUniqueService( uniqueServicesM.asString(i), false );
997 catch(Exception &)
1001 // we don't try to associate message from client
1002 CNetManager::getNetBase ("NS")->ignoreAllUnknownId (true);
1004 // add the callback in case of disconnection
1005 CNetManager::setConnectionCallback ("NS", cbConnect, NULL);
1007 // add the callback in case of disconnection
1008 CNetManager::setDisconnectionCallback ("NS", cbDisconnect, NULL);
1010 // DEBUG
1011 // DebugLog->addDisplayer( new CStdDisplayer() );
1013 vector<CInetAddress> v = CInetAddress::localAddresses();
1014 nlinfo ("%d detected local addresses:", v.size());
1015 for (uint i = 0; i < v.size(); i++)
1017 nlinfo (" %d - '%s'",i, v[i].asString().c_str());
1020 uint16 nsport = 50000;
1021 if ((var = ConfigFile.getVarPtr ("NSPort")) != NULL)
1023 nsport = var->asInt ();
1026 CallbackServer = new CCallbackServer;
1027 CallbackServer->init(nsport);
1028 CallbackServer->addCallbackArray(CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));
1029 CallbackServer->setConnectionCallback(cbConnect, NULL);
1030 CallbackServer->setDisconnectionCallback(cbDisconnect, NULL);
1034 * Update
1036 bool update ()
1038 checkWaitingUnregistrationServices ();
1040 CallbackServer->update ();
1042 return true;
1045 void release()
1047 if (CallbackServer != NULL)
1048 delete CallbackServer;
1049 CallbackServer = NULL;
1052 private:
1054 /// Service instance manager singleton
1055 CServiceInstanceManager _ServiceInstances;
1059 static const char* getCompleteServiceName(const IService* theService)
1061 static std::string s;
1062 s= "naming_service";
1064 if (theService->haveLongArg("nsname"))
1066 s+= "_"+theService->getLongArg("nsname");
1069 if (theService->haveLongArg("fullnsname"))
1071 s= theService->getLongArg("fullnsname");
1074 return s.c_str();
1077 static const char* getShortServiceName(const IService* theService)
1079 static std::string s;
1080 s= "NS";
1082 if (theService->haveLongArg("shortnsname"))
1084 s= theService->getLongArg("shortnsname");
1087 return s.c_str();
1090 /// Naming Service
1092 NLNET_SERVICE_MAIN( CNamingService, getShortServiceName(scn), getCompleteServiceName(scn), 0, EmptyCallbackArray, NELNS_CONFIG, NELNS_LOGS)
1096 // Commands
1100 NLMISC_COMMAND (nsServices, "displays the list of all registered services", "")
1102 if(args.size() != 0) return false;
1104 displayRegisteredServices (&log);
1106 return true;
1109 NLMISC_COMMAND (kill, "kill a service and send an unregister broadcast to other service", "<ServiceShortName>|<ServiceId>")
1111 if(args.size() != 1) return false;
1113 // try with number
1115 TServiceId sid(atoi(args[0].c_str()));
1117 if(sid.get() == 0)
1119 // not a number, try a name
1120 list<CServiceEntry>::iterator it;
1121 for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)
1123 if ((*it).Name == args[0])
1125 sid = (*it).SId;
1126 break;
1129 if (it == RegisteredServices.end())
1131 log.displayNL ("Bad service name or id '%s'", args[0].c_str());
1132 return false;
1136 doUnregisterService (sid);
1137 return true;
1140 NLMISC_DYNVARIABLE(uint32, NbRegisteredServices, "display the number of service that are registered in naming service")
1142 if (get) *pointer = (uint32)RegisteredServices.size();
1145 NLMISC_COMMAND( displayServiceInstances, "SIM: Display info on service instances", "" )
1147 SIMInstance->displayInfo( &log );
1148 return true;
1151 NLMISC_COMMAND( killAllServices, "SIM: Make all the controlled services quit", "" )
1153 SIMInstance->killAllServices();
1154 return true;