VirtualBox

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

Last change on this file since 64226 was 63177, checked in by vboxsync, 8 years ago

Main: warnings

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