void tSonarSourceStateMachine::SetSimulating(bool SimulationOn) { bool NeedClientEmit = false; tMacAddress ClientMac; QHostAddress ClientIP; { tWriteLocker Locker(m_Lock); if(SimulationOn != m_Simulating) { m_Simulating = SimulationOn; if(m_Simulating) { DBG_SONAR_SOURCE_STATE(DbgPrintf("tSonarSourceStateMachine::SetSimulating - Client")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientIP = m_MyIP; ClientMac = m_MyMac; } else { DBG_SONAR_SOURCE_STATE(DbgPrintf("tSonarSourceStateMachine::SetSimulating - Server")); ChangeState(SonarCommon::eSonarServerState_Server); } } } if(NeedClientEmit) { // DbgPrintf("tSonarSourceStateMachine::SetSimulating - NeedClientEmit"); emit SetClientState(ClientMac, ClientIP); } }
void nsNativeAppSupportUnix::DoInteract() { nsCOMPtr<nsIObserverService> obsServ = mozilla::services::GetObserverService(); if (!obsServ) { SmcInteractDone(mSessionConnection, False); SmcSaveYourselfDone(mSessionConnection, True); SetClientState(STATE_IDLE); return; } nsCOMPtr<nsISupportsPRBool> cancelQuit = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID); bool abortQuit = false; if (cancelQuit) { cancelQuit->SetData(false); obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr); cancelQuit->GetData(&abortQuit); } if (!abortQuit && mClientState == STATE_DISCONNECTED) { // The session manager disappeared, whilst we were interacting, so // quit now nsCOMPtr<nsIAppStartup> appService = do_GetService("@mozilla.org/toolkit/app-startup;1"); if (appService) { appService->Quit(nsIAppStartup::eForceQuit); } } else { if (mClientState != STATE_SHUTDOWN_CANCELLED) { // Only do this if the shutdown wasn't cancelled SmcInteractDone(mSessionConnection, !!abortQuit); SmcSaveYourselfDone(mSessionConnection, !abortQuit); } SetClientState(STATE_IDLE); } }
void nsNativeAppSupportUnix::DisconnectFromSM() { // the SM is free to exit any time after we disconnect, so callers must be // sure to have reached a sufficiently advanced phase of shutdown that there // is no risk of data loss: // e.g. all async writes are complete by the end of "profile-before-change" if (mSessionConnection) { SetClientState(STATE_DISCONNECTED); SmcCloseConnection(mSessionConnection, 0, nullptr); mSessionConnection = nullptr; gdk_x11_set_sm_client_id(nullptr); // follow gnome-client behaviour } }
void tSonarSourceStateMachine::RemoteMasterSeen(tMacAddress NewServerMac, QHostAddress IP) { //QString classStr = tSonarSourceStateMachine::GetClassString(m_Class); //DbgPrintf("RemoteMasterSeen (%s) - IP=%s", classStr.toStdString().c_str(), IP.toString().toAscii().constData() ); // Ignore all remote masters in offline mode if(tSonarSettings::Instance()->OfflineModeUsed(m_Class)) { return; } if(m_State == SonarCommon::eSonarServerState_Server) { // Can't be the server in these cases! // In the case of forwardscan we can have the forward but won't be outputting network data unless we detect forwardscan transducer connected if(!m_HaveHardware || (m_Class == SonarCommon::eSonarServer_Forwardscan && !tSonarSettings::Instance()->InternalForwardscanEnabled())) { m_State = SonarCommon::eSonarServerState_NoServer; } } bool NeedClientEmit = false; bool NeedNewServerCommanded = false; tMacAddress ClientMac; { tWriteLocker Locker(m_Lock); switch(m_State) { case SonarCommon::eSonarServerState_NoServer: if((NewServerMac == m_SavedMaster) || (m_SavedMaster.IsNull() == true)) { m_TimeoutCounter = m_cClientTimeout; m_CurrentMac = NewServerMac; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("Remote master seen (our server)")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientMac = NewServerMac; emit UpdateServer(m_SavedMaster, m_Class); } else if(m_Class != SonarCommon::eSonarServer_Sidescan) { // If we are here it means we have a server previously saved, in order to prevent a legacy unit from claiming the server // then force it to switch its source to the one we had previously selected emit SendServerCommand(m_SavedMaster, m_Class); } break; case SonarCommon::eSonarServerState_Server: if(NewServerMac == m_SavedMaster) { if(NewServerMac != m_MyMac) { m_TimeoutCounter = m_cClientTimeout; m_CurrentMac = m_SavedMaster; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("Remote master seen (our server)")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientMac = m_SavedMaster; // NSW-24004: Will set structure in client/server mode whenever we are not our own source, this will ensure that our // internal settings won't be affected by the setting changes made to the new source and vice-versa if(m_Class == SonarCommon::eSonarServer_Sidescan) { tSonarSettings::Instance()->SetClientServerMode(true); } emit UpdateServer(m_SavedMaster, m_Class); } } else { // NSW-17844: We allow multiple servers in sidescan and going into two server mode can prevent us from restoring // the user selected source when turning unit off and on. if(m_Class != SonarCommon::eSonarServer_Sidescan) { if(m_SavedMaster == m_MyMac ) { // We were set as the server and a new server has just been detected, it could be a new unit joining the network or // a legacy unit that doesn't support the sever saving and restoring requested in NSW-23903, in either of these cases // we need to re-claim the server status instead of going into two server mode emit ClaimServer(m_Class); DBG_SONAR_SOURCE_STATE(DbgPrintf("Claiming server")); } else { m_TimeoutCounter = m_cTwoServerTimeout;//~~~~~ + GetTimeSinceBoot() / 10; if(m_TimeoutCounter > 20) { m_TimeoutCounter = 20 + (qrand() % 10); } ChangeState(SonarCommon::eSonarServerState_TwoServers); DBG_SONAR_SOURCE_STATE(DbgPrintf("New server (%s) - going to two server mode", IP.toString().toAscii().constData())); } } } break; case SonarCommon::eSonarServerState_Client: //~~~~~~~~~~~ Captured on state diagram? if(m_CurrentMac.IsBroadcast()) { m_CurrentMac = NewServerMac; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); } // Reset the timeout whenever we see our server... if(NewServerMac == m_CurrentMac || m_CurrentMac.IsBroadcast()) { m_TimeoutCounter = m_cClientTimeout; static const QHostAddress Broadcast(QHostAddress::Broadcast); if(m_CurrentIP == Broadcast) { // DbgPrintf("*****Sonar client updated server IP: %s", IP.toString().toAscii().constData()); m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); ClientMac = NewServerMac; NeedNewServerCommanded = true; } } else { // If this is the server we really want, the switch! if(NewServerMac == m_SavedMaster) { m_TimeoutCounter = m_cClientTimeout; m_CurrentMac = m_SavedMaster; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("Remote server (our server)")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientMac = m_SavedMaster; emit UpdateServer(m_SavedMaster, m_Class); } } break; case SonarCommon::eSonarServerState_TwoServers: // Need to restore our server if it comes to network a little late and we are in two server mode already // If this is the server we really want, the switch! if(NewServerMac == m_SavedMaster) { m_TimeoutCounter = m_cClientTimeout; m_CurrentMac = m_SavedMaster; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("Remote server, two servers (our server)")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientMac = m_SavedMaster; emit UpdateServer(m_SavedMaster, m_Class); } break; default: // All other cases ignore until they timeout break; } } if(NeedClientEmit) { emit SetClientState(ClientMac, IP); } if(NeedNewServerCommanded) { NewServerCommanded(ClientMac, IP, false); } }
void tSonarSourceStateMachine::NewServerCommanded(tMacAddress NewServerMac, QHostAddress IP, bool GUICommand) { // Ignore all remote masters in offline mode if(tSonarSettings::Instance()->OfflineModeUsed(m_Class)) { // The state can be in the process of updating by another signal that is coming // after the sonar settings already received the simulator on command. //Assert(m_State == eSonarServerState_Server); return; } // NSW-26815: Ignore server change commands if we don't have the source on our list const QHostAddress broadcast(QHostAddress::Broadcast); if(IP == broadcast) { // Invalid IP received, means the source is on our list, ignore this command // until source is detected... return; } bool NeedClientEmit = false; tMacAddress ClientMac; { tWriteLocker Locker(m_Lock); m_SavedMaster = NewServerMac; m_pSettings->SetValue("ServerMac", m_SavedMaster.ToString()); if(!m_Simulating) { if(m_SavedMaster == m_MyMac) { // NSW-24004: Only set client/server mode to false when becoming the sidescan server if(m_Class == SonarCommon::eSonarServer_Sidescan) { tSonarSettings::Instance()->SetClientServerMode(false); } m_CurrentIP = m_MyIP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("New server commanded, becoming server")); ChangeState(SonarCommon::eSonarServerState_Server); } else { QString classStr = tSonarSourceStateMachine::GetClassString(m_Class); DbgPrintf("New server(%s) - becoming client (%s)", classStr.toStdString().c_str(), IP.toString().toAscii().constData()); m_TimeoutCounter = m_cClientTimeout; m_CurrentMac = m_SavedMaster; m_CurrentIP = IP; m_pSettings->SetValue("ServerIP", m_CurrentIP.toString()); DBG_SONAR_SOURCE_STATE(DbgPrintf("New server commanded, becoming client")); ChangeState(SonarCommon::eSonarServerState_Client); NeedClientEmit = true; ClientMac = m_SavedMaster; // NSW-24004: Will set structure in client/server mode whenever we are not our own source, this will ensure that our // internal settings won't be affected by the setting changes made to the new source and vice-versa if(m_Class == SonarCommon::eSonarServer_Sidescan) { tSonarSettings::Instance()->SetClientServerMode(true); } } if(GUICommand && (m_Class != SonarCommon::eSonarServer_Sidescan)) { tThread::AssertGUIThread(); emit SendServerCommand(m_SavedMaster, m_Class); } } } emit UpdateServer(m_SavedMaster, m_Class); if(NeedClientEmit) { emit SetClientState(ClientMac, IP); } }
NS_IMETHODIMP nsNativeAppSupportUnix::Start(bool *aRetVal) { NS_ASSERTION(gAppData, "gAppData must not be null."); // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService, // from diffrent threads. This could lead to race conditions if the dbus is not // initialized before making any other library calls. #ifdef MOZ_ENABLE_DBUS dbus_threads_init_default(); #endif #if (MOZ_WIDGET_GTK == 2) if (gtk_major_version < MIN_GTK_MAJOR_VERSION || (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) { GtkWidget* versionErrDialog = gtk_message_dialog_new(nullptr, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, UNSUPPORTED_GTK_MSG, gtk_major_version, gtk_minor_version, MIN_GTK_MAJOR_VERSION, MIN_GTK_MINOR_VERSION); gtk_dialog_run(GTK_DIALOG(versionErrDialog)); gtk_widget_destroy(versionErrDialog); exit(0); } #endif *aRetVal = true; #ifdef MOZ_X11 gboolean sm_disable = FALSE; if (!getenv("SESSION_MANAGER")) { sm_disable = TRUE; } nsAutoCString prev_client_id; char **curarg = gArgv + 1; while (*curarg) { char *arg = *curarg; if (arg[0] == '-' && arg[1] == '-') { arg += 2; if (!strcmp(arg, "sm-disable")) { RemoveArg(curarg); sm_disable = TRUE; continue; } else if (!strcmp(arg, "sm-client-id")) { RemoveArg(curarg); if (*curarg[0] != '-') { prev_client_id = *curarg; RemoveArg(curarg); } continue; } } ++curarg; } if (prev_client_id.IsEmpty()) { prev_client_id = getenv("DESKTOP_AUTOSTART_ID"); } // We don't want child processes to use the same ID unsetenv("DESKTOP_AUTOSTART_ID"); char *client_id = nullptr; if (!sm_disable) { PRLibrary *iceLib = PR_LoadLibrary("libICE.so.6"); if (!iceLib) { return NS_OK; } PRLibrary *smLib = PR_LoadLibrary("libSM.so.6"); if (!smLib) { PR_UnloadLibrary(iceLib); return NS_OK; } IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(iceLib, "IceSetIOErrorHandler"); IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(iceLib, "IceAddConnectionWatch"); IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(iceLib, "IceConnectionNumber"); IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(iceLib, "IceProcessMessages"); IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(iceLib, "IceGetConnectionContext"); if (!IceSetIOErrorHandler || !IceAddConnectionWatch || !IceConnectionNumber || !IceProcessMessages || !IceGetConnectionContext) { PR_UnloadLibrary(iceLib); PR_UnloadLibrary(smLib); return NS_OK; } SmcInteractDone = (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone"); SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(smLib, "SmcSaveYourselfDone"); SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(smLib, "SmcInteractRequest"); SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(smLib, "SmcCloseConnection"); SmcOpenConnection = (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection"); SmcSetProperties = (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties"); if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest || !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) { PR_UnloadLibrary(iceLib); PR_UnloadLibrary(smLib); return NS_OK; } ice_init(); // all callbacks are mandatory in libSM 1.0, so listen even if we don't care. unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; SmcCallbacks callbacks; callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB; callbacks.save_yourself.client_data = static_cast<SmPointer>(this); callbacks.die.callback = nsNativeAppSupportUnix::DieCB; callbacks.die.client_data = static_cast<SmPointer>(this); callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB; callbacks.save_complete.client_data = nullptr; callbacks.shutdown_cancelled.callback = nsNativeAppSupportUnix::ShutdownCancelledCB; callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this); char errbuf[256]; mSessionConnection = SmcOpenConnection(nullptr, this, SmProtoMajor, SmProtoMinor, mask, &callbacks, prev_client_id.get(), &client_id, sizeof(errbuf), errbuf); } if (!mSessionConnection) { return NS_OK; } LogModule::Init(); // need to make sure initialized before SetClientState if (prev_client_id.IsEmpty() || (client_id && !prev_client_id.Equals(client_id))) { SetClientState(STATE_REGISTERING); } else { SetClientState(STATE_IDLE); } gdk_x11_set_sm_client_id(client_id); // Set SM Properties // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required // properties so must be set, and must have a sensible fallback value. // Determine executable path to use for XSMP session restore // Is there a request to suppress default binary launcher? nsAutoCString path(getenv("MOZ_APP_LAUNCHER")); if (path.IsEmpty()) { NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!"); nsCOMPtr<nsIFile> executablePath; nsresult rv; bool dummy; rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath)); if (NS_SUCCEEDED(rv)) { // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does nsAutoCString leafName; rv = executablePath->GetNativeLeafName(leafName); if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) { leafName.SetLength(leafName.Length() - strlen("-bin")); executablePath->SetNativeLeafName(leafName); } executablePath->GetNativePath(path); } } if (path.IsEmpty()) { // can't determine executable path. Best fallback is name from // application.ini but it might not resolve to the same executable at // launch time. path = gAppData->name; // will always be set ToLowerCase(path); MOZ_LOG(sMozSMLog, LogLevel::Warning, ("Could not determine executable path. Falling back to %s.", path.get())); } SmProp propRestart, propClone, propProgram, propUser, *props[4]; SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1]; int n = 0; NS_NAMED_LITERAL_CSTRING(kClientIDParam, "--sm-client-id"); SetSMValue(valsRestart[0], path); SetSMValue(valsRestart[1], kClientIDParam); SetSMValue(valsRestart[2], nsDependentCString(client_id)); SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart); props[n++] = &propRestart; SetSMValue(valsClone[0], path); SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone); props[n++] = &propClone; nsAutoCString appName(gAppData->name); // will always be set ToLowerCase(appName); SetSMValue(valsProgram[0], appName); SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram); props[n++] = &propProgram; nsAutoCString userName; // username that started the program struct passwd* pw = getpwuid(getuid()); if (pw && pw->pw_name) { userName = pw->pw_name; } else { userName = NS_LITERAL_CSTRING("nobody"); MOZ_LOG(sMozSMLog, LogLevel::Warning, ("Could not determine user-name. Falling back to %s.", userName.get())); } SetSMValue(valsUser[0], userName); SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser); props[n++] = &propUser; SmcSetProperties(mSessionConnection, n, props); g_free(client_id); #endif /* MOZ_X11 */ return NS_OK; }