VirtualBox

source: vbox/trunk/src/VBox/Main/xpcom/server_module.cpp@ 34575

Last change on this file since 34575 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • 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-2007 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 "xpcom/server.h"
47#include "Logging.h"
48
49#include <VBox/err.h>
50
51#include <iprt/param.h>
52#include <iprt/path.h>
53#include <iprt/process.h>
54#include <iprt/env.h>
55#include <iprt/thread.h>
56
57#include <string.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
94NS_DECL_CLASSINFO (VirtualBox)
95NS_IMPL_CI_INTERFACE_GETTER1 (VirtualBox, IVirtualBox)
96
97static nsresult vboxsvcSpawnDaemon(void)
98{
99 PRFileDesc *readable = nsnull, *writable = nsnull;
100 PRProcessAttr *attr = nsnull;
101 nsresult rv = NS_ERROR_FAILURE;
102 PRFileDesc *devNull;
103 // The ugly casts are necessary because the PR_CreateProcessDetached has
104 // a const array of writable strings as a parameter. It won't write. */
105 char * const args[] = { (char *)VBoxSVCPath, (char *)"--auto-shutdown", 0 };
106
107 // Use a pipe to determine when the daemon process is in the position
108 // to actually process requests. The daemon will write "READY" to the pipe.
109 if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
110 goto end;
111 PR_SetFDInheritable(writable, PR_TRUE);
112
113 attr = PR_NewProcessAttr();
114 if (!attr)
115 goto end;
116
117 if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
118 goto end;
119
120 devNull = PR_Open("/dev/null", PR_RDWR, 0);
121 if (!devNull)
122 goto end;
123
124 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
125 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
126 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
127
128 if (PR_CreateProcessDetached(VBoxSVCPath, args, nsnull, attr) != PR_SUCCESS)
129 goto end;
130
131 // Close /dev/null
132 PR_Close(devNull);
133 // Close the child end of the pipe to make it the only owner of the
134 // file descriptor, so that unexpected closing can be detected.
135 PR_Close(writable);
136 writable = nsnull;
137
138 char msg[10];
139 memset(msg, '\0', sizeof(msg));
140 if ( PR_Read(readable, msg, sizeof(msg)-1) != 5
141 || strcmp(msg, "READY"))
142 goto end;
143
144 rv = NS_OK;
145
146end:
147 if (readable)
148 PR_Close(readable);
149 if (writable)
150 PR_Close(writable);
151 if (attr)
152 PR_DestroyProcessAttr(attr);
153 return rv;
154}
155
156
157/**
158 * VirtualBox component constructor.
159 *
160 * This constructor is responsible for starting the VirtualBox server
161 * process, connecting to it, and redirecting the constructor request to the
162 * VirtualBox component defined on the server.
163 */
164static NS_IMETHODIMP
165VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
166 void **aResult)
167{
168 LogFlowFuncEnter();
169
170 nsresult rc = NS_OK;
171 int vrc = VINF_SUCCESS;
172
173 do
174 {
175 *aResult = NULL;
176 if (NULL != aOuter)
177 {
178 rc = NS_ERROR_NO_AGGREGATION;
179 break;
180 }
181
182 if (!IsVBoxSVCPathSet)
183 {
184 /* Get the directory containing XPCOM components -- the VBoxSVC
185 * executable is expected in the parent directory. */
186 nsCOMPtr <nsIProperties> dirServ = do_GetService (NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
187 if (NS_SUCCEEDED(rc))
188 {
189 nsCOMPtr <nsIFile> componentDir;
190 rc = dirServ->Get (NS_XPCOM_COMPONENT_DIR,
191 NS_GET_IID (nsIFile), getter_AddRefs (componentDir));
192
193 if (NS_SUCCEEDED(rc))
194 {
195 nsCAutoString path;
196 componentDir->GetNativePath (path);
197
198 LogFlowFunc (("component directory = \"%s\"\n", path.get()));
199 AssertBreakStmt (path.Length() + strlen (VBoxSVC_exe) < RTPATH_MAX,
200 rc = NS_ERROR_FAILURE);
201
202#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
203 char achKernArch[128];
204 int cbKernArch = sysinfo (SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
205 if (cbKernArch > 0)
206 {
207 sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
208 IsVBoxSVCPathSet = true;
209 }
210 else
211 rc = NS_ERROR_UNEXPECTED;
212#else
213 strcpy (VBoxSVCPath, path.get());
214 RTPathStripFilename (VBoxSVCPath);
215 strcat (VBoxSVCPath, VBoxSVC_exe);
216
217 IsVBoxSVCPathSet = true;
218#endif
219 }
220 }
221 if (NS_FAILED(rc))
222 break;
223 }
224
225 nsCOMPtr <ipcIService> ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc);
226 if (NS_FAILED(rc))
227 break;
228
229 /* connect to the VBoxSVC server process */
230
231 bool startedOnce = false;
232 unsigned timeLeft = VBoxSVC_Timeout;
233
234 do
235 {
236 LogFlowFunc (("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
237
238 PRUint32 serverID = 0;
239 rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
240 if (NS_FAILED(rc))
241 {
242 LogFlowFunc (("Starting server \"%s\"...\n", VBoxSVCPath));
243
244 startedOnce = true;
245
246 rc = vboxsvcSpawnDaemon();
247 if (NS_FAILED(rc))
248 break;
249
250 /* wait for the server process to establish a connection */
251 do
252 {
253 RTThreadSleep (VBoxSVC_WaitSlice);
254 rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
255 if (NS_SUCCEEDED(rc))
256 break;
257 if (timeLeft <= VBoxSVC_WaitSlice)
258 {
259 timeLeft = 0;
260 break;
261 }
262 timeLeft -= VBoxSVC_WaitSlice;
263 }
264 while (1);
265
266 if (!timeLeft)
267 {
268 rc = IPC_ERROR_WOULD_BLOCK;
269 break;
270 }
271 }
272
273 LogFlowFunc (("Connecting to server (ID=%d)...\n", serverID));
274
275 nsCOMPtr <ipcIDConnectService> dconServ =
276 do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc);
277 if (NS_FAILED(rc))
278 break;
279
280 rc = dconServ->CreateInstance (serverID,
281 CLSID_VirtualBox,
282 aIID, aResult);
283 if (NS_SUCCEEDED(rc))
284 break;
285
286 LogFlowFunc (("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
287
288 /* It's possible that the server gets shut down after we
289 * successfully resolve the server name but before it
290 * receives our CreateInstance() request. So, check for the
291 * name again, and restart the cycle if it fails. */
292 if (!startedOnce)
293 {
294 nsresult rc2 =
295 ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
296 if (NS_SUCCEEDED(rc2))
297 break;
298
299 LogFlowFunc (("Server seems to have terminated before "
300 "receiving our request. Will try again.\n"));
301 }
302 else
303 break;
304 }
305 while (1);
306 }
307 while (0);
308
309 LogFlowFunc (("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
310 LogFlowFuncLeave();
311
312 return rc;
313}
314
315#if 0
316/// @todo not really necessary for the moment
317/**
318 *
319 * @param aCompMgr
320 * @param aPath
321 * @param aLoaderStr
322 * @param aType
323 * @param aInfo
324 *
325 * @return
326 */
327static NS_IMETHODIMP
328VirtualBoxRegistration (nsIComponentManager *aCompMgr,
329 nsIFile *aPath,
330 const char *aLoaderStr,
331 const char *aType,
332 const nsModuleComponentInfo *aInfo)
333{
334 nsCAutoString modulePath;
335 aPath->GetNativePath (modulePath);
336 nsCAutoString moduleTarget;
337 aPath->GetNativeTarget (moduleTarget);
338
339 LogFlowFunc (("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
340 modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
341
342 nsresult rc = NS_OK;
343
344 return rc;
345}
346#endif
347
348/**
349 * Component definition table.
350 * Lists all components defined in this module.
351 */
352static const nsModuleComponentInfo components[] =
353{
354 {
355 "VirtualBox component", // description
356 NS_VIRTUALBOX_CID, NS_VIRTUALBOX_CONTRACTID, // CID/ContractID
357 VirtualBoxConstructor, // constructor function
358 NULL, /* VirtualBoxRegistration, */ // registration function
359 NULL, // deregistration function
360 NULL, // destructor function
361 /// @todo
362 NS_CI_INTERFACE_GETTER_NAME(VirtualBox), // interfaces function
363 NULL, // language helper
364 /// @todo
365 &NS_CLASSINFO_NAME(VirtualBox) // global class info & flags
366 }
367};
368
369NS_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