[Spice-devel] [spice-xpi PATCHv2 07/12] Move StartClient() to the controller class

Christophe Fergeau cfergeau at redhat.com
Wed Mar 13 03:15:41 PDT 2013


This is platform specific, and is related to starting the
receiver of controller messages, so let's move it with the rest
of the platform-specific code.
---
 SpiceXPI/src/plugin/controller-unix.cpp | 106 +++++++++++++++++++++++++++++-
 SpiceXPI/src/plugin/controller.h        |  13 +++-
 SpiceXPI/src/plugin/plugin.cpp          | 110 ++++----------------------------
 SpiceXPI/src/plugin/plugin.h            |   7 +-
 4 files changed, 130 insertions(+), 106 deletions(-)

diff --git a/SpiceXPI/src/plugin/controller-unix.cpp b/SpiceXPI/src/plugin/controller-unix.cpp
index 0d8f0f8..489136e 100644
--- a/SpiceXPI/src/plugin/controller-unix.cpp
+++ b/SpiceXPI/src/plugin/controller-unix.cpp
@@ -53,20 +53,29 @@ extern "C" {
 #  include <fcntl.h>
 #  include <sys/socket.h>
 #  include <sys/un.h>
+#  include <sys/wait.h>
 }
 
 #include "rederrorcodes.h"
 #include "controller.h"
+#include "plugin.h"
 
-SpiceController::SpiceController():
+SpiceController::SpiceController(nsPluginInstance *aPlugin):
+    m_plugin(aPlugin),
     m_client_socket(-1)
 {
+    // create temporary directory in /tmp
+    char tmp_dir[] = "/tmp/spicec-XXXXXX";
+    m_tmp_dir = mkdtemp(tmp_dir);
 }
 
 SpiceController::~SpiceController()
 {
     g_debug(G_STRFUNC);
     Disconnect();
+
+    // delete the temporary directory used for a client socket
+    rmdir(m_tmp_dir.c_str());
 }
 
 void SpiceController::SetFilename(const std::string &name)
@@ -74,6 +83,11 @@ void SpiceController::SetFilename(const std::string &name)
     m_name = name;
 }
 
+void SpiceController::SetProxy(const std::string &proxy)
+{
+    m_proxy = proxy;
+}
+
 int SpiceController::Connect()
 {
     // check, if we have a filename for socket to create
@@ -148,6 +162,96 @@ uint32_t SpiceController::Write(const void *lpBuffer, uint32_t nBytesToWrite)
     return len;
 }
 
+bool SpiceController::StartClient()
+{
+    std::string socket_file(m_tmp_dir);
+    socket_file += "/spice-xpi";
+
+    /* use a pipe for the children to wait until it gets tracked */
+    int pipe_fds[2] = { -1, -1 };
+    if (pipe(pipe_fds) < 0) {
+        perror("spice-xpi system error");
+        return false;
+    }
+
+    m_pid_controller = fork();
+    if (m_pid_controller == 0)
+    {
+        setpgrp();
+
+        close(pipe_fds[1]);
+        pipe_fds[1] = -1;
+
+        char c;
+        if (read(pipe_fds[0], &c, 1) != 0)
+            g_critical("Error while reading on pipe: %s", g_strerror(errno));
+
+        close(pipe_fds[0]);
+        pipe_fds[0] = -1;
+
+        gchar **env = g_get_environ();
+        env = g_environ_setenv(env, "SPICE_XPI_SOCKET", socket_file.c_str(), TRUE);
+        if (!m_proxy.empty())
+            env = g_environ_setenv(env, "SPICE_PROXY", m_proxy.c_str(), TRUE);
+
+        execle("/usr/libexec/spice-xpi-client",
+               "/usr/libexec/spice-xpi-client", NULL,
+               env);
+        g_message("failed to run spice-xpi-client, running spicec instead");
+
+        // TODO: temporary fallback for backward compatibility
+        execle("/usr/bin/spicec",
+               "/usr/bin/spicec", "--controller", NULL,
+               env);
+
+        g_critical("ERROR failed to run spicec fallback");
+        g_strfreev(env);
+        exit(EXIT_FAILURE);
+    }
+    else
+    {
+        g_debug("child pid: %"G_GUINT64_FORMAT, (guint64)m_pid_controller);
+
+        close(pipe_fds[0]);
+        pipe_fds[0] = -1;
+
+        pthread_t controller_thread_id;
+        pthread_create(&controller_thread_id, NULL, ControllerWaitHelper,
+            reinterpret_cast<void*>(this));
+
+        close(pipe_fds[1]);
+        pipe_fds[1] = -1;
+
+        this->SetFilename(socket_file);
+
+        return true;
+    }
+
+    g_return_val_if_reached(false);
+}
+
+void SpiceController::StopClient()
+{
+    if (m_pid_controller > 0)
+        kill(-m_pid_controller, SIGTERM);
+}
+
+void *SpiceController::ControllerWaitHelper(void *opaque)
+{
+    SpiceController *fake_this = reinterpret_cast<SpiceController *>(opaque);
+    if (!fake_this)
+        return NULL;
+
+    int exit_code;
+    waitpid(fake_this->m_pid_controller, &exit_code, 0);
+    g_debug("child finished, pid: %"G_GUINT64_FORMAT, (guint64)exit_code);
+
+    fake_this->m_plugin->OnSpiceClientExit(exit_code);
+    fake_this->m_pid_controller = -1;
+
+    return NULL;
+}
+
 int SpiceController::TranslateRC(int nRC)
 {
     switch (nRC)
diff --git a/SpiceXPI/src/plugin/controller.h b/SpiceXPI/src/plugin/controller.h
index 001d2b3..d7d3875 100644
--- a/SpiceXPI/src/plugin/controller.h
+++ b/SpiceXPI/src/plugin/controller.h
@@ -65,13 +65,18 @@ extern "C" {
 
 #include <spice/controller_prot.h>
 
+class nsPluginInstance;
+
 class SpiceController
 {
 public:
-    SpiceController();
+    SpiceController(nsPluginInstance *aPlugin);
     ~SpiceController();
 
+    bool StartClient();
+    void StopClient();
     void SetFilename(const std::string &name);
+    void SetProxy(const std::string &proxy);
     int Connect(int nRetries);
     void Disconnect();
     uint32_t Write(const void *lpBuffer, uint32_t nBytesToWrite);
@@ -80,8 +85,14 @@ public:
 
 private:
     int Connect();
+    static void *ControllerWaitHelper(void *opaque);
+
+    nsPluginInstance *m_plugin;
     int m_client_socket;
     std::string m_name;
+    std::string m_tmp_dir;
+    pid_t m_pid_controller;
+    std::string m_proxy;
 };
 
 #endif // SPICE_CONTROLLER_H
diff --git a/SpiceXPI/src/plugin/plugin.cpp b/SpiceXPI/src/plugin/plugin.cpp
index 3f2de6a..58ec875 100644
--- a/SpiceXPI/src/plugin/plugin.cpp
+++ b/SpiceXPI/src/plugin/plugin.cpp
@@ -47,10 +47,6 @@
 
 #include "config.h"
 
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
@@ -175,8 +171,8 @@ void NS_DestroyPluginInstance(nsPluginInstanceBase *aPlugin)
 
 nsPluginInstance::nsPluginInstance(NPP aInstance):
     nsPluginInstanceBase(),
-    m_pid_controller(-1),
     m_connected_status(-2),
+    m_external_controller(this),
     m_instance(aInstance),
     m_initialized(true),
     m_window(NULL),
@@ -188,10 +184,6 @@ nsPluginInstance::nsPluginInstance(NPP aInstance):
     m_usb_auto_share(true),
     m_scriptable_peer(NULL)
 {
-    // create temporary directory in /tmp
-    char tmp_dir[] = "/tmp/spicec-XXXXXX";
-    m_tmp_dir = mkdtemp(tmp_dir);
-
 #if !GLIB_CHECK_VERSION(2, 35, 0)
     g_type_init();
 #endif
@@ -205,9 +197,6 @@ nsPluginInstance::~nsPluginInstance()
     // and zero its m_plugin member
     if (m_scriptable_peer)
         NPN_ReleaseObject(m_scriptable_peer);
-
-    // delete the temporary directory used for a client socket
-    rmdir(m_tmp_dir.c_str());
 }
 
 NPBool nsPluginInstance::init(NPWindow *aWindow)
@@ -233,6 +222,7 @@ NPBool nsPluginInstance::init(NPWindow *aWindow)
     m_color_depth.clear();
     m_disable_effects.clear();
     m_proxy.clear();
+    m_external_controller.SetProxy(std::string());
 
     m_fullscreen = false;
     m_smartcard = false;
@@ -537,6 +527,7 @@ char *nsPluginInstance::GetProxy() const
 void nsPluginInstance::SetProxy(const char *aProxy)
 {
     m_proxy = aProxy;
+    m_external_controller.SetProxy(m_proxy);
 }
 
 void nsPluginInstance::WriteToPipe(const void *data, uint32_t size)
@@ -586,74 +577,6 @@ void nsPluginInstance::SendStr(uint32_t id, std::string str)
     free(msg);
 }
 
-bool nsPluginInstance::StartClient()
-{
-    std::string socket_file(m_tmp_dir);
-    socket_file += "/spice-xpi";
-
-    /* use a pipe for the children to wait until it gets tracked */
-    int pipe_fds[2] = { -1, -1 };
-    if (pipe(pipe_fds) < 0) {
-        perror("spice-xpi system error");
-        return false;
-    }
-
-    m_pid_controller = fork();
-    if (m_pid_controller == 0)
-    {
-        setpgrp();
-
-        close(pipe_fds[1]);
-        pipe_fds[1] = -1;
-
-        char c;
-        if (read(pipe_fds[0], &c, 1) != 0)
-            g_critical("Error while reading on pipe: %s", g_strerror(errno));
-
-        close(pipe_fds[0]);
-        pipe_fds[0] = -1;
-
-        gchar **env = g_get_environ();
-        env = g_environ_setenv(env, "SPICE_XPI_SOCKET", socket_file.c_str(), TRUE);
-        if (!m_proxy.empty())
-            env = g_environ_setenv(env, "SPICE_PROXY", m_proxy.c_str(), TRUE);
-
-        execle("/usr/libexec/spice-xpi-client",
-               "/usr/libexec/spice-xpi-client", NULL,
-               env);
-        g_message("failed to run spice-xpi-client, running spicec instead");
-
-        // TODO: temporary fallback for backward compatibility
-        execle("/usr/bin/spicec",
-               "/usr/bin/spicec", "--controller", NULL,
-               env);
-
-        g_critical("ERROR failed to run spicec fallback");
-        g_strfreev(env);
-        exit(EXIT_FAILURE);
-    }
-    else
-    {
-        g_debug("child pid: %"G_GUINT64_FORMAT, (guint64)m_pid_controller);
-
-        close(pipe_fds[0]);
-        pipe_fds[0] = -1;
-
-        pthread_t controller_thread_id;
-        pthread_create(&controller_thread_id, NULL, ControllerWaitHelper,
-            reinterpret_cast<void*>(this));
-
-        close(pipe_fds[1]);
-        pipe_fds[1] = -1;
-
-        m_external_controller.SetFilename(socket_file);
-
-        return true;
-    }
-
-    g_return_val_if_reached(false);
-}
-
 bool nsPluginInstance::CreateTrustStoreFile(const std::string &trust_store)
 {
     GFile *tmp_file;
@@ -706,7 +629,7 @@ void nsPluginInstance::Connect()
         return;
     }
 
-    if (!this->StartClient()) {
+    if (!m_external_controller.StartClient()) {
         g_critical("failed to start SPICE client");
         return;
     }
@@ -759,8 +682,7 @@ void nsPluginInstance::Show()
 
 void nsPluginInstance::Disconnect()
 {
-    if (m_pid_controller > 0)
-        kill(-m_pid_controller, SIGTERM);
+    m_external_controller.StopClient();
 }
 
 void nsPluginInstance::ConnectedStatus(int32_t *retval)
@@ -832,26 +754,16 @@ void nsPluginInstance::CallOnDisconnected(int code)
     NPN_ReleaseVariantValue(&var_on_disconnected);
 }
 
-void *nsPluginInstance::ControllerWaitHelper(void *opaque)
+void nsPluginInstance::OnSpiceClientExit(int exit_code)
 {
-    nsPluginInstance *fake_this = reinterpret_cast<nsPluginInstance *>(opaque);
-    if (!fake_this)
-        return NULL;
-
-    int exit_code;
-    waitpid(fake_this->m_pid_controller, &exit_code, 0);
-    g_debug("child finished, pid: %"G_GUINT64_FORMAT, (guint64)exit_code);
-
-    fake_this->m_connected_status = fake_this->m_external_controller.TranslateRC(exit_code);
+    m_connected_status = m_external_controller.TranslateRC(exit_code);
     if (!getenv("SPICE_XPI_DEBUG"))
     {
-        fake_this->CallOnDisconnected(exit_code);
-        fake_this->m_external_controller.Disconnect();
+        CallOnDisconnected(exit_code);
+        m_external_controller.Disconnect();
     }
-    
-    fake_this->RemoveTrustStoreFile();
-    fake_this->m_pid_controller = -1;
-    return NULL;
+
+    RemoveTrustStoreFile();
 }
 
 // ==============================
diff --git a/SpiceXPI/src/plugin/plugin.h b/SpiceXPI/src/plugin/plugin.h
index ea50ca5..5e7f079 100644
--- a/SpiceXPI/src/plugin/plugin.h
+++ b/SpiceXPI/src/plugin/plugin.h
@@ -174,8 +174,9 @@ public:
 
     NPObject *GetScriptablePeer();
     
+    void OnSpiceClientExit(int exit_code);
+
 private:
-    static void *ControllerWaitHelper(void *opaque);
     void WriteToPipe(const void *data, uint32_t size);
     void SendInit();
     void SendMsg(uint32_t id);
@@ -185,12 +186,9 @@ private:
     void CallOnDisconnected(int code);
   
 private:
-    bool StartClient();
-    bool CreateTrustStore();
     bool CreateTrustStoreFile(const std::string &trust_store);
     bool RemoveTrustStoreFile();
 
-    pid_t m_pid_controller;
     int32_t m_connected_status;
     SpiceController m_external_controller;
 
@@ -224,7 +222,6 @@ private:
     std::string m_proxy;
     
     NPObject *m_scriptable_peer;
-    std::string m_tmp_dir;
     std::string m_trust_store_file;
 };
 
-- 
1.8.1.4



More information about the Spice-devel mailing list