VirtualBox

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

Last change on this file since 24541 was 24541, checked in by vboxsync, 15 years ago

fix #4415: VBoxSVC zombie

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