Пример #1
0
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
  }
}
Пример #4
0
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);
    }
}
Пример #5
0
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;
}