VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/xpcom/server_module.cpp@ 50355

Last change on this file since 50355 was 50355, checked in by vboxsync, 11 years ago

6813 stage 7 VirtualBoxImpl.cpp etc

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 10.9 KB
Line 
1/** @file
2 *
3 * XPCOM server process helper module implementation functions
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef RT_OS_OS2
19# include <prproces.h>
20#endif
21
22#include <nsMemory.h>
23#include <nsString.h>
24#include <nsCOMPtr.h>
25#include <nsIFile.h>
26#include <nsIGenericFactory.h>
27#include <nsIServiceManagerUtils.h>
28#include <nsICategoryManager.h>
29#include <nsDirectoryServiceDefs.h>
30
31#include <ipcIService.h>
32#include <ipcIDConnectService.h>
33#include <ipcCID.h>
34#include <ipcdclient.h>
35
36#include "prio.h"
37#include "prproces.h"
38
39// official XPCOM headers don't define it yet
40#define IPC_DCONNECTSERVICE_CONTRACTID \
41 "@mozilla.org/ipc/dconnect-service;1"
42
43// generated file
44#include <VirtualBox_XPCOM.h>
45
46#include "server.h"
47#include "Logging.h"
48
49#include <VBox/err.h>
50
51#include <iprt/assert.h>
52#include <iprt/param.h>
53#include <iprt/path.h>
54#include <iprt/process.h>
55#include <iprt/env.h>
56#include <iprt/string.h>
57#include <iprt/thread.h>
58
59#if defined(RT_OS_SOLARIS)
60# include <sys/systeminfo.h>
61#endif
62
63/// @todo move this to RT headers (and use them in MachineImpl.cpp as well)
64#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
65#define HOSTSUFF_EXE ".exe"
66#else /* !RT_OS_WINDOWS */
67#define HOSTSUFF_EXE ""
68#endif /* !RT_OS_WINDOWS */
69
70
71/** Name of the server executable. */
72const char VBoxSVC_exe[] = RTPATH_SLASH_STR "VBoxSVC" HOSTSUFF_EXE;
73
74enum
75{
76 /** Amount of time to wait for the server to establish a connection, ms */
77 VBoxSVC_Timeout = 30000,
78 /** How often to perform a connection check, ms */
79 VBoxSVC_WaitSlice = 100
80};
81
82/**
83 * Full path to the VBoxSVC executable.
84 */
85static char VBoxSVCPath[RTPATH_MAX];
86static bool IsVBoxSVCPathSet = false;
87
88/*
89 * The following macros define the method necessary to provide a list of
90 * interfaces implemented by the VirtualBox component. Note that this must be
91 * in sync with macros used for VirtualBox in server.cpp for the same purpose.
92 */
93
94static nsresult vboxsvcSpawnDaemon(void)
95{
96 PRFileDesc *readable = nsnull, *writable = nsnull;
97 PRProcessAttr *attr = nsnull;
98 nsresult rv = NS_ERROR_FAILURE;
99 PRFileDesc *devNull;
100 // The ugly casts are necessary because the PR_CreateProcessDetached has
101 // a const array of writable strings as a parameter. It won't write. */
102 char * const args[] = { (char *)VBoxSVCPath, (char *)"--auto-shutdown", 0 };
103
104 // Use a pipe to determine when the daemon process is in the position
105 // to actually process requests. The daemon will write "READY" to the pipe.
106 if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
107 goto end;
108 PR_SetFDInheritable(writable, PR_TRUE);
109
110 attr = PR_NewProcessAttr();
111 if (!attr)
112 goto end;
113
114 if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
115 goto end;
116
117 devNull = PR_Open("/dev/null", PR_RDWR, 0);
118 if (!devNull)
119 goto end;
120
121 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
122 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
123 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
124
125 if (PR_CreateProcessDetached(VBoxSVCPath, args, nsnull, attr) != PR_SUCCESS)
126 goto end;
127
128 // Close /dev/null
129 PR_Close(devNull);
130 // Close the child end of the pipe to make it the only owner of the
131 // file descriptor, so that unexpected closing can be detected.
132 PR_Close(writable);
133 writable = nsnull;
134
135 char msg[10];
136 RT_ZERO(msg);
137 if ( PR_Read(readable, msg, sizeof(msg)-1) != 5
138 || strcmp(msg, "READY"))
139 {
140 /* If several clients start VBoxSVC simultaneously only one can
141 * succeed. So treat this as success as well. */
142 rv = NS_OK;
143 goto end;
144 }
145
146 rv = NS_OK;
147
148end:
149 if (readable)
150 PR_Close(readable);
151 if (writable)
152 PR_Close(writable);
153 if (attr)
154 PR_DestroyProcessAttr(attr);
155 return rv;
156}
157
158
159/**
160 * VirtualBox component constructor.
161 *
162 * This constructor is responsible for starting the VirtualBox server
163 * process, connecting to it, and redirecting the constructor request to the
164 * VirtualBox component defined on the server.
165 */
166static NS_IMETHODIMP
167VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID,
168 void **aResult)
169{
170 LogFlowFuncEnter();
171
172 nsresult rc = NS_OK;
173 int vrc = VINF_SUCCESS;
174
175 do
176 {
177 *aResult = NULL;
178 if (NULL != aOuter)
179 {
180 rc = NS_ERROR_NO_AGGREGATION;
181 break;
182 }
183
184 if (!IsVBoxSVCPathSet)
185 {
186 /* Get the directory containing XPCOM components -- the VBoxSVC
187 * executable is expected in the parent directory. */
188 nsCOMPtr<nsIProperties> dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
189 if (NS_SUCCEEDED(rc))
190 {
191 nsCOMPtr<nsIFile> componentDir;
192 rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR,
193 NS_GET_IID(nsIFile), getter_AddRefs(componentDir));
194
195 if (NS_SUCCEEDED(rc))
196 {
197 nsCAutoString path;
198 componentDir->GetNativePath(path);
199
200 LogFlowFunc(("component directory = \"%s\"\n", path.get()));
201 AssertBreakStmt(path.Length() + strlen(VBoxSVC_exe) < RTPATH_MAX,
202 rc = NS_ERROR_FAILURE);
203
204#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
205 char achKernArch[128];
206 int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
207 if (cbKernArch > 0)
208 {
209 sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
210 IsVBoxSVCPathSet = true;
211 }
212 else
213 rc = NS_ERROR_UNEXPECTED;
214#else
215 strcpy(VBoxSVCPath, path.get());
216 RTPathStripFilename(VBoxSVCPath);
217 strcat(VBoxSVCPath, VBoxSVC_exe);
218
219 IsVBoxSVCPathSet = true;
220#endif
221 }
222 }
223 if (NS_FAILED(rc))
224 break;
225 }
226
227 nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
228 if (NS_FAILED(rc))
229 break;
230
231 /* connect to the VBoxSVC server process */
232
233 bool startedOnce = false;
234 unsigned timeLeft = VBoxSVC_Timeout;
235
236 do
237 {
238 LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
239
240 PRUint32 serverID = 0;
241 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
242 if (NS_FAILED(rc))
243 {
244 LogFlowFunc(("Starting server \"%s\"...\n", VBoxSVCPath));
245
246 startedOnce = true;
247
248 rc = vboxsvcSpawnDaemon();
249 if (NS_FAILED(rc))
250 break;
251
252 /* wait for the server process to establish a connection */
253 do
254 {
255 RTThreadSleep(VBoxSVC_WaitSlice);
256 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
257 if (NS_SUCCEEDED(rc))
258 break;
259 if (timeLeft <= VBoxSVC_WaitSlice)
260 {
261 timeLeft = 0;
262 break;
263 }
264 timeLeft -= VBoxSVC_WaitSlice;
265 }
266 while (1);
267
268 if (!timeLeft)
269 {
270 rc = IPC_ERROR_WOULD_BLOCK;
271 break;
272 }
273 }
274
275 LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));
276
277 nsCOMPtr<ipcIDConnectService> dconServ =
278 do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
279 if (NS_FAILED(rc))
280 break;
281
282 rc = dconServ->CreateInstance(serverID,
283 CLSID_VirtualBox,
284 aIID, aResult);
285 if (NS_SUCCEEDED(rc))
286 break;
287
288 LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
289
290 /* It's possible that the server gets shut down after we
291 * successfully resolve the server name but before it
292 * receives our CreateInstance() request. So, check for the
293 * name again, and restart the cycle if it fails. */
294 if (!startedOnce)
295 {
296 nsresult rc2 =
297 ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
298 if (NS_SUCCEEDED(rc2))
299 break;
300
301 LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
302 }
303 else
304 break;
305 }
306 while (1);
307 }
308 while (0);
309
310 LogFlowFunc(("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
311 LogFlowFuncLeave();
312
313 return rc;
314}
315
316#if 0
317/// @todo not really necessary for the moment
318/**
319 *
320 * @param aCompMgr
321 * @param aPath
322 * @param aLoaderStr
323 * @param aType
324 * @param aInfo
325 *
326 * @return
327 */
328static NS_IMETHODIMP
329VirtualBoxRegistration(nsIComponentManager *aCompMgr,
330 nsIFile *aPath,
331 const char *aLoaderStr,
332 const char *aType,
333 const nsModuleComponentInfo *aInfo)
334{
335 nsCAutoString modulePath;
336 aPath->GetNativePath(modulePath);
337 nsCAutoString moduleTarget;
338 aPath->GetNativeTarget(moduleTarget);
339
340 LogFlowFunc(("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
341 modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
342
343 nsresult rc = NS_OK;
344
345 return rc;
346}
347#endif
348
349/**
350 * Component definition table.
351 * Lists all components defined in this module.
352 */
353static const nsModuleComponentInfo components[] =
354{
355 {
356 "VirtualBox component", // description
357 NS_VIRTUALBOX_CID, NS_VIRTUALBOX_CONTRACTID, // CID/ContractID
358 VirtualBoxConstructor, // constructor function
359 NULL, /* VirtualBoxRegistration, */ // registration function
360 NULL, // deregistration function
361 NULL, // destructor function
362 /// @todo
363 NS_CI_INTERFACE_GETTER_NAME(VirtualBox), // interfaces function
364 NULL, // language helper
365 /// @todo
366 &NS_CLASSINFO_NAME(VirtualBox) // global class info & flags
367 }
368};
369
370NS_IMPL_NSGETMODULE(VirtualBox_Server_Module, components)
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