VirtualBox

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

Last change on this file since 16524 was 15604, checked in by vboxsync, 16 years ago

Main: #3400: Fixed a race between the VBoxSVC shutdown timer and clients wanting new objects.

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