Introduce vbox_uniformed_api to deal with version conflicts. Use vbox_install_api to register the currect vboxUniformedAPI with vbox version. vboxConnectOpen has been rewritten. --- po/POTFILES.in | 1 + src/Makefile.am | 5 +- src/vbox/vbox_common.c | 291 +++++++++++++++++++++++++++++++++ src/vbox/vbox_common.h | 130 +++++++++++++++ src/vbox/vbox_driver.c | 14 +- src/vbox/vbox_install_api.h | 26 +++ src/vbox/vbox_tmpl.c | 363 ++++++++++++++--------------------------- src/vbox/vbox_uniformed_api.h | 153 +++++++++++++++++ 8 files changed, 735 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_install_api.h create mode 100644 src/vbox/vbox_uniformed_api.h diff --git a/po/POTFILES.in b/po/POTFILES.in index d10e892..3a6bbe8 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -216,6 +216,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 982f63d..05e91e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -675,7 +675,10 @@ 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/vbox_install_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..65a249f --- /dev/null +++ b/src/vbox/vbox_common.c @@ -0,0 +1,291 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@xxxxxxxxx) + * + * 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" +#include "vbox_install_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; + +int vboxRegisterUniformedAPI(uint32_t uVersion) +{ + /* Install gVBoxAPI according to the vbox API version. + * Return -1 for unsupported version. + */ + 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); + } else { + return -1; + } + return 0; +} + +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.domainEventCallbacks && gVBoxAPI.initializeDomainEvent(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(), + false, false)) == 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; + } + + if (gVBoxAPI.hasStaticGlobalData) + 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..61f410d --- /dev/null +++ b/src/vbox/vbox_common.h @@ -0,0 +1,130 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@xxxxxxxxx) + * + * 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; + +#endif /* VBOX_COMMON_H */ diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index 7d004b2..37b772c 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_install_api.h" #define VIR_FROM_THIS VIR_FROM_VBOX @@ -161,6 +165,8 @@ int vboxRegister(void) } else { VIR_DEBUG("Unsupported VirtualBox API version: %u", uVersion); } + /* Register vboxUniformedAPI. */ + vboxRegisterUniformedAPI(uVersion); } else { VIR_DEBUG("VBoxCGlueInit failed, using dummy driver"); } @@ -175,9 +181,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 +224,5 @@ static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn, static virDriver vboxDriverDummy = { VIR_DRV_VBOX, "VBOX", - .connectOpen = vboxConnectOpen, + .connectOpen = dummyConnectOpen, }; diff --git a/src/vbox/vbox_install_api.h b/src/vbox/vbox_install_api.h new file mode 100644 index 0000000..45a8d8c --- /dev/null +++ b/src/vbox/vbox_install_api.h @@ -0,0 +1,26 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@xxxxxxxxx) + * + * 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_INSTALL_API_H +# define VBOX_INSTALL_API_H + +# include "internal.h" + +int vboxRegisterUniformedAPI(uint32_t uVersion); + +#endif /* VBOX_INSTALL_API_H */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index ccba736..6c13775 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -89,12 +89,15 @@ /* 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 VIR_LOG_INIT("vbox.vbox_tmpl"); +#define vboxUnsupported() \ + VIR_WARN("No %s in current vbox version %d.", __FUNCTION__, VBOX_API_VERSION); + #define VBOX_UTF16_FREE(arg) \ do { \ if (arg) { \ @@ -203,41 +206,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 +834,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(), - false, false)) == 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 +852,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 +11259,121 @@ vboxNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED, return nodeGetFreePages(npages, pages, startCell, cellCount, counts); } +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 +_initializeDomainEvent(vboxGlobalData *data ATTRIBUTE_UNUSED) +{ +#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 + /* No event queue functionality in 2.2.* and 4.* as of now */ + vboxUnsupported(); +#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ + /* 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_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ + return 0; +} + +static +void _registerGlobalData(vboxGlobalData *data ATTRIBUTE_UNUSED) +{ +#if VBOX_API_VERSION == 2002000 + vboxUnsupported(); +#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->initializeDomainEvent = _initializeDomainEvent; + pVBoxAPI->registerGlobalData = _registerGlobalData; + pVBoxAPI->UPFN = _UPFN; + pVBoxAPI->UIVirtualBox = _UIVirtualBox; + +#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 + pVBoxAPI->domainEventCallbacks = 0; +#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ + pVBoxAPI->domainEventCallbacks = 1; +#endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */ + +#if VBOX_API_VERSION == 2002000 + pVBoxAPI->hasStaticGlobalData = 0; +#else /* VBOX_API_VERSION > 2002000 */ + pVBoxAPI->hasStaticGlobalData = 1; +#endif /* VBOX_API_VERSION > 2002000 */ + +} /** * Function Tables diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h new file mode 100644 index 0000000..80abcbb --- /dev/null +++ b/src/vbox/vbox_uniformed_api.h @@ -0,0 +1,153 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@xxxxxxxxx) + * + * 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 for domainEvent */ +# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000 + + /* Async event handling */ + virObjectEventStatePtr domainEvents; + int fdWatch; + IVirtualBoxCallback *vboxCallback; + nsIEventQueue *vboxQueue; + + int volatile vboxCallBackRefCount; + + /* pointer back to the connection */ + virConnectPtr conn; + +# else /* VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 || VBOX_API_VERSION undefined */ + + virObjectEventStatePtr domainEvents; + int fdWatch; + void *vboxCallback; + void *vboxQueue; + int volatile vboxCallBackRefCount; + virConnectPtr conn; + +# endif /* VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 || VBOX_API_VERSION undefined */ + +} 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 (*initializeDomainEvent)(vboxGlobalData *data); + void (*registerGlobalData)(vboxGlobalData *data); + vboxUniformedPFN UPFN; + vboxUniformedIVirtualBox UIVirtualBox; + /* vbox API features */ + bool domainEventCallbacks; + bool hasStaticGlobalData; +} 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); + +#endif /* VBOX_UNIFORMED_API_H */ -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list