VirtualBox

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

Last change on this file since 35972 was 35972, checked in by vboxsync, 14 years ago

Build fix for Mac.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette