VirtualBox

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

Last change on this file since 103285 was 103285, checked in by vboxsync, 12 months ago

Re-applied r161549 again (Got rid of a lot of deprecated strcpy / strcat calls; now using the IPRT pendants (found by Parfait)), left out some stuff which wasn't wanted, less bloated version of DrvAudio.cpp. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 11.6 KB
Line 
1/* $Id: server_module.cpp 103285 2024-02-08 15:27:12Z vboxsync $ */
2/** @file
3 * XPCOM server process helper module implementation functions
4 */
5
6/*
7 * Copyright (C) 2006-2023 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. */
77const char g_szVBoxSVC_exe[] = RTPATH_SLASH_STR "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 AssertBreakStmt(path.Length() + strlen(g_szVBoxSVC_exe) < RTPATH_MAX,
207 rc = NS_ERROR_FAILURE);
208
209#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
210 char achKernArch[128];
211 int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
212 if (cbKernArch > 0)
213 {
214 sprintf(g_szVBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, g_szVBoxSVC_exe);
215 g_fIsVBoxSVCPathSet = true;
216 }
217 else
218 rc = NS_ERROR_UNEXPECTED;
219#else
220 int vrc = RTStrCopy(g_szVBoxSVCPath, sizeof(g_szVBoxSVCPath), path.get());
221 AssertRCBreakStmt(vrc, rc = NS_ERROR_FAILURE);
222 RTPathStripFilename(g_szVBoxSVCPath);
223 vrc = RTStrCat(g_szVBoxSVCPath, sizeof(g_szVBoxSVCPath), g_szVBoxSVC_exe);
224 AssertRCBreakStmt(vrc, rc = NS_ERROR_FAILURE);
225
226 g_fIsVBoxSVCPathSet = true;
227#endif
228 }
229 }
230 if (NS_FAILED(rc))
231 break;
232 }
233
234 nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
235 if (NS_FAILED(rc))
236 break;
237
238 /* connect to the VBoxSVC server process */
239
240 bool startedOnce = false;
241 unsigned timeLeft = VBoxSVC_Timeout;
242
243 do
244 {
245 LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));
246
247 PRUint32 serverID = 0;
248 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
249 if (NS_FAILED(rc))
250 {
251 LogFlowFunc(("Starting server \"%s\"...\n", g_szVBoxSVCPath));
252
253 startedOnce = true;
254
255 rc = vboxsvcSpawnDaemon();
256 if (NS_FAILED(rc))
257 break;
258
259 /* wait for the server process to establish a connection */
260 do
261 {
262 RTThreadSleep(VBoxSVC_WaitSlice);
263 rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
264 if (NS_SUCCEEDED(rc))
265 break;
266 if (timeLeft <= VBoxSVC_WaitSlice)
267 {
268 timeLeft = 0;
269 break;
270 }
271 timeLeft -= VBoxSVC_WaitSlice;
272 }
273 while (1);
274
275 if (!timeLeft)
276 {
277 rc = IPC_ERROR_WOULD_BLOCK;
278 break;
279 }
280 }
281
282 LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));
283
284 nsCOMPtr<ipcIDConnectService> dconServ =
285 do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
286 if (NS_FAILED(rc))
287 break;
288
289 rc = dconServ->CreateInstance(serverID,
290 CLSID_VirtualBox,
291 aIID, aResult);
292 if (NS_SUCCEEDED(rc))
293 break;
294
295 LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));
296
297 /* It's possible that the server gets shut down after we
298 * successfully resolve the server name but before it
299 * receives our CreateInstance() request. So, check for the
300 * name again, and restart the cycle if it fails. */
301 if (!startedOnce)
302 {
303 nsresult rc2 =
304 ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
305 if (NS_SUCCEEDED(rc2))
306 break;
307
308 LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
309 }
310 else
311 break;
312 }
313 while (1);
314 }
315 while (0);
316
317 LogFlowFunc(("rc=%Rhrc (%#08x)\n", rc, rc));
318 LogFlowFuncLeave();
319
320 return rc;
321}
322
323#if 0
324/// @todo not really necessary for the moment
325/**
326 *
327 * @param aCompMgr
328 * @param aPath
329 * @param aLoaderStr
330 * @param aType
331 * @param aInfo
332 *
333 * @return
334 */
335static NS_IMETHODIMP
336VirtualBoxRegistration(nsIComponentManager *aCompMgr,
337 nsIFile *aPath,
338 const char *aLoaderStr,
339 const char *aType,
340 const nsModuleComponentInfo *aInfo)
341{
342 nsCAutoString modulePath;
343 aPath->GetNativePath(modulePath);
344 nsCAutoString moduleTarget;
345 aPath->GetNativeTarget(moduleTarget);
346
347 LogFlowFunc(("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n",
348 modulePath.get(), moduleTarget.get(), aLoaderStr, aType));
349
350 nsresult rc = NS_OK;
351
352 return rc;
353}
354#endif
355
356/**
357 * Component definition table.
358 * Lists all components defined in this module.
359 */
360static const nsModuleComponentInfo components[] =
361{
362 {
363 "VirtualBox component", // description
364 NS_VIRTUALBOX_CID, NS_VIRTUALBOX_CONTRACTID, // CID/ContractID
365 VirtualBoxConstructor, // constructor function
366 NULL, /* VirtualBoxRegistration, */ // registration function
367 NULL, // deregistration function
368 NULL, // destructor function
369 /// @todo
370 NS_CI_INTERFACE_GETTER_NAME(VirtualBoxWrap), // interfaces function
371 NULL, // language helper
372 /// @todo
373 &NS_CLASSINFO_NAME(VirtualBoxWrap) // global class info & flags
374 }
375};
376
377NS_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