VirtualBox

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

Last change on this file since 31570 was 30631, checked in by vboxsync, 14 years ago

Main: Escape the (nsCID) { uuid-bits } compound literals expression so that they don't cause trouble with -pedantic is used. (C++ lagging behind C99 again.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 10.1 KB
Line 
1/** @file
2 *
3 * XPCOM server process hepler 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// official XPCOM headers don't define it yet
37#define IPC_DCONNECTSERVICE_CONTRACTID \
38 "@mozilla.org/ipc/dconnect-service;1"
39
40// generated file
41#include <VirtualBox_XPCOM.h>
42
43#include "xpcom/server.h"
44#include "Logging.h"
45
46#include <VBox/err.h>
47
48#include <iprt/param.h>
49#include <iprt/path.h>
50#include <iprt/process.h>
51#include <iprt/env.h>
52#include <iprt/thread.h>
53
54#include <string.h>
55
56#if defined(RT_OS_SOLARIS)
57# include <sys/systeminfo.h>
58#endif
59
60/// @todo move this to RT headers (and use them in MachineImpl.cpp as well)
61#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
62#define HOSTSUFF_EXE ".exe"
63#else /* !RT_OS_WINDOWS */
64#define HOSTSUFF_EXE ""
65#endif /* !RT_OS_WINDOWS */
66
67
68/** Name of the server executable. */
69const char VBoxSVC_exe[] = RTPATH_SLASH_STR "VBoxSVC" HOSTSUFF_EXE;
70
71enum
72{
73 /** Amount of time to wait for the server to establish a connection, ms */
74 VBoxSVC_Timeout = 30000,
75 /** How often to perform a connection check, ms */
76 VBoxSVC_WaitSlice = 100
77};
78
79/**
80 * Full path to the VBoxSVC executable.
81 */
82static char VBoxSVCPath[RTPATH_MAX];
83static bool IsVBoxSVCPathSet = false;
84
85/*
86 * The following macros define the method necessary to provide a list of
87 * interfaces implemented by the VirtualBox component. Note that this must be
88 * in sync with macros used for VirtualBox in server.cpp for the same purpose.
89 */
90
91NS_DECL_CLASSINFO (VirtualBox)
92NS_IMPL_CI_INTERFACE_GETTER1 (VirtualBox, IVirtualBox)
93
94/**
95 * VirtualBox component constructor.
96 *
97 * This constructor is responsible for starting the VirtualBox server
98 * process, connecting to it, and redirecting the constructor request to the
99 * VirtualBox component defined on the server.
100 */
101static NS_IMETHODIMP
102VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID,
103 void **aResult)
104{
105 LogFlowFuncEnter();
106
107 nsresult rc = NS_OK;
108 int vrc = VINF_SUCCESS;
109
110 do
111 {
112 *aResult = NULL;
113 if (NULL != aOuter)
114 {
115 rc = NS_ERROR_NO_AGGREGATION;
116 break;
117 }
118
119 if (!IsVBoxSVCPathSet)
120 {
121 /* Get the directory containing XPCOM components -- the VBoxSVC
122 * executable is expected in the parent directory. */
123 nsCOMPtr <nsIProperties> dirServ = do_GetService (NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
124 if (NS_SUCCEEDED(rc))
125 {
126 nsCOMPtr <nsIFile> componentDir;
127 rc = dirServ->Get (NS_XPCOM_COMPONENT_DIR,
128 NS_GET_IID (nsIFile), getter_AddRefs (componentDir));
129
130 if (NS_SUCCEEDED(rc))
131 {
132 nsCAutoString path;
133 componentDir->GetNativePath (path);
134
135 LogFlowFunc (("component directory = \"%s\"\n", path.get()));
136 AssertBreakStmt (path.Length() + strlen (VBoxSVC_exe) < RTPATH_MAX,
137 rc = NS_ERROR_FAILURE);
138
139#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
140 char achKernArch[128];
141 int cbKernArch = sysinfo (SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
142 if (cbKernArch > 0)
143 {
144 sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
145 IsVBoxSVCPathSet = true;
146 }
147 else
148 rc = NS_ERROR_UNEXPECTED;
149#else
150 strcpy (VBoxSVCPath, path.get());
151 RTPathStripFilename (VBoxSVCPath);
152 strcat (VBoxSVCPath, VBoxSVC_exe);
153
154 IsVBoxSVCPathSet = true;
155#endif
156 }
157 }
158 if (NS_FAILED(rc))
159 break;
160 }
161
162 nsCOMPtr <ipcIService> ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc);
163 if (NS_FAILED(rc))
164 break;
165
166 /* connect to the VBoxSVC server process */
167
168 bool startedOnce = false;
169 unsigned timeLeft = VBoxSVC_Timeout;
170
171 do
172 {
173 LogFlowFunc (("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
174
175 PRUint32 serverID = 0;
176 rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
177 if (NS_FAILED(rc))
178 {
179 LogFlowFunc (("Starting server \"%s\"...\n", VBoxSVCPath));
180
181 startedOnce = true;
182
183#ifdef RT_OS_OS2
184 char * const args[] = { VBoxSVCPath, "--automate", 0 };
185 /* use NSPR because we want the process to be detached right
186 * at startup (it isn't possible to detach it later on),
187 * RTProcCreate() isn't yet capable of doing that. */
188 PRStatus rv = PR_CreateProcessDetached (VBoxSVCPath,
189 args, NULL, NULL);
190 if (rv != PR_SUCCESS)
191 {
192 rc = NS_ERROR_FAILURE;
193 break;
194 }
195#else
196 const char *args[] = { VBoxSVCPath, "--automate", 0 };
197 RTPROCESS pid = NIL_RTPROCESS;
198 vrc = RTProcCreate (VBoxSVCPath, args, RTENV_DEFAULT, 0, &pid);
199 if (RT_FAILURE(vrc))
200 {
201 rc = NS_ERROR_FAILURE;
202 break;
203 }
204
205 /* need to wait for the pid to avoid zombie VBoxSVC.
206 * ignore failure since it just means we'll have a zombie
207 * VBoxSVC until we exit */
208 int vrc2 = RTProcWait(pid, RTPROCWAIT_FLAGS_BLOCK, NULL);
209 AssertRC(vrc2);
210#endif
211
212 /* wait for the server process to establish a connection */
213 do
214 {
215 RTThreadSleep (VBoxSVC_WaitSlice);
216 rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
217 if (NS_SUCCEEDED(rc))
218 break;
219 if (timeLeft <= VBoxSVC_WaitSlice)
220 {
221 timeLeft = 0;
222 break;
223 }
224 timeLeft -= VBoxSVC_WaitSlice;
225 }
226 while (1);
227
228 if (!timeLeft)
229 {
230 rc = IPC_ERROR_WOULD_BLOCK;
231 break;
232 }
233 }
234
235 LogFlowFunc (("Connecting to server (ID=%d)...\n", serverID));
236
237 nsCOMPtr <ipcIDConnectService> dconServ =
238 do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc);
239 if (NS_FAILED(rc))
240 break;
241
242 rc = dconServ->CreateInstance (serverID,
243 CLSID_VirtualBox,
244 aIID, aResult);
245 if (NS_SUCCEEDED(rc))
246 break;
247
248 LogFlowFunc (("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
249
250 /* It's possible that the server gets shut down after we
251 * successfully resolve the server name but before it
252 * receives our CreateInstance() request. So, check for the
253 * name again, and restart the cycle if it fails. */
254 if (!startedOnce)
255 {
256 nsresult rc2 =
257 ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID);
258 if (NS_SUCCEEDED(rc2))
259 break;
260
261 LogFlowFunc (("Server seems to have terminated before "
262 "receiving our request. Will try again.\n"));
263 }
264 else
265 break;
266 }
267 while (1);
268 }
269 while (0);
270
271 LogFlowFunc (("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
272 LogFlowFuncLeave();
273
274 return rc;
275}
276
277#if 0
278/// @todo not really necessary for the moment
279/**
280 *
281 * @param aCompMgr
282 * @param aPath
283 * @param aLoaderStr
284 * @param aType
285 * @param aInfo
286 *
287 * @return
288 */
289static NS_IMETHODIMP
290VirtualBoxRegistration (nsIComponentManager *aCompMgr,
291 nsIFile *aPath,
292 const char *aLoaderStr,
293 const char *aType,
294 const nsModuleComponentInfo *aInfo)
295{
296 nsCAutoString modulePath;
297 aPath->GetNativePath (modulePath);
298 nsCAutoString moduleTarget;
299 aPath->GetNativeTarget (moduleTarget);
300
301 LogFlowFunc (("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
302 modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
303
304 nsresult rc = NS_OK;
305
306 return rc;
307}
308#endif
309
310/**
311 * Component definition table.
312 * Lists all components defined in this module.
313 */
314static const nsModuleComponentInfo components[] =
315{
316 {
317 "VirtualBox component", // description
318 NS_VIRTUALBOX_CID, NS_VIRTUALBOX_CONTRACTID, // CID/ContractID
319 VirtualBoxConstructor, // constructor function
320 NULL, /* VirtualBoxRegistration, */ // registration function
321 NULL, // deregistration function
322 NULL, // destructor function
323 /// @todo
324 NS_CI_INTERFACE_GETTER_NAME(VirtualBox), // interfaces function
325 NULL, // language helper
326 /// @todo
327 &NS_CLASSINFO_NAME(VirtualBox) // global class info & flags
328 }
329};
330
331NS_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