[Spice-devel] spice-xpi now calls JS OnDisconnected

Submitted by Peter Hatina on Aug. 25, 2011, 4:51 p.m.

Details

Message ID 4E561B12.4000407@redhat.com
State New, archived
Headers show

Not browsing as part of any series.

Commit Message

Peter Hatina Aug. 25, 2011, 4:51 p.m.
Hello guys,

I did some changes in spice-xpi. Now the plugin is capable to call
JavaScript function "OnDisconnected(ErrCode)" which makes our User
Portal more natural in behavior. When spicec quit, the User Portal gets
notified by calling OnDisconnected and can react synchronously, so in
future, there won't be necessary to poll every 2 sec. to check spicec
status.

Patch hide | download patch | download mbox

From 30f5a4d57ceabdafde3ff1331662e8163d173e65 Mon Sep 17 00:00:00 2001
From: Peter Hatina <phatina@redhat.com>
Date: Thu, 25 Aug 2011 11:43:37 +0200
Subject: [PATCH] call JS OnDisconnected, when spicec quits

---
 SpiceXPI/src/plugin/plugin.cpp |  101 ++++++++++++++++++++++++++++++++--------
 SpiceXPI/src/plugin/plugin.h   |   10 +++-
 configure.ac                   |    2 +-
 3 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/SpiceXPI/src/plugin/plugin.cpp b/SpiceXPI/src/plugin/plugin.cpp
index 793f2ba..82e81c2 100644
--- a/SpiceXPI/src/plugin/plugin.cpp
+++ b/SpiceXPI/src/plugin/plugin.cpp
@@ -50,7 +50,6 @@ 
 #include <stdlib.h>
 #include <dlfcn.h>
 #include <errno.h>
-#include <sys/types.h>
 #include <unistd.h>
 #include <string>
 #include <sstream>
@@ -190,6 +189,9 @@  void NS_DestroyPluginInstance(nsPluginInstanceBase *aPlugin)
 //
 // nsPluginInstance class implementation
 //
+
+std::map<pid_t, nsPluginInstance *> nsPluginInstance::s_children;
+
 nsPluginInstance::nsPluginInstance(NPP aInstance):
     nsPluginInstanceBase(),
     m_instance(aInstance),
@@ -218,6 +220,11 @@  nsPluginInstance::nsPluginInstance(NPP aInstance):
     }
 
     m_connected_status = -2;
+
+    struct sigaction chld;
+    chld.sa_sigaction = SigchldRoutine;
+    chld.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO;
+    sigaction(SIGCHLD, &chld, NULL);
 }
 
 nsPluginInstance::~nsPluginInstance()
@@ -560,9 +567,9 @@  void nsPluginInstance::Connect()
         return;
     }
 
-    m_child_pid = fork();
-    LOG_DEBUG(" m_child_pid = " << m_child_pid);
-    if (m_child_pid == 0)
+    pid_t child = fork();
+    LOG_DEBUG("child pid: " << child);
+    if (child == 0)
     {
         std::string spicec_path = getSpicecPath();
         if (spicec_path.empty())
@@ -654,9 +661,7 @@  void nsPluginInstance::Connect()
         // set connected status
         m_connected_status = -1;
 
-        // setup wait thread
-        pthread_t wait_thread_id;
-        pthread_create(&wait_thread_id, NULL, WaitThread, static_cast<void *>(this));
+        s_children[child] = this;
     }
 }
 
@@ -668,8 +673,15 @@  void nsPluginInstance::Show()
 
 void nsPluginInstance::Disconnect()
 {
-    if (m_child_pid != 0)
-        kill(m_child_pid, SIGTERM);
+    for (std::map<pid_t, nsPluginInstance *>::iterator it = s_children.begin();
+         it != s_children.end(); ++it)
+    {
+        if (it->second == this)
+        {
+            kill(it->first, SIGTERM);
+            break;
+        }
+    }
 }
 
 void nsPluginInstance::ConnectedStatus(PRInt32 *retval)
@@ -694,20 +706,69 @@  void nsPluginInstance::SetUsbFilter(const char *aUsbFilter)
     // when fixed in RHEVM
 }
 
-void *nsPluginInstance::WaitThread(void *opaque)
+void nsPluginInstance::CallOnDisconnected(int code)
 {
-    if (opaque == NULL)
-        return NULL;
+    NPObject *window = NULL;
+    if (NPN_GetValue(m_instance, NPNVWindowNPObject, &window) != NPERR_NO_ERROR)
+    {
+        LOG_ERROR("could not get browser window, when trying to call OnDisconnected");
+        return;
+    }
+
+    // get OnDisconnected callback
+    NPIdentifier id_on_disconnected = NPN_GetStringIdentifier("OnDisconnected");
+    if (!id_on_disconnected)
+    {
+        LOG_ERROR("could not find OnDisconnected identifier");
+        return;
+    }
+
+    NPVariant var_on_disconnected;
+    if (!NPN_GetProperty(m_instance, window, id_on_disconnected, &var_on_disconnected))
+    {
+        LOG_ERROR("could not get OnDisconnected function");
+        return;
+    }
+
+    if (!NPVARIANT_IS_OBJECT(var_on_disconnected))
+    {
+        LOG_ERROR("OnDisconnected is not object");
+        return;
+    }
+
+    NPObject *call_on_disconnected = NPVARIANT_TO_OBJECT(var_on_disconnected);
+
+    // call OnDisconnected
+    NPVariant arg;
+    NPVariant void_result;
+    INT32_TO_NPVARIANT(code, arg);
+    NPVariant args[] = { arg };
+
+    if (NPN_InvokeDefault(m_instance, call_on_disconnected, args, sizeof(args) / sizeof(args[0]), &void_result))
+    {
+        LOG_DEBUG("OnDisconnected successfuly called");
+    }
+    else
+    {
+        LOG_ERROR("could not call OnDisconnected");
+    }
+
+    // cleanup
+    NPN_ReleaseObject(window);
+    NPN_ReleaseVariantValue(&var_on_disconnected);
+}
+
+void nsPluginInstance::SigchldRoutine(int sig, siginfo_t *info, void *uap)
+{
+    LOG_DEBUG("child finished, pid: " << info->si_pid);
 
     int exit_code;
-    nsPluginInstance *fake_this = reinterpret_cast<nsPluginInstance *>(opaque);
-
-    waitpid(fake_this->m_child_pid, &exit_code, 0);
-    LOG_DEBUG("spicec exit code = " << exit_code);
-    fake_this->m_connected_status = fake_this->m_external_controller.TranslateRC(exit_code);
-    unlink(fake_this->m_trust_store_file.c_str());
-    fake_this->m_trust_store_file.clear();
-    return NULL;
+    waitpid(info->si_pid, &exit_code, 0);
+
+    nsPluginInstance *fake_this = s_children[info->si_pid];
+    fake_this->CallOnDisconnected(exit_code);
+    fake_this->m_external_controller.Disconnect();
+    s_children.erase(info->si_pid);
 }
 
 // ==============================
diff --git a/SpiceXPI/src/plugin/plugin.h b/SpiceXPI/src/plugin/plugin.h
index 28cb3db..e656ac7 100644
--- a/SpiceXPI/src/plugin/plugin.h
+++ b/SpiceXPI/src/plugin/plugin.h
@@ -50,6 +50,11 @@ 
 #include <npapi.h>
 #include <npruntime.h>
 
+extern "C" {
+#include <pthread.h>
+#include <signal.h>
+}
+
 #include "pluginbase.h"
 #include "controller.h"
 #include "common.h"
@@ -154,16 +159,17 @@  public:
     NPObject *GetScriptablePeer();
     
 private:
-    static void *WaitThread(void *opaque);
+    static void SigchldRoutine(int sig, siginfo_t *info, void *uap);
     void WriteToPipe(const void *data, uint32_t size);
     void SendInit();
     void SendMsg(uint32_t id);
     void SendValue(uint32_t id, uint32_t value);
     void SendStr(uint32_t id, const char *str);
     void SendWStr(uint32_t id, const wchar_t *str);
+    void CallOnDisconnected(int code);
   
 private:
-    pid_t m_child_pid;
+    static std::map<pid_t, nsPluginInstance *> s_children;
     PRInt32 m_connected_status;
     SpiceController m_external_controller;
 
diff --git a/configure.ac b/configure.ac
index 0b20ffc..f09c68d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@ 
 AC_PREREQ([2.57])
-AC_INIT(spice-xpi, [2.5.2pre], [], spice-xpi)
+AC_INIT(spice-xpi, [2.6], [], spice-xpi)
 
 AC_CONFIG_MACRO_DIR([m4])
 AM_CONFIG_HEADER([config.h])
-- 
1.7.6


Comments

Hi,

On 08/25/2011 11:51 AM, Peter Hatina wrote:
> Hello guys,
>
> I did some changes in spice-xpi. Now the plugin is capable to call
> JavaScript function "OnDisconnected(ErrCode)" which makes our User
> Portal more natural in behavior. When spicec quit, the User Portal gets
> notified by calling OnDisconnected and can react synchronously, so in
> future, there won't be necessary to poll every 2 sec. to check spicec
> status.

Looks good. Has the new functionality been tested? Including having
connections to 2 vms open at the same time and the on-disconnect
handler for the right one getting called?

Regards,

Hans