VirtualBox

source: vbox/trunk/src/VBox/Main/cbinding/VBoxCAPIGlue.c@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
RevLine 
[55400]1/* $Id: VBoxCAPIGlue.c 98103 2023-01-17 14:15:46Z vboxsync $ */
[16832]2/** @file
[50183]3 * Glue code for dynamically linking to VBoxCAPI.
[16832]4 */
5
6/*
[98103]7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
[16832]8 *
[69377]9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
[16832]17 *
[69377]18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
[16837]20 *
[69377]21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
[18241]28 * OTHER DEALINGS IN THE SOFTWARE.
[16832]29 */
30
[57358]31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
[64448]35/* NOTE: do NOT use any include files here which are only available in the
36 * VirtualBox tree, e.g. iprt. They are not available in the SDK, which is
37 * where this file will provided as source code and has to be compilable. */
[50183]38#include "VBoxCAPIGlue.h"
39
[16832]40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
[19028]43#include <stdarg.h>
[64449]44#ifdef WIN32
45# define _INTPTR 2 /* on Windows stdint.h compares this in #if, causing warnings if not defined */
46#endif /* WIN32 */
[64448]47#include <stdint.h>
[50183]48#ifndef WIN32
49# include <dlfcn.h>
50# include <pthread.h>
51#else /* WIN32 */
[64448]52# include <Windows.h>
[50183]53#endif /* WIN32 */
[16832]54
55
[57358]56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
[18923]59#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__)
[50183]60# define DYNLIB_NAME "VBoxXPCOMC.so"
[16832]61#elif defined(__APPLE__)
[50183]62# define DYNLIB_NAME "VBoxXPCOMC.dylib"
63#elif defined(__OS2__)
64# define DYNLIB_NAME "VBoxXPCOMC.dll"
65#elif defined(WIN32)
66# define DYNLIB_NAME "VBoxCAPI.dll"
[16832]67#else
68# error "Port me"
69#endif
70
[18155]71
[57358]72/*********************************************************************************************************************************
73* Global Variables *
74*********************************************************************************************************************************/
[50183]75/** The so/dynsym/dll handle for VBoxCAPI. */
76#ifndef WIN32
77void *g_hVBoxCAPI = NULL;
78#else /* WIN32 */
79HMODULE g_hVBoxCAPI = NULL;
80#endif /* WIN32 */
[16832]81/** The last load error. */
[50183]82char g_szVBoxErrMsg[256] = "";
83/** Pointer to the VBOXCAPI function table. */
84PCVBOXCAPI g_pVBoxFuncs = NULL;
85/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */
86PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions = NULL;
[16832]87
[49539]88typedef void FNDUMMY(void);
89typedef FNDUMMY *PFNDUMMY;
90/** Just a dummy global structure containing a bunch of
[50183]91 * function pointers to code which is wanted in the link. */
92PFNDUMMY g_apfnVBoxCAPIGlue[] =
[49539]93{
[50183]94#ifndef WIN32
95 /* The following link dependency is for helping gdb as it gets hideously
96 * confused if the application doesn't drag in pthreads, but uses it. */
97 (PFNDUMMY)pthread_create,
98#endif /* !WIN32 */
99 NULL
[49539]100};
[16832]101
[49539]102
[16832]103/**
[19028]104 * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub.
105 *
[19052]106 * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty.
[19028]107 * @param pszFormat The format string.
108 * @param ... The arguments.
109 */
[19052]110static void setErrMsg(int fAlways, const char *pszFormat, ...)
[19028]111{
[19052]112 if ( fAlways
113 || !g_szVBoxErrMsg[0])
114 {
115 va_list va;
116 va_start(va, pszFormat);
117 vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va);
118 va_end(va);
119 }
[19028]120}
121
122
123/**
[50183]124 * Try load C API .so/dylib/dll from the specified location and resolve all
125 * the symbols we need. Tries both the new style and legacy name.
[16832]126 *
127 * @returns 0 on success, -1 on failure.
[50183]128 * @param pszHome The directory where to try load VBoxCAPI/VBoxXPCOMC
129 * from. Can be NULL.
[19028]130 * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not
131 * (boolean).
[16832]132 */
[50183]133static int tryLoadLibrary(const char *pszHome, int fSetAppHome)
[16832]134{
135 size_t cchHome = pszHome ? strlen(pszHome) : 0;
[18871]136 size_t cbBufNeeded;
[19028]137 char szName[4096];
[16832]138
139 /*
140 * Construct the full name.
141 */
[18871]142 cbBufNeeded = cchHome + sizeof("/" DYNLIB_NAME);
[19028]143 if (cbBufNeeded > sizeof(szName))
[16832]144 {
[19052]145 setErrMsg(1, "path buffer too small: %u bytes needed",
[19028]146 (unsigned)cbBufNeeded);
[16832]147 return -1;
148 }
[18871]149 if (cchHome)
150 {
[19028]151 memcpy(szName, pszHome, cchHome);
152 szName[cchHome] = '/';
[18871]153 cchHome++;
154 }
[19028]155 memcpy(&szName[cchHome], DYNLIB_NAME, sizeof(DYNLIB_NAME));
[16832]156
157 /*
158 * Try load it by that name, setting the VBOX_APP_HOME first (for now).
159 * Then resolve and call the function table getter.
160 */
[18871]161 if (fSetAppHome)
[18853]162 {
[50183]163#ifndef WIN32
[18871]164 if (pszHome)
165 setenv("VBOX_APP_HOME", pszHome, 1 /* always override */);
166 else
167 unsetenv("VBOX_APP_HOME");
[50183]168#endif /* !WIN32 */
[18853]169 }
[50183]170
171#ifndef WIN32
172 g_hVBoxCAPI = dlopen(szName, RTLD_NOW | RTLD_LOCAL);
[54027]173#else /* WIN32 */
174 g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */, 0 /* dwFlags */);
175#endif /* WIN32 */
[50183]176 if (g_hVBoxCAPI)
[16832]177 {
[50183]178 PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions;
[54027]179#ifndef WIN32
[50183]180 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t)
181 dlsym(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME);
[54027]182# ifdef VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME
[50183]183 if (!pfnGetFunctions)
184 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t)
185 dlsym(g_hVBoxCAPI, VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME);
[54027]186# endif /* VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME */
187#else /* WIN32 */
188 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)
189 GetProcAddress(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME);
190#endif /* WIN32 */
[16832]191 if (pfnGetFunctions)
192 {
[50183]193 g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION);
[16832]194 if (g_pVBoxFuncs)
[17677]195 {
[54027]196 if ( ( VBOX_CAPI_MAJOR(g_pVBoxFuncs->uVersion)
197 == VBOX_CAPI_MAJOR(VBOX_CAPI_VERSION))
198 && ( VBOX_CAPI_MINOR(g_pVBoxFuncs->uVersion)
199 >= VBOX_CAPI_MINOR(VBOX_CAPI_VERSION)))
200 {
201 g_pfnGetFunctions = pfnGetFunctions;
202 return 0;
203 }
204 setErrMsg(1, "%.80s: pfnGetFunctions(%#x) returned incompatible version %#x",
205 szName, VBOX_CAPI_VERSION, g_pVBoxFuncs->uVersion);
206 g_pVBoxFuncs = NULL;
[17677]207 }
[54027]208 else
209 {
210 /* bail out */
211 setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed",
212 szName, VBOX_CAPI_VERSION);
213 }
[16832]214 }
[19028]215 else
[54027]216 {
217#ifndef WIN32
[19052]218 setErrMsg(1, "dlsym(%.80s/%.32s): %.128s",
[50183]219 szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, dlerror());
[54027]220#else /* WIN32 */
[50183]221 setErrMsg(1, "GetProcAddress(%.80s/%.32s): %d",
222 szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, GetLastError());
[54027]223#endif /* WIN32 */
224 }
225
226#ifndef WIN32
227 dlclose(g_hVBoxCAPI);
228#else /* WIN32 */
[50183]229 FreeLibrary(g_hVBoxCAPI);
[54027]230#endif /* WIN32 */
[50183]231 g_hVBoxCAPI = NULL;
232 }
233 else
[54027]234 {
235#ifndef WIN32
236 setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror());
237#else /* WIN32 */
[50183]238 setErrMsg(0, "LoadLibraryEx(%.80s): %d", szName, GetLastError());
[54027]239#endif /* WIN32 */
240 }
[50183]241
242 return -1;
[16832]243}
244
245
246/**
[50183]247 * Tries to locate and load VBoxCAPI.so/dylib/dll, resolving all the related
[16832]248 * function pointers.
249 *
250 * @returns 0 on success, -1 on failure.
251 *
252 * @remark This should be considered moved into a separate glue library since
[50183]253 * its its going to be pretty much the same for any user of VBoxCAPI
[16832]254 * and it will just cause trouble to have duplicate versions of this
255 * source code all around the place.
256 */
[17813]257int VBoxCGlueInit(void)
[16832]258{
[50183]259 const char *pszHome;
260
261 memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg));
262
[16832]263 /*
264 * If the user specifies the location, try only that.
265 */
[50183]266 pszHome = getenv("VBOX_APP_HOME");
[16832]267 if (pszHome)
[50183]268 return tryLoadLibrary(pszHome, 0);
[16832]269
270 /*
271 * Try the known standard locations.
272 */
273#if defined(__gnu__linux__) || defined(__linux__)
[50183]274 if (tryLoadLibrary("/opt/VirtualBox", 1) == 0)
[16832]275 return 0;
[50183]276 if (tryLoadLibrary("/usr/lib/virtualbox", 1) == 0)
[16832]277 return 0;
278#elif defined(__sun__)
[50183]279 if (tryLoadLibrary("/opt/VirtualBox/amd64", 1) == 0)
[16832]280 return 0;
[50183]281 if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0)
[16832]282 return 0;
283#elif defined(__APPLE__)
[52846]284 if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0)
[16832]285 return 0;
[18923]286#elif defined(__FreeBSD__)
[50183]287 if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0)
[18923]288 return 0;
[33396]289#elif defined(__OS2__)
[50183]290 if (tryLoadLibrary("C:/Apps/VirtualBox", 1) == 0)
[33396]291 return 0;
[50183]292#elif defined(WIN32)
293 pszHome = getenv("ProgramFiles");
294 if (pszHome)
295 {
296 char szPath[4096];
297 size_t cb = sizeof(szPath);
298 char *tmp = szPath;
299 strncpy(tmp, pszHome, cb);
300 tmp[cb - 1] = '\0';
301 cb -= strlen(tmp);
302 tmp += strlen(tmp);
303 strncpy(tmp, "/Oracle/VirtualBox", cb);
304 tmp[cb - 1] = '\0';
305 if (tryLoadLibrary(szPath, 1) == 0)
306 return 0;
307 }
308 if (tryLoadLibrary("C:/Program Files/Oracle/VirtualBox", 1) == 0)
309 return 0;
[16832]310#else
311# error "port me"
312#endif
313
314 /*
315 * Finally try the dynamic linker search path.
316 */
[50183]317 if (tryLoadLibrary(NULL, 1) == 0)
[16832]318 return 0;
319
320 /* No luck, return failure. */
321 return -1;
322}
323
[18155]324
[16832]325/**
326 * Terminate the C glue library.
327 */
328void VBoxCGlueTerm(void)
329{
[50183]330 if (g_hVBoxCAPI)
[17570]331 {
[18156]332#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */
[50183]333#ifndef WIN32
334 dlclose(g_hVBoxCAPI);
335#else
336 FreeLibrary(g_hVBoxCAPI);
[18156]337#endif
[50183]338#endif
339 g_hVBoxCAPI = NULL;
[17570]340 }
341 g_pVBoxFuncs = NULL;
[17677]342 g_pfnGetFunctions = NULL;
[19028]343 memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg));
[16832]344}
[18155]345
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use