[libvirt] [PATCH 01/29] vbox: Begin to rewrite, vboxConnectOpen

Taowei uaedante at gmail.com
Fri Jul 18 07:46:43 UTC 2014


Introduce vbox_uniformed_api to deal with
version conflicts.

vboxConnectOpen has been rewritten.
---
 po/POTFILES.in                |    1 +
 src/Makefile.am               |    4 +-
 src/vbox/vbox_common.c        |  289 ++++++++++++++++++++++++++++++++
 src/vbox/vbox_common.h        |  132 +++++++++++++++
 src/vbox/vbox_driver.c        |   23 ++-
 src/vbox/vbox_tmpl.c          |  364 ++++++++++++++---------------------------
 src/vbox/vbox_uniformed_api.h |  152 +++++++++++++++++
 7 files changed, 717 insertions(+), 248 deletions(-)
 create mode 100644 src/vbox/vbox_common.c
 create mode 100644 src/vbox/vbox_common.h
 create mode 100644 src/vbox/vbox_uniformed_api.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 64a987e..93b7e2b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -215,6 +215,7 @@ src/util/virxml.c
 src/vbox/vbox_MSCOMGlue.c
 src/vbox/vbox_XPCOMCGlue.c
 src/vbox/vbox_driver.c
+src/vbox/vbox_common.c
 src/vbox/vbox_snapshot_conf.c
 src/vbox/vbox_tmpl.c
 src/vmware/vmware_conf.c
diff --git a/src/Makefile.am b/src/Makefile.am
index e2f76a7..1d66492 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -674,7 +674,9 @@ VBOX_DRIVER_SOURCES =						\
 	vbox/vbox_V4_2.c vbox/vbox_CAPI_v4_2.h			\
 	vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h			\
 	vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h			\
-	vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h
+	vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h              \
+	vbox/vbox_common.c vbox/vbox_common.h                   \
+	vbox/vbox_uniformed_api.h
 
 VBOX_DRIVER_EXTRA_DIST =					\
 		vbox/vbox_tmpl.c vbox/README			\
diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
new file mode 100644
index 0000000..8fb4494
--- /dev/null
+++ b/src/vbox/vbox_common.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2014, Taowei Luo (uaedante at gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "virlog.h"
+#include "viralloc.h"
+#include "nodeinfo.h"
+
+#include "vbox_common.h"
+#include "vbox_uniformed_api.h"
+
+/* Common codes for vbox driver. With the definitions in vbox_common.h,
+ * it treats vbox structs as a void*. Though vboxUniformedAPI
+ * it call vbox functions. This file is a high level implement about
+ * the vbox driver.
+ */
+
+#define VIR_FROM_THIS VIR_FROM_VBOX
+
+VIR_LOG_INIT("vbox.vbox_common");
+
+#define VBOX_UTF16_FREE(arg)                                            \
+    do {                                                                \
+        if (arg) {                                                      \
+            gVBoxAPI.UPFN.Utf16Free(data->pFuncs, arg);                 \
+            (arg) = NULL;                                               \
+        }                                                               \
+    } while (0)
+
+#define VBOX_UTF8_FREE(arg)                                             \
+    do {                                                                \
+        if (arg) {                                                      \
+            gVBoxAPI.UPFN.Utf8Free(data->pFuncs, arg);                  \
+            (arg) = NULL;                                               \
+        }                                                               \
+    } while (0)
+
+#define VBOX_COM_UNALLOC_MEM(arg)                                       \
+    do {                                                                \
+        if (arg) {                                                      \
+            gVBoxAPI.UPFN.ComUnallocMem(data->pFuncs, arg);             \
+            (arg) = NULL;                                               \
+        }                                                               \
+    } while (0)
+
+#define VBOX_UTF16_TO_UTF8(arg1, arg2)  gVBoxAPI.UPFN.Utf16ToUtf8(data->pFuncs, arg1, arg2)
+#define VBOX_UTF8_TO_UTF16(arg1, arg2)  gVBoxAPI.UPFN.Utf8ToUtf16(data->pFuncs, arg1, arg2)
+
+/* global vbox API, used for all common codes. */
+static vboxUniformedAPI gVBoxAPI;
+
+void vboxRegisterUniformedAPI(uint32_t uVersion)
+{
+    /* Install gVBoxAPI according to the vbox API version.
+     * This function don't check the validation of the
+     * uVersion, it assumes the vboxRegister will do this
+     * job.
+     */
+    if (uVersion >= 2001052 && uVersion < 2002051) {
+        vbox22InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 2002051 && uVersion < 3000051) {
+        vbox30InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 3000051 && uVersion < 3001051) {
+        vbox31InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 3001051 && uVersion < 3002051) {
+        vbox32InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 3002051 && uVersion < 4000051) {
+        vbox40InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 4000051 && uVersion < 4001051) {
+        vbox41InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 4001051 && uVersion < 4002020) {
+        vbox42InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 4002020 && uVersion < 4002051) {
+        vbox42_20InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 4002051 && uVersion < 4003004) {
+        vbox43InstallUniformedAPI(&gVBoxAPI);
+    } else if (uVersion >= 4003004 && uVersion < 4003051) {
+        vbox43_4InstallUniformedAPI(&gVBoxAPI);
+    }
+}
+
+static virDomainDefParserConfig vboxDomainDefParserConfig = {
+    .macPrefix = { 0x08, 0x00, 0x27 },
+};
+
+static virDomainXMLOptionPtr
+vboxXMLConfInit(void)
+{
+    return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
+                                 NULL, NULL);
+}
+
+static int vboxInitialize(vboxGlobalData *data)
+{
+    if (gVBoxAPI.UPFN.Initialize(data) != 0)
+        goto cleanup;
+
+    if (gVBoxAPI.fWatchNeedInitialize && gVBoxAPI.initializeFWatch(data) != 0)
+        goto cleanup;
+
+    if (data->vboxObj == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("IVirtualBox object is null"));
+        goto cleanup;
+    }
+
+    if (data->vboxSession == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("ISession object is null"));
+        goto cleanup;
+    }
+
+    return 0;
+
+ cleanup:
+    return -1;
+}
+
+static virCapsPtr vboxCapsInit(void)
+{
+    virCapsPtr caps;
+    virCapsGuestPtr guest;
+
+    if ((caps = virCapabilitiesNew(virArchFromHost(),
+                                   0, 0)) == NULL)
+        goto no_memory;
+
+    if (nodeCapsInitNUMA(caps) < 0)
+        goto no_memory;
+
+    if ((guest = virCapabilitiesAddGuest(caps,
+                                         "hvm",
+                                         caps->host.arch,
+                                         NULL,
+                                         NULL,
+                                         0,
+                                         NULL)) == NULL)
+        goto no_memory;
+
+    if (virCapabilitiesAddGuestDomain(guest,
+                                      "vbox",
+                                      NULL,
+                                      NULL,
+                                      0,
+                                      NULL) == NULL)
+        goto no_memory;
+
+    return caps;
+
+ no_memory:
+    virObjectUnref(caps);
+    return NULL;
+}
+
+static int vboxExtractVersion(vboxGlobalData *data)
+{
+    int ret = -1;
+    PRUnichar *versionUtf16 = NULL;
+    char *vboxVersion = NULL;
+    nsresult rc;
+
+    if (data->version > 0)
+        return 0;
+
+    rc = gVBoxAPI.UIVirtualBox.GetVersion(data->vboxObj, &versionUtf16);
+    if (NS_FAILED(rc))
+        goto failed;
+
+    VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
+
+    if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
+        ret = 0;
+
+    VBOX_UTF8_FREE(vboxVersion);
+    VBOX_COM_UNALLOC_MEM(versionUtf16);
+ failed:
+    if (ret != 0)
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not extract VirtualBox version"));
+
+    return ret;
+}
+
+static void vboxUninitialize(vboxGlobalData *data)
+{
+    if (!data)
+        return;
+
+    gVBoxAPI.UPFN.Uninitialize(data);
+
+    virObjectUnref(data->caps);
+    virObjectUnref(data->xmlopt);
+    if (gVBoxAPI.domainEventCallbacks)
+        virObjectEventStateFree(data->domainEvents);
+    VIR_FREE(data);
+}
+
+virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
+                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                                 unsigned int flags)
+{
+    vboxGlobalData *data = NULL;
+    uid_t uid = geteuid();
+
+    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+    if (conn->uri == NULL &&
+        !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
+        return VIR_DRV_OPEN_ERROR;
+
+    if (conn->uri->scheme == NULL ||
+        STRNEQ(conn->uri->scheme, "vbox"))
+        return VIR_DRV_OPEN_DECLINED;
+
+    /* Leave for remote driver */
+    if (conn->uri->server != NULL)
+        return VIR_DRV_OPEN_DECLINED;
+
+    if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("no VirtualBox driver path specified (try vbox:///session)"));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    if (uid != 0) {
+        if (STRNEQ(conn->uri->path, "/session")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
+            return VIR_DRV_OPEN_ERROR;
+        }
+    } else { /* root */
+        if (STRNEQ(conn->uri->path, "/system") &&
+            STRNEQ(conn->uri->path, "/session")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
+            return VIR_DRV_OPEN_ERROR;
+        }
+    }
+
+    if (VIR_ALLOC(data) < 0)
+        return VIR_DRV_OPEN_ERROR;
+
+    if (!(data->caps = vboxCapsInit()) ||
+        vboxInitialize(data) < 0 ||
+        vboxExtractVersion(data) < 0 ||
+        !(data->xmlopt = vboxXMLConfInit())) {
+        vboxUninitialize(data);
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    if (gVBoxAPI.domainEventCallbacks) {
+        if (!(data->domainEvents = virObjectEventStateNew())) {
+            vboxUninitialize(data);
+            return VIR_DRV_OPEN_ERROR;
+        }
+
+        data->conn = conn;
+        /* Introduce registerGlobalData to register
+         * g_pVBoxGlobalData in vbox_tmpl.c */
+        gVBoxAPI.registerGlobalData(data);
+    }
+
+    conn->privateData = data;
+    VIR_DEBUG("in vboxOpen");
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h
new file mode 100644
index 0000000..000f4ca
--- /dev/null
+++ b/src/vbox/vbox_common.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014, Taowei Luo (uaedante at gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VBOX_COMMON_H
+# define VBOX_COMMON_H
+
+# ifdef ___VirtualBox_CXPCOM_h
+#  error this file should not be included after vbox_CAPI_v*.h
+# endif
+
+# include "internal.h"
+# include <stddef.h>
+# include "wchar.h"
+
+/* This file extracts some symbols defined in
+ * vbox_CAPI_v*.h. It tells the vbox_common.c
+ * how to treat with this symbols. This file
+ * can't be included with files such as
+ * vbox_CAPI_v*.h, or it would casue multiple
+ * definitions.
+ *
+ * You can see the more informations in vbox_api.h
+ */
+
+/* Copied definitions from vbox_CAPI_*.h.
+ * We must MAKE SURE these codes are compatible. */
+
+typedef unsigned char PRUint8;
+# if (defined(HPUX) && defined(__cplusplus) \
+     && !defined(__GNUC__) && __cplusplus < 199707L) \
+    || (defined(SCO) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus == 1L)
+typedef char PRInt8;
+# else
+typedef signed char PRInt8;
+# endif
+
+# define PR_INT8_MAX 127
+# define PR_INT8_MIN (-128)
+# define PR_UINT8_MAX 255U
+
+typedef unsigned short PRUint16;
+typedef short PRInt16;
+
+# define PR_INT16_MAX 32767
+# define PR_INT16_MIN (-32768)
+# define PR_UINT16_MAX 65535U
+
+typedef unsigned int PRUint32;
+typedef int PRInt32;
+# define PR_INT32(x)  x
+# define PR_UINT32(x) x ## U
+
+# define PR_INT32_MAX PR_INT32(2147483647)
+# define PR_INT32_MIN (-PR_INT32_MAX - 1)
+# define PR_UINT32_MAX PR_UINT32(4294967295)
+
+typedef long PRInt64;
+typedef unsigned long PRUint64;
+typedef int PRIntn;
+typedef unsigned int PRUintn;
+
+typedef double          PRFloat64;
+typedef size_t PRSize;
+
+typedef ptrdiff_t PRPtrdiff;
+
+typedef unsigned long PRUptrdiff;
+
+typedef PRIntn PRBool;
+
+# define PR_TRUE 1
+# define PR_FALSE 0
+
+typedef PRUint8 PRPackedBool;
+
+/*
+** Status code used by some routines that have a single point of failure or
+** special status return.
+*/
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+# ifndef __PRUNICHAR__
+#  define __PRUNICHAR__
+#  if defined(WIN32) || defined(XP_MAC)
+typedef wchar_t PRUnichar;
+#  else
+typedef PRUint16 PRUnichar;
+#  endif
+# endif
+
+typedef long PRWord;
+typedef unsigned long PRUword;
+
+# define nsnull 0
+typedef PRUint32 nsresult;
+
+# if defined(__GNUC__) && (__GNUC__ > 2)
+#  define NS_LIKELY(x)    (__builtin_expect((x), 1))
+#  define NS_UNLIKELY(x)  (__builtin_expect((x), 0))
+# else
+#  define NS_LIKELY(x)    (x)
+#  define NS_UNLIKELY(x)  (x)
+# endif
+
+# define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000))
+# define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000)))
+
+/* Simplied definitions in vbox_CAPI_*.h */
+
+typedef void const *PCVBOXXPCOM;
+typedef void IVirtualBox;
+typedef void ISession;
+typedef void IVirtualBoxCallback;
+typedef void nsIEventQueue;
+
+#endif /* VBOX_COMMON_H */
diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c
index 7d004b2..ad36173 100644
--- a/src/vbox/vbox_driver.c
+++ b/src/vbox/vbox_driver.c
@@ -39,6 +39,10 @@
 #include "vbox_glue.h"
 #include "virerror.h"
 #include "virutil.h"
+#include "domain_event.h"
+#include "domain_conf.h"
+
+#include "vbox_uniformed_api.h"
 
 #define VIR_FROM_THIS VIR_FROM_VBOX
 
@@ -161,6 +165,17 @@ int vboxRegister(void)
         } else {
             VIR_DEBUG("Unsupported VirtualBox API version: %u", uVersion);
         }
+        /* Register vboxUniformedAPI. The dummy driver will not
+         * use vboxAPI, so the register step is only for validate
+         * vbox API versions.
+         * When the vbox driver is fully redesigned, and there is no
+         * vbox**Driver or vbox**NetworkDriver or vbox**StorageDriver any
+         * more, the registerAPI function will handle all jobs in this
+         * vboxRegister (eg. API version check, return a dummy driver
+         * for unsupported version).
+         * But the current design is a solution for compatibility.
+         */
+        vboxRegisterUniformedAPI(uVersion);
     } else {
         VIR_DEBUG("VBoxCGlueInit failed, using dummy driver");
     }
@@ -175,9 +190,9 @@ int vboxRegister(void)
     return 0;
 }
 
-static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
-                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
-                                        unsigned int flags)
+static virDrvOpenStatus dummyConnectOpen(virConnectPtr conn,
+                                         virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                                         unsigned int flags)
 {
     uid_t uid = geteuid();
 
@@ -218,5 +233,5 @@ static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
 static virDriver vboxDriverDummy = {
     VIR_DRV_VBOX,
     "VBOX",
-    .connectOpen = vboxConnectOpen,
+    .connectOpen = dummyConnectOpen,
 };
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 3825083..cc1733b 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -89,7 +89,7 @@
 
 /* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
 #include "vbox_glue.h"
-
+#include "vbox_uniformed_api.h"
 
 #define VIR_FROM_THIS                   VIR_FROM_VBOX
 
@@ -203,41 +203,7 @@ if (strUtf16) {\
           (unsigned)(iid)->m3[7]);\
 }\
 
-typedef struct {
-    virMutex lock;
-    unsigned long version;
-
-    virCapsPtr caps;
-    virDomainXMLOptionPtr xmlopt;
-
-    IVirtualBox *vboxObj;
-    ISession *vboxSession;
-
-    /** Our version specific API table pointer. */
-    PCVBOXXPCOM pFuncs;
-
-#if VBOX_API_VERSION == 2002000
-
-} vboxGlobalData;
-
-#else /* !(VBOX_API_VERSION == 2002000) */
-
-    /* Async event handling */
-    virObjectEventStatePtr domainEvents;
-    int fdWatch;
-
-# if VBOX_API_VERSION <= 3002000
-    /* IVirtualBoxCallback is used in VirtualBox 3.x only */
-    IVirtualBoxCallback *vboxCallback;
-# endif /* VBOX_API_VERSION <= 3002000 */
-
-    nsIEventQueue  *vboxQueue;
-    int volatile vboxCallBackRefCount;
-
-    /* pointer back to the connection */
-    virConnectPtr conn;
-
-} vboxGlobalData;
+#if VBOX_API_VERSION > 2002000
 
 /* g_pVBoxGlobalData has to be global variable,
  * there is no other way to make the callbacks
@@ -865,137 +831,6 @@ vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16,
     return result;
 }
 
-
-static virDomainDefParserConfig vboxDomainDefParserConfig = {
-    .macPrefix = { 0x08, 0x00, 0x27 },
-};
-
-
-static virDomainXMLOptionPtr
-vboxXMLConfInit(void)
-{
-    return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
-                                 NULL, NULL);
-}
-
-
-static virCapsPtr vboxCapsInit(void)
-{
-    virCapsPtr caps;
-    virCapsGuestPtr guest;
-
-    if ((caps = virCapabilitiesNew(virArchFromHost(),
-                                   0, 0)) == NULL)
-        goto no_memory;
-
-    if (nodeCapsInitNUMA(caps) < 0)
-        goto no_memory;
-
-    if ((guest = virCapabilitiesAddGuest(caps,
-                                         "hvm",
-                                         caps->host.arch,
-                                         NULL,
-                                         NULL,
-                                         0,
-                                         NULL)) == NULL)
-        goto no_memory;
-
-    if (virCapabilitiesAddGuestDomain(guest,
-                                      "vbox",
-                                      NULL,
-                                      NULL,
-                                      0,
-                                      NULL) == NULL)
-        goto no_memory;
-
-    return caps;
-
- no_memory:
-    virObjectUnref(caps);
-    return NULL;
-}
-
-static int
-vboxInitialize(vboxGlobalData *data)
-{
-    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
-
-    if (data->pFuncs == NULL)
-        goto cleanup;
-
-#if VBOX_XPCOMC_VERSION == 0x00010000U
-    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
-#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
-    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
-                               ISESSION_IID_STR, &data->vboxSession);
-
-# if VBOX_API_VERSION == 2002000
-
-    /* No event queue functionality in 2.2.* as of now */
-
-# else  /* !(VBOX_API_VERSION == 2002000) */
-
-    /* Initial the fWatch needed for Event Callbacks */
-    data->fdWatch = -1;
-
-    data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
-
-    if (data->vboxQueue == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("nsIEventQueue object is null"));
-        goto cleanup;
-    }
-
-# endif /* !(VBOX_API_VERSION == 2002000) */
-#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
-
-    if (data->vboxObj == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("IVirtualBox object is null"));
-        goto cleanup;
-    }
-
-    if (data->vboxSession == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("ISession object is null"));
-        goto cleanup;
-    }
-
-    return 0;
-
- cleanup:
-    return -1;
-}
-
-static int vboxExtractVersion(vboxGlobalData *data)
-{
-    int ret = -1;
-    PRUnichar *versionUtf16 = NULL;
-    nsresult rc;
-
-    if (data->version > 0)
-        return 0;
-
-    rc = data->vboxObj->vtbl->GetVersion(data->vboxObj, &versionUtf16);
-    if (NS_SUCCEEDED(rc)) {
-        char *vboxVersion = NULL;
-
-        VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
-
-        if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
-            ret = 0;
-
-        VBOX_UTF8_FREE(vboxVersion);
-        VBOX_COM_UNALLOC_MEM(versionUtf16);
-    }
-
-    if (ret != 0)
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Could not extract VirtualBox version"));
-
-    return ret;
-}
-
 static void vboxUninitialize(vboxGlobalData *data)
 {
     if (!data)
@@ -1014,82 +849,6 @@ static void vboxUninitialize(vboxGlobalData *data)
     VIR_FREE(data);
 }
 
-
-static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
-                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
-                                        unsigned int flags)
-{
-    vboxGlobalData *data = NULL;
-    uid_t uid = geteuid();
-
-    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
-
-    if (conn->uri == NULL &&
-        !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
-        return VIR_DRV_OPEN_ERROR;
-
-    if (conn->uri->scheme == NULL ||
-        STRNEQ(conn->uri->scheme, "vbox"))
-        return VIR_DRV_OPEN_DECLINED;
-
-    /* Leave for remote driver */
-    if (conn->uri->server != NULL)
-        return VIR_DRV_OPEN_DECLINED;
-
-    if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("no VirtualBox driver path specified (try vbox:///session)"));
-        return VIR_DRV_OPEN_ERROR;
-    }
-
-    if (uid != 0) {
-        if (STRNEQ(conn->uri->path, "/session")) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
-            return VIR_DRV_OPEN_ERROR;
-        }
-    } else { /* root */
-        if (STRNEQ(conn->uri->path, "/system") &&
-            STRNEQ(conn->uri->path, "/session")) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
-            return VIR_DRV_OPEN_ERROR;
-        }
-    }
-
-    if (VIR_ALLOC(data) < 0)
-        return VIR_DRV_OPEN_ERROR;
-
-    if (!(data->caps = vboxCapsInit()) ||
-        vboxInitialize(data) < 0 ||
-        vboxExtractVersion(data) < 0 ||
-        !(data->xmlopt = vboxXMLConfInit())) {
-        vboxUninitialize(data);
-        return VIR_DRV_OPEN_ERROR;
-    }
-
-#if VBOX_API_VERSION == 2002000
-
-    /* No domainEventCallbacks in 2.2.* version */
-
-#else  /* !(VBOX_API_VERSION == 2002000) */
-
-    if (!(data->domainEvents = virObjectEventStateNew())) {
-        vboxUninitialize(data);
-        return VIR_DRV_OPEN_ERROR;
-    }
-
-    data->conn = conn;
-    g_pVBoxGlobalData = data;
-
-#endif /* !(VBOX_API_VERSION == 2002000) */
-
-    conn->privateData = data;
-    VIR_DEBUG("in vboxOpen");
-
-    return VIR_DRV_OPEN_SUCCESS;
-}
-
 static int vboxConnectClose(virConnectPtr conn)
 {
     vboxGlobalData *data = conn->privateData;
@@ -11497,6 +11256,125 @@ vboxNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
     return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
 }
 
+/* Begin of vboxUniformedAPI */
+
+static int _pfnInitialize(vboxGlobalData *data)
+{
+    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
+    if (data->pFuncs == NULL)
+        return -1;
+#if VBOX_XPCOMC_VERSION == 0x00010000U
+    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
+#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
+    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, ISESSION_IID_STR, &data->vboxSession);
+#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
+    return 0;
+}
+
+static int
+_initializeFWatch(vboxGlobalData *data ATTRIBUTE_UNUSED)
+{
+#if (VBOX_XPCOMC_VERSION == 0x00010000U) || (VBOX_API_VERSION == 2002000)
+    /* No event queue functionality in 2.2.* as of now */
+    VIR_WARN("There is no fWatch initical in current version");
+#else /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */
+    /* Initialize the fWatch needed for Event Callbacks */
+    data->fdWatch = -1;
+    data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
+    if (data->vboxQueue == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("nsIEventQueue object is null"));
+        return -1;
+    }
+#endif /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */
+    return 0;
+}
+
+static
+void _registerGlobalData(vboxGlobalData *data ATTRIBUTE_UNUSED)
+{
+#if VBOX_API_VERSION == 2002000
+    VIR_WARN("No g_pVBoxGlobalData in current version");
+#else /* VBOX_API_VERSION != 2002000 */
+    g_pVBoxGlobalData = data;
+#endif /* VBOX_API_VERSION != 2002000 */
+}
+
+static void _pfnUninitialize(vboxGlobalData *data)
+{
+    if (data->pFuncs)
+        data->pFuncs->pfnComUninitialize();
+}
+
+static void _pfnComUnallocMem(PCVBOXXPCOM pFuncs, void *pv)
+{
+    pFuncs->pfnComUnallocMem(pv);
+}
+
+static void _pfnUtf16Free(PCVBOXXPCOM pFuncs, PRUnichar *pwszString)
+{
+    pFuncs->pfnUtf16Free(pwszString);
+}
+
+static void _pfnUtf8Free(PCVBOXXPCOM pFuncs, char *pszString)
+{
+    pFuncs->pfnUtf8Free(pszString);
+}
+
+static int _pfnUtf16ToUtf8(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString)
+{
+    return pFuncs->pfnUtf16ToUtf8(pwszString, ppszString);
+}
+
+static int _pfnUtf8ToUtf16(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString)
+{
+    return pFuncs->pfnUtf8ToUtf16(pszString, ppwszString);
+}
+
+static nsresult
+_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
+{
+    return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
+}
+
+static vboxUniformedPFN _UPFN = {
+    .Initialize = _pfnInitialize,
+    .Uninitialize = _pfnUninitialize,
+    .ComUnallocMem = _pfnComUnallocMem,
+    .Utf16Free = _pfnUtf16Free,
+    .Utf8Free = _pfnUtf8Free,
+    .Utf16ToUtf8 = _pfnUtf16ToUtf8,
+    .Utf8ToUtf16 = _pfnUtf8ToUtf16,
+};
+
+static vboxUniformedIVirtualBox _UIVirtualBox = {
+    .GetVersion = _virtualboxGetVersion,
+};
+
+void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
+{
+    pVBoxAPI->APIVersion = VBOX_API_VERSION;
+    pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION;
+    pVBoxAPI->initializeFWatch = _initializeFWatch;
+    pVBoxAPI->registerGlobalData = _registerGlobalData;
+    pVBoxAPI->UPFN = _UPFN;
+    pVBoxAPI->UIVirtualBox = _UIVirtualBox;
+#if (VBOX_XPCOMC_VERSION == 0x00010000U) || (VBOX_API_VERSION == 2002000)
+    /* No event queue functionality in 2.2.* as of now */
+    pVBoxAPI->fWatchNeedInitialize = 0;
+#else /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */
+    pVBoxAPI->fWatchNeedInitialize = 1;
+#endif /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */
+
+#if VBOX_API_VERSION == 2002000
+    pVBoxAPI->domainEventCallbacks = 0;
+#else  /* !(VBOX_API_VERSION == 2002000) */
+    pVBoxAPI->domainEventCallbacks = 1;
+#endif /* !(VBOX_API_VERSION == 2002000) */
+
+}
+
+/* End of vboxUniformedAPI and Begin of common codes */
 
 /**
  * Function Tables
diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h
new file mode 100644
index 0000000..fa753d4
--- /dev/null
+++ b/src/vbox/vbox_uniformed_api.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2014, Taowei Luo (uaedante at gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VBOX_UNIFORMED_API_H
+# define VBOX_UNIFORMED_API_H
+
+# include "internal.h"
+
+/* This file may be used in three place. That is vbox_tmpl.c,
+ * vbox_common.c and vbox_driver.c. The vboxUniformedAPI and some
+ * types used for vboxUniformedAPI is defined here.
+ *
+ * The vbox_tmpl.c is the only place where the driver knows the inside
+ * architecture of those vbox structs(vboxObj, vboxSession,
+ * pFuncs, vboxCallback and vboxQueue). The file should be included
+ * after the currect vbox_CAPI_v*.h, then we can use the vbox structs
+ * in vboxGlobalData. The vbox_tmpl.c should implement functions
+ * defined in vboxUniformedAPI.
+ *
+ * In vbox_driver.c, it is used to define the struct vboxUniformedAPI.
+ * The vbox_driver.c collects vboxUniformedAPI for all versions.
+ * Then vboxRegister calls the vboxRegisterUniformedAPI to register.
+ * Note: In vbox_driver.c, the vbox structs in vboxGlobalData is
+ * defined by vbox_CAPI_v2.2.h.
+ *
+ * The vbox_common.c, it is used to generate common codes for all vbox
+ * versions. Bacause the same member varible's offset in a vbox struct
+ * may change between different vbox versions. The vbox_common.c
+ * shouldn't directly use struct's member varibles defined in
+ * vbox_CAPI_v*.h. To make things safety, we include the
+ * vbox_common.h in vbox_common.c. In this case, we treat structs
+ * defined by vbox as a void*. The common codes don't concern about
+ * the inside of this structs(actually, we can't, in the common level).
+ * With the help of vboxUniformed API, we call VirtualBox's API and
+ * implement the vbox driver in a high level.
+ *
+ * In conclusion:
+ *  * In vbox_tmpl.c, this file is included after vbox_CAPI_v*.h
+ *  * In vbox_driver.c, this file is included after vbox_glue.h
+ *  * In vbox_common.c, this file is included after vbox_common.h
+ *
+ */
+
+typedef struct {
+    virMutex lock;
+    unsigned long version;
+
+    virCapsPtr caps;
+    virDomainXMLOptionPtr xmlopt;
+
+    IVirtualBox *vboxObj;
+    ISession *vboxSession;
+
+    /** Our version specific API table pointer. */
+    PCVBOXXPCOM pFuncs;
+
+    /* The next is used when VBOX_API_VERSION > 2002000 */
+    /* Async event handling */
+    virObjectEventStatePtr domainEvents;
+    int fdWatch;
+# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 && VBOX_API_VERSION <= 3002000
+    /* IVirtualBoxCallback is used in VirtualBox 3.x only */
+    IVirtualBoxCallback *vboxCallback;
+# else /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */
+    void *vboxCallback;
+# endif /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */
+
+
+# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000
+    nsIEventQueue  *vboxQueue;
+# else /* VBOX_API_VERSION == 2002000 or undefined */
+    void *vboxQueue;
+# endif /* VBOX_API_VERSION == 2002000 or undefined */
+    int volatile vboxCallBackRefCount;
+
+    /* pointer back to the connection */
+    virConnectPtr conn;
+
+} vboxGlobalData;
+
+/* vboxUniformedAPI gives vbox_common.c a uniformed layer to see
+ * vbox API.
+ */
+
+/* Functions for pFuncs */
+typedef struct {
+    int (*Initialize)(vboxGlobalData *data);
+    void (*Uninitialize)(vboxGlobalData *data);
+    void (*ComUnallocMem)(PCVBOXXPCOM pFuncs, void *pv);
+    void (*Utf16Free)(PCVBOXXPCOM pFuncs, PRUnichar *pwszString);
+    void (*Utf8Free)(PCVBOXXPCOM pFuncs, char *pszString);
+    int (*Utf16ToUtf8)(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString);
+    int (*Utf8ToUtf16)(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString);
+} vboxUniformedPFN;
+
+/* Functions for IVirtualBox */
+typedef struct {
+    nsresult (*GetVersion)(IVirtualBox *vboxObj, PRUnichar **versionUtf16);
+} vboxUniformedIVirtualBox;
+
+typedef struct {
+    /* vbox API version */
+    uint32_t APIVersion;
+    uint32_t XPCOMCVersion;
+    /* vbox APIs */
+    int (*initializeFWatch)(vboxGlobalData *data);
+    void (*registerGlobalData)(vboxGlobalData *data);
+    vboxUniformedPFN UPFN;
+    vboxUniformedIVirtualBox UIVirtualBox;
+    /* vbox API features */
+    bool fWatchNeedInitialize;
+    bool domainEventCallbacks;
+} vboxUniformedAPI;
+
+/* libvirt API
+ * These API would be removed after we generate the
+ * vboxDriver in common code.
+ */
+virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
+                                 virConnectAuthPtr auth,
+                                 unsigned int flags);
+
+/* Version specified functions for installing uniformed API */
+void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox30InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox31InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox32InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox40InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox41InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox42InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox42_20InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox43InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+void vbox43_4InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
+
+void vboxRegisterUniformedAPI(uint32_t uVersion);
+
+#endif /* VBOX_UNIFORMED_API_H */
-- 
1.7.9.5




More information about the libvir-list mailing list