VirtualBox

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

Last change on this file since 58059 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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