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(a)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(a)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(a)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