VirtualBox

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

Last change on this file since 53627 was 51498, checked in by vboxsync, 11 years ago

6813 - MachineImpl use of server side wrappers + misc mods on other classes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.3 KB
Line 
1/* $Id: server.cpp 51498 2014-06-02 18:53:08Z vboxsync $ */
2/** @file
3 * XPCOM server process (VBoxSVC) start point.
4 */
5
6/*
7 * Copyright (C) 2004-2014 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#include <ipcIService.h>
19#include <ipcCID.h>
20
21#include <nsIComponentRegistrar.h>
22
23#include <nsEventQueueUtils.h>
24#include <nsGenericFactory.h>
25
26#include "prio.h"
27#include "prproces.h"
28
29#include "server.h"
30
31#include "Logging.h"
32
33#include <VBox/param.h>
34
35#include <iprt/buildconfig.h>
36#include <iprt/initterm.h>
37#include <iprt/critsect.h>
38#include <iprt/getopt.h>
39#include <iprt/message.h>
40#include <iprt/string.h>
41#include <iprt/stream.h>
42#include <iprt/path.h>
43#include <iprt/timer.h>
44#include <iprt/env.h>
45
46#include <signal.h> // for the signal handler
47#include <stdlib.h>
48#include <unistd.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <sys/stat.h>
52#include <sys/resource.h>
53
54/////////////////////////////////////////////////////////////////////////////
55// VirtualBox component instantiation
56/////////////////////////////////////////////////////////////////////////////
57
58#include <nsIGenericFactory.h>
59#include <VirtualBox_XPCOM.h>
60
61#include "ApplianceImpl.h"
62#include "AudioAdapterImpl.h"
63#include "BandwidthControlImpl.h"
64#include "BandwidthGroupImpl.h"
65#include "NetworkServiceRunner.h"
66#include "DHCPServerImpl.h"
67#include "GuestOSTypeImpl.h"
68#include "HostImpl.h"
69#include "HostNetworkInterfaceImpl.h"
70#include "MachineImpl.h"
71#include "MediumFormatImpl.h"
72#include "MediumImpl.h"
73#include "NATEngineImpl.h"
74#include "NetworkAdapterImpl.h"
75#include "ParallelPortImpl.h"
76#include "ProgressProxyImpl.h"
77#include "SerialPortImpl.h"
78#include "SharedFolderImpl.h"
79#include "SnapshotImpl.h"
80#include "StorageControllerImpl.h"
81#include "SystemPropertiesImpl.h"
82#include "USBControllerImpl.h"
83#include "USBDeviceFiltersImpl.h"
84#include "VFSExplorerImpl.h"
85#include "VirtualBoxImpl.h"
86#include "VRDEServerImpl.h"
87#ifdef VBOX_WITH_USB
88# include "HostUSBDeviceImpl.h"
89# include "USBDeviceFilterImpl.h"
90# include "USBDeviceImpl.h"
91#endif
92#ifdef VBOX_WITH_EXTPACK
93# include "ExtPackManagerImpl.h"
94#endif
95# include "NATNetworkImpl.h"
96
97// This needs to stay - it is needed by the service registration below, and
98// is defined in the automatically generated VirtualBoxWrap.cpp
99extern nsIClassInfo *NS_CLASSINFO_NAME(VirtualBoxWrap);
100NS_DECL_CI_INTERFACE_GETTER(VirtualBoxWrap)
101
102// The declarations/implementations of the various XPCOM helper data structures
103// and functions have to be removed bit by bit, as the conversion to the
104// automatically generated wrappers makes them obsolete.
105
106/* implement nsISupports parts of our objects with support for nsIClassInfo */
107NS_DECL_CLASSINFO(SessionMachine)
108NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
109
110NS_DECL_CLASSINFO(SnapshotMachine)
111NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
112
113NS_DECL_CLASSINFO(ProgressProxy)
114NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress)
115
116#ifdef VBOX_WITH_USB
117
118#endif
119
120#ifdef VBOX_WITH_RESOURCE_USAGE_API
121NS_DECL_CLASSINFO(PerformanceCollector)
122NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceCollector, IPerformanceCollector)
123NS_DECL_CLASSINFO(PerformanceMetric)
124NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceMetric, IPerformanceMetric)
125#endif /* VBOX_WITH_RESOURCE_USAGE_API */
126
127////////////////////////////////////////////////////////////////////////////////
128
129static bool gAutoShutdown = false;
130/** Delay before shutting down the VirtualBox server after the last
131 * VirtualBox instance is released, in ms */
132static uint32_t gShutdownDelayMs = 5000;
133
134static nsIEventQueue *gEventQ = nsnull;
135static PRBool volatile gKeepRunning = PR_TRUE;
136static PRBool volatile gAllowSigUsrQuit = PR_TRUE;
137
138/////////////////////////////////////////////////////////////////////////////
139
140/**
141 * Simple but smart PLEvent wrapper.
142 *
143 * @note Instances must be always created with <tt>operator new</tt>!
144 */
145class MyEvent
146{
147public:
148
149 MyEvent()
150 {
151 mEv.that = NULL;
152 };
153
154 /**
155 * Posts this event to the given message queue. This method may only be
156 * called once. @note On success, the event will be deleted automatically
157 * after it is delivered and handled. On failure, the event will delete
158 * itself before this method returns! The caller must not delete it in
159 * either case.
160 */
161 nsresult postTo(nsIEventQueue *aEventQ)
162 {
163 AssertReturn(mEv.that == NULL, NS_ERROR_FAILURE);
164 AssertReturn(aEventQ, NS_ERROR_FAILURE);
165 nsresult rv = aEventQ->InitEvent(&mEv.e, NULL,
166 eventHandler, eventDestructor);
167 if (NS_SUCCEEDED(rv))
168 {
169 mEv.that = this;
170 rv = aEventQ->PostEvent(&mEv.e);
171 if (NS_SUCCEEDED(rv))
172 return rv;
173 }
174 delete this;
175 return rv;
176 }
177
178 virtual void *handler() = 0;
179
180private:
181
182 struct Ev
183 {
184 PLEvent e;
185 MyEvent *that;
186 } mEv;
187
188 static void *PR_CALLBACK eventHandler(PLEvent *self)
189 {
190 return reinterpret_cast<Ev *>(self)->that->handler();
191 }
192
193 static void PR_CALLBACK eventDestructor(PLEvent *self)
194 {
195 delete reinterpret_cast<Ev *>(self)->that;
196 }
197};
198
199////////////////////////////////////////////////////////////////////////////////
200
201/**
202 * VirtualBox class factory that destroys the created instance right after
203 * the last reference to it is released by the client, and recreates it again
204 * when necessary (so VirtualBox acts like a singleton object).
205 */
206class VirtualBoxClassFactory : public VirtualBox
207{
208public:
209
210 virtual ~VirtualBoxClassFactory()
211 {
212 LogFlowFunc(("Deleting VirtualBox...\n"));
213
214 FinalRelease();
215 sInstance = NULL;
216
217 LogFlowFunc(("VirtualBox object deleted.\n"));
218 RTPrintf("Informational: VirtualBox object deleted.\n");
219 }
220
221 NS_IMETHOD_(nsrefcnt) Release()
222 {
223 /* we overload Release() to guarantee the VirtualBox destructor is
224 * always called on the main thread */
225
226 nsrefcnt count = VirtualBox::Release();
227
228 if (count == 1)
229 {
230 /* the last reference held by clients is being released
231 * (see GetInstance()) */
232
233 PRBool onMainThread = PR_TRUE;
234 if (gEventQ)
235 gEventQ->IsOnCurrentThread(&onMainThread);
236
237 PRBool timerStarted = PR_FALSE;
238
239 /* sTimer is null if this call originates from FactoryDestructor()*/
240 if (sTimer != NULL)
241 {
242 LogFlowFunc(("Last VirtualBox instance was released.\n"));
243 LogFlowFunc(("Scheduling server shutdown in %u ms...\n",
244 gShutdownDelayMs));
245
246 /* make sure the previous timer (if any) is stopped;
247 * otherwise RTTimerStart() will definitely fail. */
248 RTTimerLRStop(sTimer);
249
250 int vrc = RTTimerLRStart(sTimer, gShutdownDelayMs * RT_NS_1MS_64);
251 AssertRC(vrc);
252 timerStarted = SUCCEEDED(vrc);
253 }
254 else
255 {
256 LogFlowFunc(("Last VirtualBox instance was released "
257 "on XPCOM shutdown.\n"));
258 Assert(onMainThread);
259 }
260
261 gAllowSigUsrQuit = PR_TRUE;
262
263 if (!timerStarted)
264 {
265 if (!onMainThread)
266 {
267 /* Failed to start the timer, post the shutdown event
268 * manually if not on the main thread already. */
269 ShutdownTimer(NULL, NULL, 0);
270 }
271 else
272 {
273 /* Here we come if:
274 *
275 * a) gEventQ is 0 which means either FactoryDestructor() is called
276 * or the IPC/DCONNECT shutdown sequence is initiated by the
277 * XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
278 * happens on the main thread.
279 *
280 * b) gEventQ has reported we're on the main thread. This means
281 * that DestructEventHandler() has been called, but another
282 * client was faster and requested VirtualBox again.
283 *
284 * In either case, there is nothing to do.
285 *
286 * Note: case b) is actually no more valid since we don't
287 * call Release() from DestructEventHandler() in this case
288 * any more. Thus, we assert below.
289 */
290
291 Assert(gEventQ == NULL);
292 }
293 }
294 }
295
296 return count;
297 }
298
299 class MaybeQuitEvent : public MyEvent
300 {
301 /* called on the main thread */
302 void *handler()
303 {
304 LogFlowFuncEnter();
305
306 Assert(RTCritSectIsInitialized(&sLock));
307
308 /* stop accepting GetInstance() requests on other threads during
309 * possible destruction */
310 RTCritSectEnter(&sLock);
311
312 nsrefcnt count = 0;
313
314 /* sInstance is NULL here if it was deleted immediately after
315 * creation due to initialization error. See GetInstance(). */
316 if (sInstance != NULL)
317 {
318 /* Release the guard reference added in GetInstance() */
319 count = sInstance->Release();
320 }
321
322 if (count == 0)
323 {
324 if (gAutoShutdown)
325 {
326 Assert(sInstance == NULL);
327 LogFlowFunc(("Terminating the server process...\n"));
328 /* make it leave the event loop */
329 gKeepRunning = PR_FALSE;
330 }
331 else
332 LogFlowFunc(("No automatic shutdown.\n"));
333 }
334 else
335 {
336 /* This condition is quite rare: a new client happened to
337 * connect after this event has been posted to the main queue
338 * but before it started to process it. */
339 LogFlowFunc(("Destruction is canceled (refcnt=%d).\n", count));
340 }
341
342 RTCritSectLeave(&sLock);
343
344 LogFlowFuncLeave();
345 return NULL;
346 }
347 };
348
349 static void ShutdownTimer(RTTIMERLR hTimerLR, void *pvUser, uint64_t /*iTick*/)
350 {
351 NOREF(hTimerLR);
352 NOREF(pvUser);
353
354 /* A "too late" event is theoretically possible if somebody
355 * manually ended the server after a destruction has been scheduled
356 * and this method was so lucky that it got a chance to run before
357 * the timer was killed. */
358 AssertReturnVoid(gEventQ);
359
360 /* post a quit event to the main queue */
361 MaybeQuitEvent *ev = new MaybeQuitEvent();
362 nsresult rv = ev->postTo(gEventQ);
363 NOREF(rv);
364
365 /* A failure above means we've been already stopped (for example
366 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
367 * will do the job. Nothing to do. */
368 }
369
370 static NS_IMETHODIMP FactoryConstructor()
371 {
372 LogFlowFunc(("\n"));
373
374 /* create a critsect to protect object construction */
375 if (RT_FAILURE(RTCritSectInit(&sLock)))
376 return NS_ERROR_OUT_OF_MEMORY;
377
378 int vrc = RTTimerLRCreateEx(&sTimer, 0, 0, ShutdownTimer, NULL);
379 if (RT_FAILURE(vrc))
380 {
381 LogFlowFunc(("Failed to create a timer! (vrc=%Rrc)\n", vrc));
382 return NS_ERROR_FAILURE;
383 }
384
385 return NS_OK;
386 }
387
388 static NS_IMETHODIMP FactoryDestructor()
389 {
390 LogFlowFunc(("\n"));
391
392 RTTimerLRDestroy(sTimer);
393 sTimer = NULL;
394
395 RTCritSectDelete(&sLock);
396
397 if (sInstance != NULL)
398 {
399 /* Either posting a destruction event failed for some reason (most
400 * likely, the quit event has been received before the last release),
401 * or the client has terminated abnormally w/o releasing its
402 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
403 * Release the guard reference we added in GetInstance(). */
404 sInstance->Release();
405 }
406
407 return NS_OK;
408 }
409
410 static nsresult GetInstance(VirtualBox **inst)
411 {
412 LogFlowFunc(("Getting VirtualBox object...\n"));
413
414 RTCritSectEnter(&sLock);
415
416 if (!gKeepRunning)
417 {
418 LogFlowFunc(("Process termination requested first. Refusing.\n"));
419
420 RTCritSectLeave(&sLock);
421
422 /* this rv is what CreateInstance() on the client side returns
423 * when the server process stops accepting events. Do the same
424 * here. The client wrapper should attempt to start a new process in
425 * response to a failure from us. */
426 return NS_ERROR_ABORT;
427 }
428
429 nsresult rv = NS_OK;
430
431 if (sInstance == NULL)
432 {
433 LogFlowFunc(("Creating new VirtualBox object...\n"));
434 sInstance = new VirtualBoxClassFactory();
435 if (sInstance != NULL)
436 {
437 /* make an extra AddRef to take the full control
438 * on the VirtualBox destruction (see FinalRelease()) */
439 sInstance->AddRef();
440
441 sInstance->AddRef(); /* protect FinalConstruct() */
442 rv = sInstance->FinalConstruct();
443 RTPrintf("Informational: VirtualBox object created (rc=%Rhrc).\n", rv);
444 if (NS_FAILED(rv))
445 {
446 /* On failure diring VirtualBox initialization, delete it
447 * immediately on the current thread by releasing all
448 * references in order to properly schedule the server
449 * shutdown. Since the object is fully deleted here, there
450 * is a chance to fix the error and request a new
451 * instantiation before the server terminates. However,
452 * the main reason to maintain the shutdown delay on
453 * failure is to let the front-end completely fetch error
454 * info from a server-side IVirtualBoxErrorInfo object. */
455 sInstance->Release();
456 sInstance->Release();
457 Assert(sInstance == NULL);
458 }
459 else
460 {
461 /* On success, make sure the previous timer is stopped to
462 * cancel a scheduled server termination (if any). */
463 gAllowSigUsrQuit = PR_FALSE;
464 RTTimerLRStop(sTimer);
465 }
466 }
467 else
468 {
469 rv = NS_ERROR_OUT_OF_MEMORY;
470 }
471 }
472 else
473 {
474 LogFlowFunc(("Using existing VirtualBox object...\n"));
475 nsrefcnt count = sInstance->AddRef();
476 Assert(count > 1);
477
478 if (count == 2)
479 {
480 LogFlowFunc(("Another client has requested a reference to VirtualBox, canceling destruction...\n"));
481
482 /* make sure the previous timer is stopped */
483 gAllowSigUsrQuit = PR_FALSE;
484 RTTimerLRStop(sTimer);
485 }
486 }
487
488 *inst = sInstance;
489
490 RTCritSectLeave(&sLock);
491
492 return rv;
493 }
494
495private:
496
497 /* Don't be confused that sInstance is of the *ClassFactory type. This is
498 * actually a singleton instance (*ClassFactory inherits the singleton
499 * class; we combined them just for "simplicity" and used "static" for
500 * factory methods. *ClassFactory here is necessary for a couple of extra
501 * methods. */
502
503 static VirtualBoxClassFactory *sInstance;
504 static RTCRITSECT sLock;
505
506 static RTTIMERLR sTimer;
507};
508
509VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = NULL;
510RTCRITSECT VirtualBoxClassFactory::sLock;
511
512RTTIMERLR VirtualBoxClassFactory::sTimer = NIL_RTTIMERLR;
513
514NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(VirtualBox, VirtualBoxClassFactory::GetInstance)
515
516////////////////////////////////////////////////////////////////////////////////
517
518typedef NSFactoryDestructorProcPtr NSFactoryConstructorProcPtr;
519
520/**
521 * Enhanced module component information structure.
522 *
523 * nsModuleComponentInfo lacks the factory construction callback, here we add
524 * it. This callback is called straight after a nsGenericFactory instance is
525 * successfully created in RegisterSelfComponents.
526 */
527struct nsModuleComponentInfoPlusFactoryConstructor
528{
529 /** standard module component information */
530 const nsModuleComponentInfo *mpModuleComponentInfo;
531 /** (optional) Factory Construction Callback */
532 NSFactoryConstructorProcPtr mFactoryConstructor;
533};
534
535/////////////////////////////////////////////////////////////////////////////
536
537/**
538 * Helper function to register self components upon start-up
539 * of the out-of-proc server.
540 */
541static nsresult
542RegisterSelfComponents(nsIComponentRegistrar *registrar,
543 const nsModuleComponentInfoPlusFactoryConstructor *aComponents,
544 PRUint32 count)
545{
546 nsresult rc = NS_OK;
547 const nsModuleComponentInfoPlusFactoryConstructor *info = aComponents;
548 for (PRUint32 i = 0; i < count && NS_SUCCEEDED(rc); i++, info++)
549 {
550 /* skip components w/o a constructor */
551 if (!info->mpModuleComponentInfo->mConstructor)
552 continue;
553 /* create a new generic factory for a component and register it */
554 nsIGenericFactory *factory;
555 rc = NS_NewGenericFactory(&factory, info->mpModuleComponentInfo);
556 if (NS_SUCCEEDED(rc) && info->mFactoryConstructor)
557 {
558 rc = info->mFactoryConstructor();
559 if (NS_FAILED(rc))
560 NS_RELEASE(factory);
561 }
562 if (NS_SUCCEEDED(rc))
563 {
564 rc = registrar->RegisterFactory(info->mpModuleComponentInfo->mCID,
565 info->mpModuleComponentInfo->mDescription,
566 info->mpModuleComponentInfo->mContractID,
567 factory);
568 NS_RELEASE(factory);
569 }
570 }
571 return rc;
572}
573
574/////////////////////////////////////////////////////////////////////////////
575
576static ipcIService *gIpcServ = nsnull;
577static const char *g_pszPidFile = NULL;
578
579class ForceQuitEvent : public MyEvent
580{
581 void *handler()
582 {
583 LogFlowFunc(("\n"));
584
585 gKeepRunning = PR_FALSE;
586
587 if (g_pszPidFile)
588 RTFileDelete(g_pszPidFile);
589
590 return NULL;
591 }
592};
593
594static void signal_handler(int sig)
595{
596 if (gEventQ && gKeepRunning)
597 {
598 if (sig == SIGUSR1)
599 {
600 if (gAllowSigUsrQuit)
601 {
602 VirtualBoxClassFactory::MaybeQuitEvent *ev = new VirtualBoxClassFactory::MaybeQuitEvent();
603 ev->postTo(gEventQ);
604 }
605 /* else do nothing */
606 }
607 else
608 {
609 /* post a force quit event to the queue */
610 ForceQuitEvent *ev = new ForceQuitEvent();
611 ev->postTo(gEventQ);
612 }
613 }
614}
615
616static nsresult vboxsvcSpawnDaemonByReExec(const char *pszPath, bool fAutoShutdown, const char *pszPidFile)
617{
618 PRFileDesc *readable = nsnull, *writable = nsnull;
619 PRProcessAttr *attr = nsnull;
620 nsresult rv = NS_ERROR_FAILURE;
621 PRFileDesc *devNull;
622 unsigned args_index = 0;
623 // The ugly casts are necessary because the PR_CreateProcessDetached has
624 // a const array of writable strings as a parameter. It won't write. */
625 char * args[1 + 1 + 2 + 1];
626 args[args_index++] = (char *)pszPath;
627 if (fAutoShutdown)
628 args[args_index++] = (char *)"--auto-shutdown";
629 if (pszPidFile)
630 {
631 args[args_index++] = (char *)"--pidfile";
632 args[args_index++] = (char *)pszPidFile;
633 }
634 args[args_index++] = 0;
635
636 // Use a pipe to determine when the daemon process is in the position
637 // to actually process requests. The daemon will write "READY" to the pipe.
638 if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
639 goto end;
640 PR_SetFDInheritable(writable, PR_TRUE);
641
642 attr = PR_NewProcessAttr();
643 if (!attr)
644 goto end;
645
646 if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
647 goto end;
648
649 devNull = PR_Open("/dev/null", PR_RDWR, 0);
650 if (!devNull)
651 goto end;
652
653 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
654 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
655 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
656
657 if (PR_CreateProcessDetached(pszPath, (char * const *)args, nsnull, attr) != PR_SUCCESS)
658 goto end;
659
660 // Close /dev/null
661 PR_Close(devNull);
662 // Close the child end of the pipe to make it the only owner of the
663 // file descriptor, so that unexpected closing can be detected.
664 PR_Close(writable);
665 writable = nsnull;
666
667 char msg[10];
668 memset(msg, '\0', sizeof(msg));
669 if ( PR_Read(readable, msg, sizeof(msg)-1) != 5
670 || strcmp(msg, "READY"))
671 goto end;
672
673 rv = NS_OK;
674
675end:
676 if (readable)
677 PR_Close(readable);
678 if (writable)
679 PR_Close(writable);
680 if (attr)
681 PR_DestroyProcessAttr(attr);
682 return rv;
683}
684
685int main(int argc, char **argv)
686{
687 /*
688 * Initialize the VBox runtime without loading
689 * the support driver
690 */
691 int vrc = RTR3InitExe(argc, &argv, 0);
692 if (RT_FAILURE(vrc))
693 return RTMsgInitFailure(vrc);
694
695 static const RTGETOPTDEF s_aOptions[] =
696 {
697 { "--automate", 'a', RTGETOPT_REQ_NOTHING },
698 { "--auto-shutdown", 'A', RTGETOPT_REQ_NOTHING },
699 { "--daemonize", 'd', RTGETOPT_REQ_NOTHING },
700 { "--shutdown-delay", 'D', RTGETOPT_REQ_UINT32 },
701 { "--pidfile", 'p', RTGETOPT_REQ_STRING },
702 { "--logfile", 'F', RTGETOPT_REQ_STRING },
703 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 },
704 { "--logsize", 'S', RTGETOPT_REQ_UINT64 },
705 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 }
706 };
707
708 const char *pszLogFile = NULL;
709 uint32_t cHistory = 10; // enable log rotation, 10 files
710 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
711 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
712 bool fDaemonize = false;
713 PRFileDesc *daemon_pipe_wr = nsnull;
714
715 RTGETOPTSTATE GetOptState;
716 vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
717 AssertRC(vrc);
718
719 RTGETOPTUNION ValueUnion;
720 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
721 {
722 switch (vrc)
723 {
724 case 'a':
725 /* --automate mode means we are started by XPCOM on
726 * demand. Daemonize ourselves and activate
727 * auto-shutdown. */
728 gAutoShutdown = true;
729 fDaemonize = true;
730 break;
731
732 case 'A':
733 /* --auto-shutdown mode means we're already daemonized. */
734 gAutoShutdown = true;
735 break;
736
737 case 'd':
738 fDaemonize = true;
739 break;
740
741 case 'D':
742 gShutdownDelayMs = ValueUnion.u32;
743 break;
744
745 case 'p':
746 g_pszPidFile = ValueUnion.psz;
747 break;
748
749 case 'F':
750 pszLogFile = ValueUnion.psz;
751 break;
752
753 case 'R':
754 cHistory = ValueUnion.u32;
755 break;
756
757 case 'S':
758 uHistoryFileSize = ValueUnion.u64;
759 break;
760
761 case 'I':
762 uHistoryFileTime = ValueUnion.u32;
763 break;
764
765 case 'h':
766 RTPrintf("no help\n");
767 return 1;
768
769 case 'V':
770 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
771 return 0;
772
773 default:
774 return RTGetOptPrintError(vrc, &ValueUnion);
775 }
776 }
777
778 if (fDaemonize)
779 {
780 vboxsvcSpawnDaemonByReExec(argv[0], gAutoShutdown, g_pszPidFile);
781 exit(126);
782 }
783
784 nsresult rc;
785
786 /** @todo Merge this code with svcmain.cpp (use Logging.cpp?). */
787 char szLogFile[RTPATH_MAX];
788 if (!pszLogFile)
789 {
790 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
791 if (RT_SUCCESS(vrc))
792 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
793 }
794 else
795 {
796 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
797 vrc = VERR_NO_MEMORY;
798 }
799 if (RT_FAILURE(vrc))
800 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
801
802 char szError[RTPATH_MAX + 128];
803 vrc = com::VBoxLogRelCreate("XPCOM Server", szLogFile,
804 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
805 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
806 RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
807 cHistory, uHistoryFileTime, uHistoryFileSize,
808 szError, sizeof(szError));
809 if (RT_FAILURE(vrc))
810 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", szError, vrc);
811
812 daemon_pipe_wr = PR_GetInheritedFD(VBOXSVC_STARTUP_PIPE_NAME);
813 RTEnvUnset("NSPR_INHERIT_FDS");
814
815 const nsModuleComponentInfo VirtualBoxInfo = {
816 "VirtualBox component",
817 NS_VIRTUALBOX_CID,
818 NS_VIRTUALBOX_CONTRACTID,
819 VirtualBoxConstructor, // constructor function
820 NULL, // registration function
821 NULL, // deregistration function
822 VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
823 NS_CI_INTERFACE_GETTER_NAME(VirtualBoxWrap),
824 NULL, // language helper
825 &NS_CLASSINFO_NAME(VirtualBoxWrap),
826 0 // flags
827 };
828
829 const nsModuleComponentInfoPlusFactoryConstructor components[] = {
830 {
831 &VirtualBoxInfo,
832 VirtualBoxClassFactory::FactoryConstructor // factory constructor function
833 }
834 };
835
836 do
837 {
838 rc = com::Initialize();
839 if (NS_FAILED(rc))
840 {
841 RTMsgError("Failed to initialize XPCOM! (rc=%Rhrc)\n", rc);
842 break;
843 }
844
845 nsCOMPtr<nsIComponentRegistrar> registrar;
846 rc = NS_GetComponentRegistrar(getter_AddRefs(registrar));
847 if (NS_FAILED(rc))
848 {
849 RTMsgError("Failed to get component registrar! (rc=%Rhrc)", rc);
850 break;
851 }
852
853 registrar->AutoRegister(nsnull);
854 rc = RegisterSelfComponents(registrar, components,
855 NS_ARRAY_LENGTH(components));
856 if (NS_FAILED(rc))
857 {
858 RTMsgError("Failed to register server components! (rc=%Rhrc)", rc);
859 break;
860 }
861
862 /* get the main thread's event queue (afaik, the dconnect service always
863 * gets created upon XPCOM startup, so it will use the main (this)
864 * thread's event queue to receive IPC events) */
865 rc = NS_GetMainEventQ(&gEventQ);
866 if (NS_FAILED(rc))
867 {
868 RTMsgError("Failed to get the main event queue! (rc=%Rhrc)", rc);
869 break;
870 }
871
872 nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rc));
873 if (NS_FAILED(rc))
874 {
875 RTMsgError("Failed to get IPC service! (rc=%Rhrc)", rc);
876 break;
877 }
878
879 NS_ADDREF(gIpcServ = ipcServ);
880
881 LogFlowFunc(("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
882
883 rc = gIpcServ->AddName(VBOXSVC_IPC_NAME);
884 if (NS_FAILED(rc))
885 {
886 LogFlowFunc(("Failed to register the server name (rc=%Rhrc (%08X))!\n"
887 "Is another server already running?\n", rc, rc));
888
889 RTMsgError("Failed to register the server name \"%s\" (rc=%Rhrc)!\n"
890 "Is another server already running?\n",
891 VBOXSVC_IPC_NAME, rc);
892 NS_RELEASE(gIpcServ);
893 break;
894 }
895
896 {
897 /* setup signal handling to convert some signals to a quit event */
898 struct sigaction sa;
899 sa.sa_handler = signal_handler;
900 sigemptyset(&sa.sa_mask);
901 sa.sa_flags = 0;
902 sigaction(SIGINT, &sa, NULL);
903 sigaction(SIGQUIT, &sa, NULL);
904 sigaction(SIGTERM, &sa, NULL);
905 sigaction(SIGTRAP, &sa, NULL);
906 sigaction(SIGUSR1, &sa, NULL);
907 }
908
909 {
910 char szBuf[80];
911 int iSize;
912
913 iSize = RTStrPrintf(szBuf, sizeof(szBuf),
914 VBOX_PRODUCT" XPCOM Server Version "
915 VBOX_VERSION_STRING);
916 for (int i = iSize; i > 0; i--)
917 putchar('*');
918 RTPrintf("\n%s\n", szBuf);
919 RTPrintf("(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
920 "All rights reserved.\n");
921#ifdef DEBUG
922 RTPrintf("Debug version.\n");
923#endif
924 }
925
926 if (daemon_pipe_wr != nsnull)
927 {
928 RTPrintf("\nStarting event loop....\n[send TERM signal to quit]\n");
929 /* now we're ready, signal the parent process */
930 PR_Write(daemon_pipe_wr, "READY", strlen("READY"));
931 /* close writing end of the pipe, its job is done */
932 PR_Close(daemon_pipe_wr);
933 }
934 else
935 RTPrintf("\nStarting event loop....\n[press Ctrl-C to quit]\n");
936
937 if (g_pszPidFile)
938 {
939 RTFILE hPidFile = NIL_RTFILE;
940 vrc = RTFileOpen(&hPidFile, g_pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
941 if (RT_SUCCESS(vrc))
942 {
943 char szBuf[32];
944 const char *lf = "\n";
945 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
946 RTFileWrite(hPidFile, szBuf, strlen(szBuf), NULL);
947 RTFileWrite(hPidFile, lf, strlen(lf), NULL);
948 RTFileClose(hPidFile);
949 }
950 }
951
952 // Increase the file table size to 10240 or as high as possible.
953 struct rlimit lim;
954 if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
955 {
956 if ( lim.rlim_cur < 10240
957 && lim.rlim_cur < lim.rlim_max)
958 {
959 lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
960 if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
961 RTPrintf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
962 }
963 }
964 else
965 RTPrintf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
966
967 PLEvent *ev;
968 while (gKeepRunning)
969 {
970 gEventQ->WaitForEvent(&ev);
971 gEventQ->HandleEvent(ev);
972 }
973
974 /* stop accepting new events. Clients that happen to resolve our
975 * name and issue a CreateInstance() request after this point will
976 * get NS_ERROR_ABORT once we handle the remaining messages. As a
977 * result, they should try to start a new server process. */
978 gEventQ->StopAcceptingEvents();
979
980 /* unregister ourselves. After this point, clients will start a new
981 * process because they won't be able to resolve the server name.*/
982 gIpcServ->RemoveName(VBOXSVC_IPC_NAME);
983
984 /* process any remaining events. These events may include
985 * CreateInstance() requests received right before we called
986 * StopAcceptingEvents() above, and those will fail. */
987 gEventQ->ProcessPendingEvents();
988
989 RTPrintf("Terminated event loop.\n");
990 }
991 while (0); // this scopes the nsCOMPtrs
992
993 NS_IF_RELEASE(gIpcServ);
994 NS_IF_RELEASE(gEventQ);
995
996 /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
997
998 LogFlowFunc(("Calling com::Shutdown()...\n"));
999 rc = com::Shutdown();
1000 LogFlowFunc(("Finished com::Shutdown() (rc=%Rhrc)\n", rc));
1001
1002 if (NS_FAILED(rc))
1003 RTMsgError("Failed to shutdown XPCOM! (rc=%Rhrc)", rc);
1004
1005 RTPrintf("XPCOM server has shutdown.\n");
1006
1007 if (g_pszPidFile)
1008 RTFileDelete(g_pszPidFile);
1009
1010 return 0;
1011}
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