[Spice-devel] [spice-xpi PATCHv2 12/12] Add an abstract controller base class

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


It contains all the generic code, then platform-specific controller
implementations will inherit from it and overload the non-generic parts
abstract methods.
---
v2:
  - adjust to the changes in other patches, in particular the split of
    GetClientPaths, which should fix a compilation issue that occurred
    with the first iteration

 SpiceXPI/src/plugin/Makefile.am         |   2 +
 SpiceXPI/src/plugin/controller-unix.cpp | 215 +++-----------------------
 SpiceXPI/src/plugin/controller-unix.h   |  97 ++++++++++++
 SpiceXPI/src/plugin/controller.cpp      | 260 ++++++++++++++++++++++++++++++++
 SpiceXPI/src/plugin/controller.h        |  29 ++--
 SpiceXPI/src/plugin/plugin.cpp          |  22 +--
 SpiceXPI/src/plugin/plugin.h            |   2 +-
 7 files changed, 407 insertions(+), 220 deletions(-)
 create mode 100644 SpiceXPI/src/plugin/controller-unix.h
 create mode 100644 SpiceXPI/src/plugin/controller.cpp

diff --git a/SpiceXPI/src/plugin/Makefile.am b/SpiceXPI/src/plugin/Makefile.am
index 2f12e70..2db218e 100644
--- a/SpiceXPI/src/plugin/Makefile.am
+++ b/SpiceXPI/src/plugin/Makefile.am
@@ -26,8 +26,10 @@ libnsISpicec_la_SOURCES =			\
 	$(top_srcdir)/common/rederrorcodes.h	\
 	glib-compat.c				\
 	glib-compat.h				\
+	controller.cpp				\
 	controller.h				\
 	controller-unix.cpp			\
+	controller-unix.h			\
 	npapi/npapi.h				\
 	npapi/npfunctions.h			\
 	npapi/npruntime.h			\
diff --git a/SpiceXPI/src/plugin/controller-unix.cpp b/SpiceXPI/src/plugin/controller-unix.cpp
index 04257e9..1e60e5c 100644
--- a/SpiceXPI/src/plugin/controller-unix.cpp
+++ b/SpiceXPI/src/plugin/controller-unix.cpp
@@ -40,6 +40,7 @@
  *   the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
+#include "config.h"
 
 #include <cstdio>
 #include <cstdlib>
@@ -57,11 +58,11 @@ extern "C" {
 }
 
 #include "rederrorcodes.h"
-#include "controller.h"
+#include "controller-unix.h"
 #include "plugin.h"
 
-SpiceController::SpiceController(nsPluginInstance *aPlugin):
-    m_plugin(aPlugin),
+SpiceControllerUnix::SpiceControllerUnix(nsPluginInstance *aPlugin):
+    SpiceController(aPlugin),
     m_client_socket(-1)
 {
     // create temporary directory in /tmp
@@ -69,7 +70,7 @@ SpiceController::SpiceController(nsPluginInstance *aPlugin):
     m_tmp_dir = mkdtemp(tmp_dir);
 }
 
-SpiceController::~SpiceController()
+SpiceControllerUnix::~SpiceControllerUnix()
 {
     g_debug(G_STRFUNC);
     Disconnect();
@@ -78,17 +79,7 @@ SpiceController::~SpiceController()
     rmdir(m_tmp_dir.c_str());
 }
 
-void SpiceController::SetFilename(const std::string &name)
-{
-    m_name = name;
-}
-
-void SpiceController::SetProxy(const std::string &proxy)
-{
-    m_proxy = proxy;
-}
-
-int SpiceController::Connect()
+int SpiceControllerUnix::Connect()
 {
     // check, if we have a filename for socket to create
     if (m_name.empty())
@@ -122,20 +113,8 @@ int SpiceController::Connect()
     return rc;
 }
 
-int SpiceController::Connect(const int nRetries)
+bool SpiceControllerUnix::CheckPipe()
 {
-    int rc = -1;
-    int sleep_time = 0;
-
-    // try to connect for specified count
-    for (int i = 0; rc != 0 && i < nRetries; ++i)
-    {
-        rc = Connect();
-        g_usleep(sleep_time * G_USEC_PER_SEC);
-        ++sleep_time;
-    }
-
-    return rc;
 }
 
 GStrv SpiceControllerUnix::GetClientPath()
@@ -152,7 +131,7 @@ GStrv SpiceControllerUnix::GetFallbackClientPath()
     return g_strdupv((GStrv)fallback_argv);
 }
 
-void SpiceController::SetupControllerPipe(GStrv &env)
+void SpiceControllerUnix::SetupControllerPipe(GStrv &env)
 {
     std::string socket_file(this->m_tmp_dir);
     socket_file += "/spice-xpi";
@@ -162,18 +141,13 @@ void SpiceController::SetupControllerPipe(GStrv &env)
     env = g_environ_setenv(env, "SPICE_XPI_SOCKET", socket_file.c_str(), TRUE);
 }
 
-void SpiceController::Disconnect()
+void SpiceControllerUnix::StopClient()
 {
-    // close the socket
-    close(m_client_socket);
-    m_client_socket = -1;
-
-    // delete the temporary file, which is used for the socket
-    unlink(m_name.c_str());
-    m_name.clear();
+    if (m_pid_controller > 0)
+        kill(-m_pid_controller, SIGTERM);
 }
 
-uint32_t SpiceController::Write(const void *lpBuffer, uint32_t nBytesToWrite)
+uint32_t SpiceControllerUnix::Write(const void *lpBuffer, uint32_t nBytesToWrite)
 {
     ssize_t len = send(m_client_socket, lpBuffer, nBytesToWrite, 0);
 
@@ -186,164 +160,13 @@ uint32_t SpiceController::Write(const void *lpBuffer, uint32_t nBytesToWrite)
     return len;
 }
 
-void SpiceController::ChildExited(GPid pid, gint status, gpointer user_data)
-{
-    SpiceController *fake_this = (SpiceController *)user_data;
-
-    g_message("Client with pid %p exited", pid);
-
-    g_main_loop_quit(fake_this->m_child_watch_mainloop);
-    /* FIXME: we are not in the main thread!! */
-    fake_this->m_plugin->OnSpiceClientExit(status);
-}
-
-void SpiceController::WaitForPid(GPid pid)
-{
-    GMainContext *context;
-    GSource *source;
-
-    context = g_main_context_new();
-
-    m_child_watch_mainloop = g_main_loop_new(context, FALSE);
-    source = g_child_watch_source_new(pid);
-    g_source_set_callback(source, (GSourceFunc)ChildExited, this, NULL);
-    g_source_attach(source, context);
-
-    g_main_loop_run(m_child_watch_mainloop);
-
-    g_main_loop_unref(m_child_watch_mainloop);
-    g_main_context_unref(context);
-
-    g_spawn_close_pid(pid);
-    if (pid == m_pid_controller)
-        m_pid_controller = 0;
-}
-
-
-gpointer SpiceController::ClientThread(gpointer data)
-{
-    SpiceController *fake_this = (SpiceController *)data;
-    gchar **env = g_get_environ();
-    GPid pid;
-    gboolean spawned = FALSE;
-    GError *error = NULL;
-    GStrv client_argv;
-
-    // Setup client environment
-    fake_this->SetupControllerPipe(env);
-    if (!fake_this->m_proxy.empty())
-        env = g_environ_setenv(env, "SPICE_PROXY", fake_this->m_proxy.c_str(), TRUE);
-
-    // Try to spawn main client
-    client_argv = fake_this->GetClientPath();
-    if (client_argv != NULL) {
-        char *argv_str = g_strjoinv(" ", client_argv);
-        g_warning("main client cmdline: %s", argv_str);
-        g_free(argv_str);
-
-        spawned = g_spawn_async(NULL,
-                                client_argv, env,
-                                G_SPAWN_DO_NOT_REAP_CHILD,
-                                NULL, NULL, /* child_func, child_arg */
-                                &pid, &error);
-        if (error != NULL) {
-            g_warning("failed to start %s: %s", client_argv[0], error->message);
-            g_warn_if_fail(spawned == FALSE);
-            g_clear_error(&error);
-        }
-        g_strfreev(client_argv);
-    }
-
-    if (!spawned) {
-        // Fallback client for backward compatibility
-        GStrv fallback_argv;
-        char *argv_str;
-        fallback_argv = fake_this->GetFallbackClientPath();
-        if (fallback_argv == NULL) {
-            goto out;
-        }
-
-        argv_str = g_strjoinv(" ", fallback_argv);
-        g_warning("fallback client cmdline: %s", argv_str);
-        g_free(argv_str);
-
-        g_message("failed to run preferred client, running fallback client instead");
-        spawned = g_spawn_async(NULL, fallback_argv, env,
-                                G_SPAWN_DO_NOT_REAP_CHILD,
-                                NULL, NULL, /* child_func, child_arg */
-                                &pid, &error);
-        if (error != NULL) {
-            g_warning("failed to start %s: %s", fallback_argv[0], error->message);
-            g_warn_if_fail(spawned == FALSE);
-            g_clear_error(&error);
-        }
-    }
-
-out:
-    g_strfreev(env);
-
-    if (!spawned) {
-        g_critical("ERROR failed to run spicec fallback");
-        return NULL;
-    }
-
-#ifdef XP_UNIX
-    fake_this->m_pid_controller = pid;
-#endif
-    fake_this->WaitForPid(pid);
-
-    return NULL;
-}
-
-bool SpiceController::StartClient()
-{
-    GThread *thread;
-
-    thread = g_thread_new("spice-xpi client thread", ClientThread, this);
-
-    return (thread != NULL);
-}
-
-void SpiceController::StopClient()
-{
-    if (m_pid_controller > 0)
-        kill(-m_pid_controller, SIGTERM);
-}
-
-int SpiceController::TranslateRC(int nRC)
+void SpiceControllerUnix::Disconnect()
 {
-    switch (nRC)
-    {
-    case SPICEC_ERROR_CODE_SUCCESS:
-        return 0;
-
-    case SPICEC_ERROR_CODE_GETHOSTBYNAME_FAILED:
-        return RDP_ERROR_CODE_HOST_NOT_FOUND;
-
-    case SPICEC_ERROR_CODE_CONNECT_FAILED:
-        return RDP_ERROR_CODE_WINSOCK_CONNECT_FAILED;
-
-    case SPICEC_ERROR_CODE_ERROR:
-    case SPICEC_ERROR_CODE_SOCKET_FAILED:
-        return RDP_ERROR_CODE_INTERNAL_ERROR;
-
-    case SPICEC_ERROR_CODE_RECV_FAILED:
-        return RDP_ERROR_RECV_WINSOCK_FAILED;
-
-    case SPICEC_ERROR_CODE_SEND_FAILED:
-        return RDP_ERROR_SEND_WINSOCK_FAILED;
-
-    case SPICEC_ERROR_CODE_NOT_ENOUGH_MEMORY:
-        return RDP_ERROR_CODE_OUT_OF_MEMORY;
-
-    case SPICEC_ERROR_CODE_AGENT_TIMEOUT:
-        return RDP_ERROR_CODE_TIMEOUT;
-
-    case SPICEC_ERROR_CODE_AGENT_ERROR:
-        return RDP_ERROR_CODE_INTERNAL_ERROR;
+    // close the socket
+    close(m_client_socket);
+    m_client_socket = -1;
 
-    default:
-        return RDP_ERROR_CODE_INTERNAL_ERROR;
-    }
+    // delete the temporary file, which is used for the socket
+    unlink(m_name.c_str());
+    m_name.clear();
 }
-
diff --git a/SpiceXPI/src/plugin/controller-unix.h b/SpiceXPI/src/plugin/controller-unix.h
new file mode 100644
index 0000000..bba884d
--- /dev/null
+++ b/SpiceXPI/src/plugin/controller-unix.h
@@ -0,0 +1,97 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ *   The contents of this file are subject to the Mozilla Public License Version
+ *   1.1 (the "License"); you may not use this file except in compliance with
+ *   the License. You may obtain a copy of the License at
+ *   http://www.mozilla.org/MPL/
+ *
+ *   Software distributed under the License is distributed on an "AS IS" basis,
+ *   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ *   for the specific language governing rights and limitations under the
+ *   License.
+ *
+ *   Copyright 2009-2011, Red Hat Inc.
+ *   Copyright 2013, Red Hat Inc.
+ *   Based on mozilla.org's scriptable plugin example
+ *
+ *   The Original Code is mozilla.org code.
+ *
+ *   The Initial Developer of the Original Code is
+ *   Netscape Communications Corporation.
+ *   Portions created by the Initial Developer are Copyright (C) 1998
+ *   the Initial Developer. All Rights Reserved.
+ *
+ *   Contributor(s):
+ *   Uri Lublin
+ *   Martin Stransky
+ *   Peter Hatina
+ *   Christophe Fergeau
+ *
+ *   Alternatively, the contents of this file may be used under the terms of
+ *   either the GNU General Public License Version 2 or later (the "GPL"), or
+ *   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ *   in which case the provisions of the GPL or the LGPL are applicable instead
+ *   of those above. If you wish to allow use of your version of this file only
+ *   under the terms of either the GPL or the LGPL, and not to allow others to
+ *   use your version of this file under the terms of the MPL, indicate your
+ *   decision by deleting the provisions above and replace them with the notice
+ *   and other provisions required by the GPL or the LGPL. If you do not delete
+ *   the provisions above, a recipient may use your version of this file under
+ *   the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef SPICE_CONTROLLER_UNIX_H
+#define SPICE_CONTROLLER_UNIX_H
+
+/*
+    Basic assumption:
+    ------------------
+    Cross platform compatible.
+    Easy to transform into remote process communication
+    Secured
+
+    chosen:
+        Unix - Unix Domain Sockets (easy to change into regular sockets for remote communication)
+        Windows - Named pipe (which allows remote access and is duplex
+            (rather than anonymous pipe which is local only and one way)
+*/
+
+#include <glib.h>
+#include <glib-object.h> /* for GStrv */
+#include <gio/gio.h>
+#include <string>
+extern "C" {
+#  include <stdint.h>
+#  include <limits.h>
+}
+
+#include <spice/controller_prot.h>
+#include "controller.h"
+
+class nsPluginInstance;
+
+class SpiceControllerUnix: public SpiceController
+{
+public:
+    SpiceControllerUnix(nsPluginInstance *aPlugin);
+    virtual ~SpiceControllerUnix();
+
+    virtual void StopClient();
+    virtual uint32_t Write(const void *lpBuffer, uint32_t nBytesToWrite);
+    int Connect(int nRetries) { return SpiceController::Connect(nRetries); };
+
+private:
+    virtual int Connect();
+    virtual void Disconnect();
+    virtual void SetupControllerPipe(GStrv &env);
+    virtual bool CheckPipe();
+    virtual GStrv GetClientPath(void);
+    virtual GStrv GetFallbackClientPath(void);
+
+    int m_client_socket;
+    std::string m_tmp_dir;
+};
+
+#endif // SPICE_CONTROLLER_UNIX_H
diff --git a/SpiceXPI/src/plugin/controller.cpp b/SpiceXPI/src/plugin/controller.cpp
new file mode 100644
index 0000000..ccef1d4
--- /dev/null
+++ b/SpiceXPI/src/plugin/controller.cpp
@@ -0,0 +1,260 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ *   The contents of this file are subject to the Mozilla Public License Version
+ *   1.1 (the "License"); you may not use this file except in compliance with
+ *   the License. You may obtain a copy of the License at
+ *   http://www.mozilla.org/MPL/
+ *
+ *   Software distributed under the License is distributed on an "AS IS" basis,
+ *   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ *   for the specific language governing rights and limitations under the
+ *   License.
+ *
+ *   Copyright 2009-2011, Red Hat Inc.
+ *   Copyright 2013, Red Hat Inc.
+ *   Based on mozilla.org's scriptable plugin example
+ *
+ *   The Original Code is mozilla.org code.
+ *
+ *   The Initial Developer of the Original Code is
+ *   Netscape Communications Corporation.
+ *   Portions created by the Initial Developer are Copyright (C) 1998
+ *   the Initial Developer. All Rights Reserved.
+ *
+ *   Contributor(s):
+ *   Uri Lublin
+ *   Martin Stransky
+ *   Peter Hatina
+ *   Christophe Fergeau
+ *
+ *   Alternatively, the contents of this file may be used under the terms of
+ *   either the GNU General Public License Version 2 or later (the "GPL"), or
+ *   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ *   in which case the provisions of the GPL or the LGPL are applicable instead
+ *   of those above. If you wish to allow use of your version of this file only
+ *   under the terms of either the GPL or the LGPL, and not to allow others to
+ *   use your version of this file under the terms of the MPL, indicate your
+ *   decision by deleting the provisions above and replace them with the notice
+ *   and other provisions required by the GPL or the LGPL. If you do not delete
+ *   the provisions above, a recipient may use your version of this file under
+ *   the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "config.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <glib.h>
+
+#include "rederrorcodes.h"
+#include "controller.h"
+#include "plugin.h"
+
+SpiceController::SpiceController(nsPluginInstance *aPlugin):
+    m_pid_controller(0),
+    m_pipe(NULL),
+    m_plugin(aPlugin),
+    m_child_watch_mainloop(NULL)
+{
+}
+
+SpiceController::~SpiceController()
+{
+    g_debug(G_STRFUNC);
+    Disconnect();
+}
+
+void SpiceController::SetFilename(const std::string &name)
+{
+    m_name = name;
+}
+
+void SpiceController::SetProxy(const std::string &proxy)
+{
+    m_proxy = proxy;
+}
+
+#define FACILITY_SPICEX             50
+#define FACILITY_CREATE_RED_PROCESS 51
+#define FACILITY_STRING_OPERATION   52
+#define FACILITY_CREATE_RED_EVENT   53
+#define FACILITY_CREATE_RED_PIPE    54
+#define FACILITY_PIPE_OPERATION     55
+
+int SpiceController::Connect(const int nRetries)
+{
+    int rc = -1;
+    int sleep_time = 0;
+
+    // try to connect for specified count
+    for (int i = 0; rc != 0 && i < nRetries; ++i)
+    {
+        rc = Connect();
+        g_usleep(sleep_time * G_USEC_PER_SEC);
+        ++sleep_time;
+    }
+
+    return rc;
+}
+
+void SpiceController::Disconnect()
+{
+}
+
+void SpiceController::ChildExited(GPid pid, gint status, gpointer user_data)
+{
+    SpiceController *fake_this = (SpiceController *)user_data;
+
+    g_message("Client with pid %p exited", pid);
+
+    g_main_loop_quit(fake_this->m_child_watch_mainloop);
+    /* FIXME: we are not in the main thread!! */
+    fake_this->m_plugin->OnSpiceClientExit(status);
+}
+
+void SpiceController::WaitForPid(GPid pid)
+{
+    GMainContext *context;
+    GSource *source;
+
+    context = g_main_context_new();
+
+    m_child_watch_mainloop = g_main_loop_new(context, FALSE);
+    source = g_child_watch_source_new(pid);
+    g_source_set_callback(source, (GSourceFunc)ChildExited, this, NULL);
+    g_source_attach(source, context);
+
+    g_main_loop_run(m_child_watch_mainloop);
+
+    g_main_loop_unref(m_child_watch_mainloop);
+    g_main_context_unref(context);
+
+    g_spawn_close_pid(pid);
+    if (pid == m_pid_controller)
+        m_pid_controller = 0;
+}
+
+gpointer SpiceController::ClientThread(gpointer data)
+{
+    SpiceController *fake_this = (SpiceController *)data;
+    gchar **env = g_get_environ();
+    GPid pid;
+    gboolean spawned = FALSE;
+    GError *error = NULL;
+    GStrv client_argv;
+
+    // Setup client environment
+    fake_this->SetupControllerPipe(env);
+    if (!fake_this->m_proxy.empty())
+        env = g_environ_setenv(env, "SPICE_PROXY", fake_this->m_proxy.c_str(), TRUE);
+
+    // Try to spawn main client
+    client_argv = fake_this->GetClientPath();
+    if (client_argv != NULL) {
+        char *argv_str = g_strjoinv(" ", client_argv);
+        g_warning("main client cmdline: %s", argv_str);
+        g_free(argv_str);
+
+        spawned = g_spawn_async(NULL,
+                                client_argv, env,
+                                G_SPAWN_DO_NOT_REAP_CHILD,
+                                NULL, NULL, /* child_func, child_arg */
+                                &pid, &error);
+        if (error != NULL) {
+            g_warning("failed to start %s: %s", client_argv[0], error->message);
+            g_warn_if_fail(spawned == FALSE);
+            g_clear_error(&error);
+        }
+        g_strfreev(client_argv);
+    }
+
+    if (!spawned) {
+        // Fallback client for backward compatibility
+        GStrv fallback_argv;
+        char *argv_str;
+        fallback_argv = fake_this->GetFallbackClientPath();
+        if (fallback_argv == NULL) {
+            goto out;
+        }
+
+        argv_str = g_strjoinv(" ", fallback_argv);
+        g_warning("fallback client cmdline: %s", argv_str);
+        g_free(argv_str);
+
+        g_message("failed to run preferred client, running fallback client instead");
+        spawned = g_spawn_async(NULL, fallback_argv, env,
+                                G_SPAWN_DO_NOT_REAP_CHILD,
+                                NULL, NULL, /* child_func, child_arg */
+                                &pid, &error);
+        if (error != NULL) {
+            g_warning("failed to start %s: %s", fallback_argv[0], error->message);
+            g_warn_if_fail(spawned == FALSE);
+            g_clear_error(&error);
+        }
+    }
+
+    out:
+        g_strfreev(env);
+
+    if (!spawned) {
+        g_critical("ERROR failed to run spicec fallback");
+        return NULL;
+    }
+
+#ifdef XP_UNIX
+    fake_this->m_pid_controller = pid;
+#endif
+    fake_this->WaitForPid(pid);
+
+    return NULL;
+}
+
+bool SpiceController::StartClient()
+{
+    GThread *thread;
+
+    thread = g_thread_new("spice-xpi client thread", ClientThread, this);
+
+    return (thread != NULL);
+}
+
+int SpiceController::TranslateRC(int nRC)
+{
+    switch (nRC)
+    {
+    case SPICEC_ERROR_CODE_SUCCESS:
+        return 0;
+
+    case SPICEC_ERROR_CODE_GETHOSTBYNAME_FAILED:
+        return RDP_ERROR_CODE_HOST_NOT_FOUND;
+
+    case SPICEC_ERROR_CODE_CONNECT_FAILED:
+        return RDP_ERROR_CODE_WINSOCK_CONNECT_FAILED;
+
+    case SPICEC_ERROR_CODE_ERROR:
+    case SPICEC_ERROR_CODE_SOCKET_FAILED:
+        return RDP_ERROR_CODE_INTERNAL_ERROR;
+
+    case SPICEC_ERROR_CODE_RECV_FAILED:
+        return RDP_ERROR_RECV_WINSOCK_FAILED;
+
+    case SPICEC_ERROR_CODE_SEND_FAILED:
+        return RDP_ERROR_SEND_WINSOCK_FAILED;
+
+    case SPICEC_ERROR_CODE_NOT_ENOUGH_MEMORY:
+        return RDP_ERROR_CODE_OUT_OF_MEMORY;
+
+    case SPICEC_ERROR_CODE_AGENT_TIMEOUT:
+        return RDP_ERROR_CODE_TIMEOUT;
+
+    case SPICEC_ERROR_CODE_AGENT_ERROR:
+        return RDP_ERROR_CODE_INTERNAL_ERROR;
+
+    default:
+        return RDP_ERROR_CODE_INTERNAL_ERROR;
+    }
+}
diff --git a/SpiceXPI/src/plugin/controller.h b/SpiceXPI/src/plugin/controller.h
index b38f7bc..02a4302 100644
--- a/SpiceXPI/src/plugin/controller.h
+++ b/SpiceXPI/src/plugin/controller.h
@@ -59,6 +59,7 @@
 
 #include <glib.h>
 #include <glib-object.h> /* for GStrv */
+#include <gio/gio.h>
 #include <string>
 extern "C" {
 #  include <stdint.h>
@@ -73,33 +74,35 @@ class SpiceController
 {
 public:
     SpiceController(nsPluginInstance *aPlugin);
-    ~SpiceController();
+    virtual ~SpiceController();
 
     bool StartClient();
-    void StopClient();
+    virtual void StopClient() = 0;
     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);
+    virtual void Disconnect();
+    virtual uint32_t Write(const void *lpBuffer, uint32_t nBytesToWrite) = 0;
 
     static int TranslateRC(int nRC);
 
+protected:
+    std::string m_name;
+    std::string m_proxy;
+    GPid m_pid_controller;
+    GOutputStream *m_pipe;
+
 private:
-    int Connect();
+    virtual int Connect() = 0;
     void WaitForPid(GPid pid);
-    void SetupControllerPipe(GStrv &env);
-    GStrv GetClientPath(void);
-    GStrv GetFallbackClientPath(void);
+    virtual void SetupControllerPipe(GStrv &env) = 0;
+    virtual bool CheckPipe() = 0;
+    virtual GStrv GetClientPath(void) = 0;
+    virtual GStrv GetFallbackClientPath(void) = 0;
     static void ChildExited(GPid pid, gint status, gpointer user_data);
     static gpointer ClientThread(gpointer data);
 
     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;
 
     GMainLoop *m_child_watch_mainloop;
 };
diff --git a/SpiceXPI/src/plugin/plugin.cpp b/SpiceXPI/src/plugin/plugin.cpp
index 58ec875..b1ba532 100644
--- a/SpiceXPI/src/plugin/plugin.cpp
+++ b/SpiceXPI/src/plugin/plugin.cpp
@@ -66,7 +66,7 @@ extern "C" {
 #include <fstream>
 #include <set>
 
-#include "controller.h"
+#include "controller-unix.h"
 #include "plugin.h"
 #include "nsScriptablePeer.h"
 
@@ -172,7 +172,6 @@ void NS_DestroyPluginInstance(nsPluginInstanceBase *aPlugin)
 nsPluginInstance::nsPluginInstance(NPP aInstance):
     nsPluginInstanceBase(),
     m_connected_status(-2),
-    m_external_controller(this),
     m_instance(aInstance),
     m_initialized(true),
     m_window(NULL),
@@ -187,6 +186,8 @@ nsPluginInstance::nsPluginInstance(NPP aInstance):
 #if !GLIB_CHECK_VERSION(2, 35, 0)
     g_type_init();
 #endif
+
+    m_external_controller = new SpiceControllerUnix(this);
 }
 
 nsPluginInstance::~nsPluginInstance()
@@ -197,6 +198,7 @@ nsPluginInstance::~nsPluginInstance()
     // and zero its m_plugin member
     if (m_scriptable_peer)
         NPN_ReleaseObject(m_scriptable_peer);
+    delete(m_external_controller);
 }
 
 NPBool nsPluginInstance::init(NPWindow *aWindow)
@@ -222,7 +224,7 @@ NPBool nsPluginInstance::init(NPWindow *aWindow)
     m_color_depth.clear();
     m_disable_effects.clear();
     m_proxy.clear();
-    m_external_controller.SetProxy(std::string());
+    m_external_controller->SetProxy(std::string());
 
     m_fullscreen = false;
     m_smartcard = false;
@@ -527,12 +529,12 @@ char *nsPluginInstance::GetProxy() const
 void nsPluginInstance::SetProxy(const char *aProxy)
 {
     m_proxy = aProxy;
-    m_external_controller.SetProxy(m_proxy);
+    m_external_controller->SetProxy(m_proxy);
 }
 
 void nsPluginInstance::WriteToPipe(const void *data, uint32_t size)
 {
-    m_external_controller.Write(data, size);
+    m_external_controller->Write(data, size);
 }
 
 void nsPluginInstance::SendInit()
@@ -629,12 +631,12 @@ void nsPluginInstance::Connect()
         return;
     }
 
-    if (!m_external_controller.StartClient()) {
+    if (!m_external_controller->StartClient()) {
         g_critical("failed to start SPICE client");
         return;
     }
 
-    if (m_external_controller.Connect(10) != 0)
+    if (m_external_controller->Connect(10) != 0)
     {
         g_critical("could not connect to spice client controller");
         return;
@@ -682,7 +684,7 @@ void nsPluginInstance::Show()
 
 void nsPluginInstance::Disconnect()
 {
-    m_external_controller.StopClient();
+    m_external_controller->StopClient();
 }
 
 void nsPluginInstance::ConnectedStatus(int32_t *retval)
@@ -756,11 +758,11 @@ void nsPluginInstance::CallOnDisconnected(int code)
 
 void nsPluginInstance::OnSpiceClientExit(int exit_code)
 {
-    m_connected_status = m_external_controller.TranslateRC(exit_code);
+    m_connected_status = m_external_controller->TranslateRC(exit_code);
     if (!getenv("SPICE_XPI_DEBUG"))
     {
         CallOnDisconnected(exit_code);
-        m_external_controller.Disconnect();
+        m_external_controller->Disconnect();
     }
 
     RemoveTrustStoreFile();
diff --git a/SpiceXPI/src/plugin/plugin.h b/SpiceXPI/src/plugin/plugin.h
index 5e7f079..7884dc7 100644
--- a/SpiceXPI/src/plugin/plugin.h
+++ b/SpiceXPI/src/plugin/plugin.h
@@ -190,7 +190,7 @@ private:
     bool RemoveTrustStoreFile();
 
     int32_t m_connected_status;
-    SpiceController m_external_controller;
+    SpiceController *m_external_controller;
 
     NPP m_instance;
     NPBool m_initialized;
-- 
1.8.1.4



More information about the Spice-devel mailing list