VirtualBox

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

Last change on this file since 69235 was 69235, checked in by vboxsync, 7 years ago

Main/cbinding: scm update

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette