1 // NeLNS - 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/>.
19 #endif // HAVE_CONFIG_H
22 #define NELNS_CONFIG ""
23 #endif // NELNS_CONFIG
34 #include "nel/misc/types_nl.h"
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"
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());
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
113 class CServiceInstanceManager
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();
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
;
157 CServiceInstanceManager::CServiceInstanceManager()
159 nlassert( ! SIMInstance
);
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
)
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() );
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() );
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
) );
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
;
285 bool canAccess (const vector
<CInetAddress
> &addr
, const CServiceEntry
&entry
, vector
<CInetAddress
> &accessibleAddr
)
287 accessibleAddr
.clear ();
289 if (entry
.WaitingUnregistration
)
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 ());
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
;
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());
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
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
);
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
);
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
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
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
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
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
492 nlinfo ("Replace the service %s", name.c_str());
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());
499 needRegister = false;
508 // we have to find a sid
513 list
<CServiceEntry
>::iterator it
;
514 for (it
= RegisteredServices
.begin(); it
!= RegisteredServices
.end (); it
++)
516 if ((*it
).SId
== sid
)
521 if (it
== RegisteredServices
.end ())
523 // ok, we have an empty sid
528 sid
.set(sid
.get()+1);
529 if (sid
.get() == 0) // round the clock
531 nlwarning ("Service identifier allocation overflow");
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());
552 if (it
!= RegisteredServices
.end ())
558 // if ok, register the service and send a broadcast to other people
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
570 CMessage
msgout ("RGB");
571 TServiceId::size_type s
= 1;
573 msgout
.serial (const_cast<string
&>(name
));
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());
598 // Reply "startup denied", and do not send registration to other services
603 // send the message to the service to say if it s ok or not
606 // send the answer to the client
607 CMessage
msgout ("RG");
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
))
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
);
639 msgout
.serial( reason
);
642 netbase
.send (msgout
, from
);
643 netbase
.flush (from
);
647 //displayRegisteredServices ();
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());
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
);
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
)
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 ();
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
)
714 vector
<CInetAddress
> addr
;
717 msgin
.serialCont (addr
);
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
)
738 vector
<CInetAddress
> addr
;
741 msgin
.serialCont (addr
);
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
)
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
;
781 list
<CServiceEntry
>::iterator it
;
782 for (it
= RegisteredServices
.begin(); it
!= RegisteredServices
.end (); it
++)
784 if ((*it
).Addr
[0].port () == nextAvailablePort
)
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
)
813 uint16 port
= doAllocatePort (netbase
.hostAddress (from
));
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)
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");
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))
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
)
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();
942 TCallbackItem CallbackArray
[] =
944 { "RG", cbRegister
},
945 { "RRG", cbResendRegisteration
},
946 { "QP", cbQueryPort
},
947 { "UNI", cbUnregisterSId
},
948 { "ACK_UNI", cbACKUnregistration
},
949 // { "RS", cbRegisteredServices },
957 class CNamingService
: public NLNET::IService
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 );
991 CConfigFile::CVar
& uniqueServicesM
= ConfigFile
.getVar("UniqueByMachineServices");
992 for ( uint i
=0; i
!=uniqueServicesM
.size(); ++i
)
994 _ServiceInstances
.addUniqueService( uniqueServicesM
.asString(i
), false );
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);
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
);
1038 checkWaitingUnregistrationServices ();
1040 CallbackServer
->update ();
1047 if (CallbackServer
!= NULL
)
1048 delete CallbackServer
;
1049 CallbackServer
= NULL
;
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");
1077 static const char* getShortServiceName(const IService
* theService
)
1079 static std::string s
;
1082 if (theService
->haveLongArg("shortnsname"))
1084 s
= theService
->getLongArg("shortnsname");
1092 NLNET_SERVICE_MAIN( CNamingService
, getShortServiceName(scn
), getCompleteServiceName(scn
), 0, EmptyCallbackArray
, NELNS_CONFIG
, NELNS_LOGS
)
1100 NLMISC_COMMAND (nsServices
, "displays the list of all registered services", "")
1102 if(args
.size() != 0) return false;
1104 displayRegisteredServices (&log
);
1109 NLMISC_COMMAND (kill
, "kill a service and send an unregister broadcast to other service", "<ServiceShortName>|<ServiceId>")
1111 if(args
.size() != 1) return false;
1115 TServiceId
sid(atoi(args
[0].c_str()));
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])
1129 if (it
== RegisteredServices
.end())
1131 log
.displayNL ("Bad service name or id '%s'", args
[0].c_str());
1136 doUnregisterService (sid
);
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
);
1151 NLMISC_COMMAND( killAllServices
, "SIM: Make all the controlled services quit", "" )
1153 SIMInstance
->killAllServices();