VirtualBox

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

Last change on this file since 106402 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 11.5 KB
Line 
1/* $Id: server_module.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * XPCOM server process helper module implementation functions
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_VBOXSVC
29#include <nsMemory.h>
30#include <nsString.h>
31#include <nsCOMPtr.h>
32#include <nsIFile.h>
33#include <nsIGenericFactory.h>
34#include <nsIServiceManagerUtils.h>
35#include <nsICategoryManager.h>
36#include <nsDirectoryServiceDefs.h>
37
38#include <ipcIService.h>
39#include <ipcIDConnectService.h>
40#include <ipcCID.h>
41#include <ipcdclient.h>
42
43// official XPCOM headers don't define it yet
44#define IPC_DCONNECTSERVICE_CONTRACTID \
45 "@mozilla.org/ipc/dconnect-service;1"
46
47// generated file
48#include <VBox/com/VirtualBox.h>
49
50#include "server.h"
51#include "LoggingNew.h"
52
53#include <iprt/errcore.h>
54
55#include <iprt/assert.h>
56#include <iprt/param.h>
57#include <iprt/path.h>
58#include <iprt/pipe.h>
59#include <iprt/process.h>
60#include <iprt/env.h>
61#include <iprt/string.h>
62#include <iprt/thread.h>
63
64#if defined(RT_OS_SOLARIS)
65# include <sys/systeminfo.h>
66#endif
67
68/// @todo move this to RT headers (and use them in MachineImpl.cpp as well)
69#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
70#define HOSTSUFF_EXE ".exe"
71#else /* !RT_OS_WINDOWS */
72#define HOSTSUFF_EXE ""
73#endif /* !RT_OS_WINDOWS */
74
75
76/** Name of the server executable. */
77static const char g_szVBoxSVC_exe[] = "VBoxSVC" HOSTSUFF_EXE;
78
79enum
80{
81 /** Amount of time to wait for the server to establish a connection, ms */
82 VBoxSVC_Timeout = 30000,
83 /** How often to perform a connection check, ms */
84 VBoxSVC_WaitSlice = 100
85};
86
87/**
88 * Full path to the VBoxSVC executable.
89 */
90static char g_szVBoxSVCPath[RTPATH_MAX];
91static bool g_fIsVBoxSVCPathSet = false;
92
93/*
94 * The following macros define the method necessary to provide a list of
95 * interfaces implemented by the VirtualBox component. Note that this must be
96 * in sync with macros used for VirtualBox in server.cpp for the same purpose.
97 */
98
99NS_DECL_CLASSINFO(VirtualBoxWrap)
100NS_IMPL_CI_INTERFACE_GETTER1(VirtualBoxWrap, IVirtualBox)
101
102static nsresult vboxsvcSpawnDaemon(void)
103{
104 /*
105 * Setup an anonymous pipe that we can use to determine when the daemon
106 * process has started up. the daemon will write a char to the pipe, and
107 * when we read it, we'll know to proceed with trying to connect to the
108 * daemon.
109 */
110 RTPIPE hPipeWr = NIL_RTPIPE;
111 RTPIPE hPipeRd = NIL_RTPIPE;
112 int vrc = RTPipeCreate(&hPipeRd, &hPipeWr, RTPIPE_C_INHERIT_WRITE);
113 if (RT_SUCCESS(vrc))
114 {
115 char szPipeInheritFd[32]; RT_ZERO(szPipeInheritFd);
116 const char *apszArgs[] =
117 {
118 g_szVBoxSVCPath,
119 "--auto-shutdown",
120 "--inherit-startup-pipe",
121 &szPipeInheritFd[0],
122 NULL
123 };
124
125 ssize_t cch = RTStrFormatU32(&szPipeInheritFd[0], sizeof(szPipeInheritFd),
126 (uint32_t)RTPipeToNative(hPipeWr), 10 /*uiBase*/,
127 0 /*cchWidth*/, 0 /*cchPrecision*/, 0 /*fFlags*/);
128 Assert(cch > 0); RT_NOREF(cch);
129
130 RTHANDLE hStdNil;
131 hStdNil.enmType = RTHANDLETYPE_FILE;
132 hStdNil.u.hFile = NIL_RTFILE;
133
134 vrc = RTProcCreateEx(g_szVBoxSVCPath, apszArgs, RTENV_DEFAULT,
135 RTPROC_FLAGS_DETACHED, &hStdNil, &hStdNil, &hStdNil,
136 NULL /* pszAsUser */, NULL /* pszPassword */, NULL /* pExtraData */,
137 NULL /* phProcess */);
138 if (RT_SUCCESS(vrc))
139 {
140 vrc = RTPipeClose(hPipeWr); AssertRC(vrc); RT_NOREF(vrc);
141 hPipeWr = NIL_RTPIPE;
142
143 size_t cbRead = 0;
144 char msg[10];
145 memset(msg, '\0', sizeof(msg));
146 vrc = RTPipeReadBlocking(hPipeRd, &msg[0], sizeof(msg) - 1, &cbRead);
147 if ( RT_SUCCESS(vrc)
148 && cbRead == 5
149 && !strcmp(msg, "READY"))
150 {
151 RTPipeClose(hPipeRd);
152 return NS_OK;
153 }
154 }
155
156 if (hPipeWr != NIL_RTPIPE)
157 RTPipeClose(hPipeWr);
158 RTPipeClose(hPipeRd);
159 }
160
161 return NS_ERROR_FAILURE;
162}
163
164
165/**
166 * VirtualBox component constructor.
167 *
168 * This constructor is responsible for starting the VirtualBox server
169 * process, connecting to it, and redirecting the constructor request to the
170 * VirtualBox component defined on the server.
171 */
172static NS_IMETHODIMP
173VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID,
174 void **aResult)
175{
176 LogFlowFuncEnter();
177
178 nsresult rc = NS_OK;
179
180 do
181 {
182 *aResult = NULL;
183 if (NULL != aOuter)
184 {
185 rc = NS_ERROR_NO_AGGREGATION;
186 break;
187 }
188
189 if (!g_fIsVBoxSVCPathSet)
190 {
191 /* Get the directory containing XPCOM components -- the VBoxSVC
192 * executable is expected in the parent directory. */
193 nsCOMPtr<nsIProperties> dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
194 if (NS_SUCCEEDED(rc))
195 {
196 nsCOMPtr<nsIFile> componentDir;
197 rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR,
198 NS_GET_IID(nsIFile), getter_AddRefs(componentDir));
199
200 if (NS_SUCCEEDED(rc))
201 {
202 nsCAutoString path;
203 componentDir->GetNativePath(path);
204
205 LogFlowFunc(("component directory = \"%s\"\n", path.get()));
206
207#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
208 char szKernArch[128];
209 int cbKernArch = sysinfo(SI_ARCHITECTURE_K, szKernArch, sizeof(szKernArch));
210 AssertBreakStmt(cbKernArch > 0, rc = NS_ERROR_UNEXPECTED);
211# ifdef VBOX_PATH_APP_PRIVATE
212 sprintf(g_szVBoxSVCPath, VBOX_PATH_APP_PRIVATE "/%s/%s", szKernArch, g_szVBoxSVC_exe);
213# else
214 sprintf(g_szVBoxSVCPath, "/opt/VirtualBox/%s/%s", szKernArch, g_szVBoxSVC_exe);
215# endif
216 g_fIsVBoxSVCPathSet = true;
217#else
218 int vrc = RTStrCopy(g_szVBoxSVCPath, sizeof(g_szVBoxSVCPath), path.get());
219 AssertRCBreakStmt(vrc, rc = NS_ERROR_FAILURE);
220
221 RTPathStripFilename(g_szVBoxSVCPath); /* ".." to the parent directory */
222
223 vrc = RTPathAppend(g_szVBoxSVCPath, sizeof(g_szVBoxSVCPath), g_szVBoxSVC_exe);
224 AssertRCBreakStmt(vrc, rc = NS_ERROR_FAILURE);
225 g_fIsVBoxSVCPathSet = true;
226#endif
227 }
228 }
229 if (NS_FAILED(rc))
230 break;
231 }
232
233 nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
234 if (NS_FAILED(rc))
235 break;
236
237 /* connect to the VBoxSVC server process */
238
239 bool startedOnce = false;
240 unsigned timeLeft = VBoxSVC_Timeout;
241
242 do
243 {
244 LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
245
246 PRUint32 serverID = 0;
247 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
248 if (NS_FAILED(rc))
249 {
250 LogFlowFunc(("Starting server \"%s\"...\n", g_szVBoxSVCPath));
251
252 startedOnce = true;
253
254 rc = vboxsvcSpawnDaemon();
255 if (NS_FAILED(rc))
256 break;
257
258 /* wait for the server process to establish a connection */
259 do
260 {
261 RTThreadSleep(VBoxSVC_WaitSlice);
262 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
263 if (NS_SUCCEEDED(rc))
264 break;
265 if (timeLeft <= VBoxSVC_WaitSlice)
266 {
267 timeLeft = 0;
268 break;
269 }
270 timeLeft -= VBoxSVC_WaitSlice;
271 }
272 while (1);
273
274 if (!timeLeft)
275 {
276 rc = IPC_ERROR_WOULD_BLOCK;
277 break;
278 }
279 }
280
281 LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));
282
283 nsCOMPtr<ipcIDConnectService> dconServ =
284 do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
285 if (NS_FAILED(rc))
286 break;
287
288 rc = dconServ->CreateInstance(serverID,
289 CLSID_VirtualBox,
290 aIID, aResult);
291 if (NS_SUCCEEDED(rc))
292 break;
293
294 LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
295
296 /* It's possible that the server gets shut down after we
297 * successfully resolve the server name but before it
298 * receives our CreateInstance() request. So, check for the
299 * name again, and restart the cycle if it fails. */
300 if (!startedOnce)
301 {
302 nsresult rc2 =
303 ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
304 if (NS_SUCCEEDED(rc2))
305 break;
306
307 LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
308 }
309 else
310 break;
311 }
312 while (1);
313 }
314 while (0);
315
316 LogFlowFunc(("rc=%Rhrc (%#08x)\n", rc, rc));
317 LogFlowFuncLeave();
318
319 return rc;
320}
321
322#if 0
323/// @todo not really necessary for the moment
324/**
325 *
326 * @param aCompMgr
327 * @param aPath
328 * @param aLoaderStr
329 * @param aType
330 * @param aInfo
331 *
332 * @return
333 */
334static NS_IMETHODIMP
335VirtualBoxRegistration(nsIComponentManager *aCompMgr,
336 nsIFile *aPath,
337 const char *aLoaderStr,
338 const char *aType,
339 const nsModuleComponentInfo *aInfo)
340{
341 nsCAutoString modulePath;
342 aPath->GetNativePath(modulePath);
343 nsCAutoString moduleTarget;
344 aPath->GetNativeTarget(moduleTarget);
345
346 LogFlowFunc(("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
347 modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
348
349 nsresult rc = NS_OK;
350
351 return rc;
352}
353#endif
354
355/**
356 * Component definition table.
357 * Lists all components defined in this module.
358 */
359static const nsModuleComponentInfo components[] =
360{
361 {
362 "VirtualBox component", // description
363 NS_VIRTUALBOX_CID, NS_VIRTUALBOX_CONTRACTID, // CID/ContractID
364 VirtualBoxConstructor, // constructor function
365 NULL, /* VirtualBoxRegistration, */ // registration function
366 NULL, // deregistration function
367 NULL, // destructor function
368 /// @todo
369 NS_CI_INTERFACE_GETTER_NAME(VirtualBoxWrap), // interfaces function
370 NULL, // language helper
371 /// @todo
372 &NS_CLASSINFO_NAME(VirtualBoxWrap) // global class info & flags
373 }
374};
375
376NS_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