VirtualBox

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

Last change on this file since 54803 was 54027, checked in by vboxsync, 10 years ago

Main/cbinding: Add new helper functions to clear out strings (useful if they contain sensitive data). While doing this, added code to the glue init which checks if the version of the structure is compatible with what the client expects. This exposed annoying code duplication between the non-Windows/Windows implementations which is now eliminated.

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