// decode a service in a form 'alias/shortname-sid' void decodeUnifiedName(const string &unifiedName, string &alias, string &shortName, TServiceId &sid) { size_t pos1 = 0, pos2 = 0; pos1 = unifiedName.find("/"); if (pos1 != string::npos) { alias = unifiedName.substr(0, pos1); pos1++; } else { alias = ""; pos1 = 0; } pos2 = unifiedName.find("-"); if (pos2 != string::npos) { shortName = unifiedName.substr(pos1,pos2-pos1); sid.set(atoi(unifiedName.substr(pos2+1).c_str())); } else { shortName = unifiedName.substr(pos1); sid.set(0); } if (alias.empty()) { alias = shortName; } }
static void cbPosition(CMessage &msgin, const std::string &serviceName, TServiceId sid) { // temp uint32 id; CVector position; msgin.serial(id); msgin.serial(position); nldebug("Received CLS_POSITION, %s %s", serviceName.c_str(), sid.toString().c_str()); // Update position information in the player list _pmap::iterator ItPlayer; ItPlayer = playerList.find( id ); if ( ItPlayer == playerList.end() ) { nlwarning( "Player id %u not found !", id ); } else { ((*ItPlayer).second).position = position; //nldebug( "SB: Player position updated" ); } CMessage msgout("ENTITY_TP"); msgout.serial(id); msgout.serial(position); CUnifiedNetwork::getInstance()->send("FS", msgout); }
/* * Supports any service id, even one not added before (ignored then) */ void CTickProxy::removeService( TServiceId serviceId ) { vector<TServiceId>::iterator it = find( _Services.begin(), _Services.end(), serviceId ); if ( it == _Services.end() ) return; // ignore a service not registered _Services.erase( it ); // Simulate Tock from leaving service if needed if ( State == ExpectingLocalTocks ) { if ( find( _TockedServices.begin(), _TockedServices.end(), serviceId ) != _TockedServices.end() ) { // The service already tocked and we are still in this state, it means we're waiting for another service to tock nlassert( _NbTocked != 0 ); --_NbTocked; // decrement because _Service.size() is being decremented // If other tocks are coming, they will call doNextTask. However, it is possible that no // other tock is expected, if the tock did not triggered a master tock (changing State). if ( _NbTocked == _Services.size() ) cbDoNextTask(); else nldebug( "TCK- Service %hu already tocked, waiting for %u other tocks", serviceId.get(), _Services.size() - _NbTocked ); } else { // The service didn't tock yet, interpret its quitting as a tock cbDoNextTask(); } } }
// This function is called by FES to setup the right number of players (if FES was already present before WS launching) void cbFESNbPlayers2(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 nbPlayers; uint32 nbPendingPlayers; msgin.serial(nbPlayers); msgin.serial(nbPendingPlayers); uint32 totalNbOnlineUsers = 0, totalNbPendingUsers = 0; for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { CFES &fes = *it; if (fes.SId == sid) { nldebug("Frontend '%d' reported %d online users", sid.get(), nbPlayers); fes.NbUser = nbPlayers; fes.NbPendingUsers = nbPendingPlayers; if (nbPlayers != 0 && fes.State == PatchOnly) { nlwarning("Frontend %d is in state PatchOnly, yet reports to have online %d players, state AcceptClientOnly is forced (FS_ACCEPT message sent)"); (*it).setToAcceptClients(); } } totalNbOnlineUsers += fes.NbUser; totalNbPendingUsers += fes.NbPendingUsers; } if (CWelcomeServiceMod::isInitialized()) CWelcomeServiceMod::getInstance()->updateConnectedPlayerCount(totalNbOnlineUsers, totalNbPendingUsers); }
// This function is called by FES to setup the right number of players (if FES was already present before WS launching) void cbFESNbPlayers(CMessage &msgin, const std::string &serviceName, TServiceId sid) { // *********** WARNING ******************* // This version of the callback is deprecated, the system // now use cbFESNbPlayers2 that report the pending user count // as well as the number of connected players. // It is kept for backward compatibility only. // *************************************** uint32 nbPlayers; msgin.serial(nbPlayers); uint32 totalNbOnlineUsers = 0, totalNbPendingUsers = 0; for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { if ((*it).SId == sid) { nldebug("Frontend '%d' reported %d online users", sid.get(), nbPlayers); (*it).NbUser = nbPlayers; if (nbPlayers != 0 && (*it).State == PatchOnly) { nlwarning("Frontend %d is in state PatchOnly, yet reports to have online %d players, state AcceptClientOnly is forced (FS_ACCEPT message sent)"); (*it).setToAcceptClients(); } } totalNbOnlineUsers += (*it).NbUser; totalNbPendingUsers += (*it).NbPendingUsers; } if (CWelcomeServiceMod::isInitialized()) CWelcomeServiceMod::getInstance()->updateConnectedPlayerCount(totalNbOnlineUsers, totalNbPendingUsers); }
// This function is called when a FES rejected a client' cookie void cbFESRemovedPendingCookie(CMessage &msgin, const std::string &serviceName, TServiceId sid) { CLoginCookie cookie; msgin.serial(cookie); nldebug( "ERLOG: RPC recvd from %s-%hu => %s removed", serviceName.c_str(), sid.get(), cookie.toString().c_str(), cookie.toString().c_str()); // client' cookie rejected, no longer pending uint32 totalNbOnlineUsers = 0, totalNbPendingUsers = 0; for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { if ((*it).SId == sid) { if ((*it).NbPendingUsers > 0) --(*it).NbPendingUsers; } totalNbOnlineUsers += (*it).NbUser; totalNbPendingUsers += (*it).NbPendingUsers; } if (CWelcomeServiceMod::isInitialized()) { CWelcomeServiceMod::getInstance()->pendingUserLost(cookie); CWelcomeServiceMod::getInstance()->updateConnectedPlayerCount(totalNbOnlineUsers, totalNbPendingUsers); } }
/* * Map Service Id */ bool CDbManager::mapService(TServiceId serviceId, TDatabaseId databaseId) { if (serviceId.get() > 256 || _ServiceMap[serviceId.get()] != INVALID_DATABASE_ID) { nlwarning("CDbManager::mapService(): failed, serviceId '%hu' not valid or service already mapped", serviceId.get()); return false; } _ServiceMap[serviceId.get()] = databaseId; CDatabase* database = getDatabase(databaseId); if (database != NULL) database->mapToService(serviceId); return true; }
/**************************************************************************** * Connection callback for the collision service ****************************************************************************/ static void cbCollisionServiceUp(const std::string &serviceName, TServiceId sid, void *arg) { nldebug("SB: Collision Service UP, %s %s", serviceName.c_str(), sid.toString().c_str()); clear(); msgRegister(sid); for (_pmap::iterator it = playerList.begin(); it != playerList.end(); it++) addEntity(it->second.id, it->second.position, 1.0f); }
void serviceConnection(const std::string &serviceName, TServiceId sid, void *arg) { // don't add AS if (serviceName == "AS") return; if (sid.get() >= Services.size()) { Services.resize(sid.get()+1); } Services[sid.get()].init(serviceName, sid); sendInformation(sid); nlinfo("%s-%hu connected", Services[sid.get()].ShortName.c_str(), Services[sid.get()].ServiceId.get()); }
// a front end closes the connection, deconnect him void cbFESDisconnection (const std::string &serviceName, TServiceId sid, void *arg) { nldebug("new FES disconnection: sid %u", sid.get()); for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { if ((*it).SId == sid) { // send a message to the LS to say that all players from this FES are offline map<uint32, TServiceId>::iterator itc = UserIdSockAssociations.begin(); map<uint32, TServiceId>::iterator nitc = itc; while (itc != UserIdSockAssociations.end()) { nitc++; if ((*itc).second == sid) { // bye bye little player uint32 userid = (*itc).first; nlinfo ("Due to a frontend crash, removed the player %d", userid); if (!DontUseLS) { CMessage msgout ("CC"); msgout.serial (userid); uint8 con = 0; msgout.serial (con); CUnifiedNetwork::getInstance()->send ("LS", msgout); } UserIdSockAssociations.erase (itc); } itc = nitc; } bool dummy; (*it).reportStateToLS(dummy, false); // remove the FES FESList.erase (it); break; } } // Update the welcome service client with the new count of connection uint32 totalNbOnlineUsers =0, totalNbPendingUsers = 0; for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { const CFES &fes = *it; totalNbOnlineUsers += fes.NbUser; totalNbPendingUsers += fes.NbPendingUsers; } if (CWelcomeServiceMod::isInitialized()) CWelcomeServiceMod::getInstance()->updateConnectedPlayerCount(totalNbOnlineUsers, totalNbPendingUsers); displayFES (); }
void cbUpService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is up", serviceName.c_str(), sid.get()); CMessage msgout("TOTO"); uint32 i = 10; msgout.serial(i); CUnifiedNetwork::getInstance()->send(sid, msgout); }
// a new front end connecting to me, add it void cbFESConnection (const std::string &serviceName, TServiceId sid, void *arg) { FESList.push_back (CFES ((TServiceId)sid)); nldebug("new FES connection: sid %u", sid.get()); displayFES (); bool dummy; FESList.back().reportStateToLS(dummy); if (!UsePatchMode.get()) { FESList.back().setToAcceptClients(); } }
void reset() { AliasName.clear(); ShortName.clear(); LongName.clear(); ServiceId.set(0); Ready = false; Connected = false; Commands.clear(); AutoReconnect = false; PId = 0; Relaunch = false; LastPing = 0; WaitingRequestId.clear(); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// CONNECTION TO THE LOGIN SERVICE /////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// void cbLSChooseShard (CMessage &msgin, const std::string &serviceName, TServiceId sid) { // the LS warns me that a new client want to come in my shard nldebug( "ERLOG: CS recvd from %s-%hu", serviceName.c_str(), sid.get()); // // S07: receive the "CS" message from LS and send the "CS" message to the selected FES // CLoginCookie cookie; msgin.serial (cookie); string userName, userPriv, userExtended; msgin.serial (userName); try { msgin.serial (userPriv); } catch (const Exception &) { nlwarning ("LS didn't give me the user privilege for user '%s', set to empty", userName.c_str()); } try { msgin.serial (userExtended); } catch (const Exception &) { nlwarning ("LS didn't give me the extended data for user '%s', set to empty", userName.c_str()); } string ret = lsChooseShard(userName, cookie, userPriv, userExtended, WS::TUserRole::ur_player, 0xffffffff, ~0); if (!ret.empty()) { // send back an error message to LS CMessage msgout ("SCS"); msgout.serial (ret); msgout.serial (cookie); CUnifiedNetwork::getInstance()->send(sid, msgout); } }
std::string getServiceUnifiedName() const { nlassert(!ShortName.empty()); string res; if(!AliasName.empty()) { res = AliasName+"/"; } res += ShortName; if(ServiceId.get() != 0) { res += "-"; res += NLMISC::toString(ServiceId); } if(res.empty()) res = "???"; return res; }
static void cbServiceReady(CMessage &msgin, const std::string &serviceName, TServiceId sid) { if (sid.get() >= Services.size()) { nlwarning("Ready of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } if (!Services[sid.get()].Connected) { nlwarning("Ready of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } nlinfo("*:*:%d is ready '%s'", Services[sid.get()].ServiceId.get(), Services[sid.get()].getServiceUnifiedName().c_str()); Services[sid.get()].Ready = true; }
static void cbExecCommandResult(CMessage &msgin, const std::string &serviceName, TServiceId sid) { // treat the rely message sent back from a service whom we asked to execute a command NLMISC::InfoLog->displayNL("EXEC_COMMAND_RESULT' Received from: %3d: %s", sid.get() ,serviceName.c_str()); // retrieve the text from the input message CSString txt; msgin.serial(txt); // divide the text into lines because NeL doesn't like long texts CVectorSString lines; txt.splitLines(lines); // display the lines of text for (uint32 i=0;i<lines.size();++i) { NLMISC::InfoLog->displayNL("%s",lines[i].c_str()); } }
bool writeServiceLaunchCtrl(TServiceId serviceId,bool delay,const std::string& txt) { // run trough the services container looking for a match for the service id that we've been given for (TServices::iterator it= Services.begin(); it!=Services.end(); ++it) { if (it->ServiceId==serviceId) { // we found a match for the service id so try to do something sensible with it... // get hold of the different components of the command description... string alias, command, path, arg; bool ok= getServiceLaunchInfo(it->AliasName,alias,command,path,arg); if (!ok) return false; // go ahead and write the launch ctrl file... return writeServiceLaunchCtrl(alias,path,delay,txt); } } // we failed to find a match for the serviceId that we've been given so complain and return false nlwarning("Failed to write launch_ctrl file for unknown service: %u",serviceId.get()); return false; }
void addRequest(uint32 rid, const string &rawvarpath, TServiceId sid) { nlinfo("REQUEST: addRequest from %hu: '%s'", sid.get(), rawvarpath.c_str()); string str; CLog logDisplayVars; CMemDisplayer mdDisplayVars; logDisplayVars.addDisplayer(&mdDisplayVars); CVarPath varpath(rawvarpath); // add the request Requests.push_back(CRequest(rid, sid)); // for each destination in the rawvarpath... for (uint i = 0; i < varpath.Destination.size(); i++) { CVarPath vp(varpath.Destination[i].first); for (uint t = 0; t < vp.Destination.size(); t++) { string service = vp.Destination[t].first; if (service == "*") { addRequestForOnlineServices(rid,varpath.Destination[i].second); } else if (service == "#") { addRequestForAllServices(rid,varpath.Destination[i].second); } else { addRequestForNamedService(rid,service,varpath.Destination[i].second); } } } }
static void cbStopService (CMessage &/* msgin */, const std::string &serviceName, TServiceId sid) { nlinfo ("ADMIN: Receive a stop from service %s-%hu, need to quit", serviceName.c_str(), sid.get()); IService::getInstance()->exit (0xFFFF); }
void CMirrorService::receiveDeltaFromRemoteMS( CMessage& msgin, TServiceId senderMSId ) { H_AUTO(receiveDeltaFromRemoteMS); // 2b. Receive delta updates from remote MSs => store them in pending deltas _PendingDeltas.push_back( make_pair( senderMSId, msgin ) ); // warning: msgin must be copied because below we advance the reading position of msgin //nldebug( "Received delta from %s", servStr(senderMSId).c_str() ); // Get the "wait for" mode of this remote MS delta bool waitForIt; msgin.serial( waitForIt ); if ( waitForIt ) // we assume it does not change during the lifetime of a particular remote MS { // Check if the sender is a new remote MS (search in the "delta update expectation list") std::list< TServiceId >::const_iterator it = find( _RemoteMSToWaitForDelta.begin(), _RemoteMSToWaitForDelta.end(), senderMSId ); if ( it == _RemoteMSToWaitForDelta.end() ) { _RemoteMSToWaitForDelta.push_back( senderMSId ); // _RemoteMSToWaitForDelta will not contain remote MSes for which we don't have to wait ++_NbExpectedDeltaUpdates; } } TGameCycle gamecycle; msgin.serial( gamecycle ); //nldebug( "%u: Rcvd Delta %u", CTickProxy::getGameCycle(), gamecycle ); _QuickLog.displayNL( "TCK-%u: Rcvd Delta %u from MS-%hu (NbExpectedDelta=%hd)", CTickProxy::getGameCycle(), gamecycle, senderMSId.get(), _NbExpectedDeltaUpdates ); // Count this delta update for the wait test only if its tick is the current tick or +1 (see explanation below) // Explanation: possibles cases: // // MS1 MS2 // | | // Tick1>| Tick1>| // Delta>|>Delta <====> Delta>|>Delta // |>Tock1 |>Tock1 // | | // | Tick2>| // Delta>| <----- |>Delta // Tick2>|>Delta -----> Delta>|>Tock2 // |>Tock2 | // if ( CTickProxy::State == ExpectingMasterTick ) { // If sync not received yet, defer possible incrementation of _NbDeltaUpdatesReceived // because we can't compare now the gamecycle of the delta update with the current gamecycle // (see examineDeltaUpdatesReceivedBeforeSync() called when receiving the sync) if ( CTickProxy::getGameCycle() == 0 ) { if ( waitForIt ) _GameCyclesOfDeltaReceivedBeforeSync.push_back( gamecycle ); return; } // Accept +1 only if received by advance (before the tick update) // Forbid >+1 // Discard <= else if ( gamecycle > CTickProxy::getGameCycle() ) { nlassert( gamecycle == CTickProxy::getGameCycle() + 1 ); if ( waitForIt ) ++_NbDeltaUpdatesReceived; } } else { // Accept == if received in the same tick // Forbid > // Discard < if ( gamecycle >= CTickProxy::getGameCycle() ) { nlassert( gamecycle == CTickProxy::getGameCycle() ); if ( waitForIt ) ++_NbDeltaUpdatesReceived; } } doNextTask(); }
static void cbAdminPong(CMessage &msgin, const std::string &serviceName, TServiceId sid) { for(uint i = 0; i < Services.size(); i++) { if(Services[i].ServiceId == sid) { nlinfo("receive pong"); if(Services[i].LastPing == 0) nlwarning("Received a pong from service %s-%hu but we didn't expect a pong from it", serviceName.c_str(), sid.get()); else Services[i].LastPing = 0; return; } } nlwarning("Received a pong from service %s-%hu that is not in my service list", serviceName.c_str(), sid.get()); }
// This function is called by FES to setup its PatchAddress void cbFESPatchAddress(CMessage &msgin, const std::string &serviceName, TServiceId sid) { std::string address; msgin.serial(address); bool acceptClients; msgin.serial(acceptClients); nldebug("Received patch server address '%s' from service %s %d", address.c_str(), serviceName.c_str(), sid.get()); for (list<CFES>::iterator it = FESList.begin(); it != FESList.end(); it++) { if ((*it).SId == sid) { nldebug("Affected patch server address '%s' to frontend %s %d", address.c_str(), serviceName.c_str(), sid.get()); if (!UsePatchMode.get() && !acceptClients) { // not in patch mode, force fs to accept clients acceptClients = true; (*it).setToAcceptClients(); } (*it).PatchAddress = address; (*it).State = (acceptClients ? AcceptClientOnly : PatchOnly); if (acceptClients) nldebug("Frontend %s %d reported to accept client, patching unavailable for that server", address.c_str(), serviceName.c_str(), sid.get()); else nldebug("Frontend %s %d reported to be in patching mode", address.c_str(), serviceName.c_str(), sid.get()); bool dummy; (*it).reportStateToLS(dummy); break; } } }
void cbDownService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is down", serviceName.c_str(), sid.get()); }
static void ASDisconnection(const string &serviceName, TServiceId sid, void *arg) { nlinfo("Disconnected to %s-%hu", serviceName.c_str(), sid.get()); }
void CTickProxy::receiveTockFromClient( CMessage& msgin, TServiceId senderId, bool real ) { // Receive measures of client service TimeMeasures.ServiceMeasures.push_back( CServiceGameCycleTimeMeasure() ); CServiceGameCycleTimeMeasure& stm = TimeMeasures.ServiceMeasures.back(); stm.ClientServiceId = senderId; if ( real ) { stm.ServiceMeasure[TickTockInterval] = accTimeToMs( getAccurateTime() - _BeginOfTickTime ); msgin.serial( stm.ServiceMeasure[TickUpdateDuration] ); msgin.serial( stm.ServiceMeasure[PrevProcessMirrorUpdateDuration] ); msgin.serial( stm.ServiceMeasure[PrevReceiveMsgsViaMirrorDuration] ); msgin.serial( stm.ServiceMeasure[PrevTotalGameCycleDuration] ); } else { for ( uint i=0; i!=NbServiceTimeMeasureTypes; ++i ) stm.ServiceMeasure[i] = 0; } //nldebug( "TCK-%u: %hu tocking", getGameCycle(), senderId ); //time_t t; time( &t ); _QuickLog.displayNL( "%"NL_I64"u: TCK-%u: %hu tocking", getPerfTime() /*IDisplayer::dateToHumanString( t )*/, getGameCycle(), senderId.get() ); ++_NbTocked; _TockedServices.push_back( senderId ); cbDoNextTask(); }
void serviceDisconnection(const std::string &serviceName, TServiceId sid, void *arg) { // don't remove AS if (serviceName == "AS") return; if (sid.get() >= Services.size()) { nlwarning("Disconnection of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } if (!Services[sid.get()].Connected) { nlwarning("Disconnection of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } // we need to remove pending request for(uint i = 0; i < Services[sid.get()].WaitingRequestId.size(); i++) { subRequestWaitingNb(Services[sid.get()].WaitingRequestId[i]); } nlinfo("%s-%hu disconnected", Services[sid.get()].ShortName.c_str(), Services[sid.get()].ServiceId.get()); if (Services[sid.get()].Relaunch) { // we have to relaunch it in time because ADMIN asked it sint32 delay = IService::getInstance()->ConfigFile.exists("RestartDelay")? IService::getInstance()->ConfigFile.getVar("RestartDelay").asInt(): 5; // must restart it so if delay is -1, set it by default to 5 seconds if (delay == -1) delay = 5; startService(delay, Services[sid.get()].getServiceUnifiedName()); } else if (Services[sid.get()].AutoReconnect) { // we have to relaunch it sint32 delay = IService::getInstance()->ConfigFile.exists("RestartDelay")? IService::getInstance()->ConfigFile.getVar("RestartDelay").asInt(): 5; if (delay >= 0) { startService(delay, Services[sid.get()].getServiceUnifiedName()); } else nlinfo("Don't restart the service because RestartDelay is %d", delay); sendAdminEmail("Server %s service '%s' : Stopped, auto reconnect in %d seconds", CInetAddress::localHost().hostName().c_str(), Services[sid.get()].getServiceUnifiedName().c_str(), delay); } // if the appropriate cfg file variable is set then we kill the service brutally on disconnection - this // allows one to fix a certain number of problem cases in program shut-down that would otherwise require // manual intervention on the machine if (KillServicesOnDisconnect) { killProgram(Services[sid.get()].PId); } Services[sid.get()].reset(); }
void CTickProxy::sendSyncToClient( TServiceId serviceId ) { CMessage msgout( "REGISTERED" ); msgout.serial( _GameTime ); msgout.serial( _GameTimeStep ); msgout.serial( _GameCycle ); CUnifiedNetwork::getInstance()->send( serviceId, msgout ); //nldebug( "TCK-%u: Sync %hu", getGameCycle(), serviceId ); //time_t t; time( &t ); _QuickLog.displayNL( "%"NL_I64"u: TCK-%u: Sync %hu", getPerfTime() /*IDisplayer::dateToHumanString( t )*/, getGameCycle(), serviceId.get() ); }
static void cbAESDisconnection (const std::string &serviceName, TServiceId sid, void * /* arg */) { nlinfo("Lost connection to the %s-%hu", serviceName.c_str(), sid.get()); }
static void cbServiceIdentification(CMessage &msgin, const std::string &serviceName, TServiceId sid) { if (sid.get() >= Services.size()) { nlwarning("Identification of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } if (!Services[sid.get()].Connected) { nlwarning("Identification of an unknown service %s-%hu", serviceName.c_str(), sid.get()); return; } msgin.serial(Services[sid.get()].AliasName, Services[sid.get()].LongName, Services[sid.get()].PId); msgin.serialCont(Services[sid.get()].Commands); nlinfo("Received service identification: Sid=%-3i Alias='%s' LongName='%s' ShortName='%s' PId=%u",sid.get(),Services[sid.get()].AliasName.c_str(),Services[sid.get()].LongName.c_str(),serviceName.c_str(),Services[sid.get()].PId); // if there's an alias, it means that it s me that launch the services, autoreconnect it if (!Services[sid.get()].AliasName.empty()) Services[sid.get()].AutoReconnect = true; nlinfo("*:*:%d is identified to be '%s' '%s' pid:%d", Services[sid.get()].ServiceId.get(), Services[sid.get()].getServiceUnifiedName().c_str(), Services[sid.get()].LongName.c_str(), Services[sid.get()].PId); }