VirtualBox

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

Last change on this file since 20630 was 20630, checked in by vboxsync, 15 years ago

Python: moved waiting on client side, removed main API for event waiting, as making no sense

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: server.cpp 20630 2009-06-16 13:55:38Z vboxsync $ */
2/** @file
3 * XPCOM server process (VBoxSVC) start point.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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/* Make sure all the stdint.h macros are included - must come first! */
23#ifndef __STDC_LIMIT_MACROS
24# define __STDC_LIMIT_MACROS
25#endif
26#ifndef __STDC_CONSTANT_MACROS
27# define __STDC_CONSTANT_MACROS
28#endif
29
30#include <ipcIService.h>
31#include <ipcCID.h>
32
33#include <nsIComponentRegistrar.h>
34
35#if defined(XPCOM_GLUE)
36#include <nsXPCOMGlue.h>
37#endif
38
39#include <nsEventQueueUtils.h>
40#include <nsGenericFactory.h>
41
42#include "xpcom/server.h"
43
44#include "Logging.h"
45
46#include <VBox/param.h>
47#include <VBox/version.h>
48
49#include <iprt/initterm.h>
50#include <iprt/path.h>
51#include <iprt/critsect.h>
52#include <iprt/timer.h>
53
54#include <stdio.h>
55
56// for the signal handler
57#include <signal.h>
58#include <stdlib.h>
59#include <unistd.h>
60#include <errno.h>
61#include <getopt.h>
62
63#ifndef RT_OS_OS2
64# include <sys/resource.h>
65#endif
66
67/////////////////////////////////////////////////////////////////////////////
68// VirtualBox component instantiation
69/////////////////////////////////////////////////////////////////////////////
70
71#include <nsIGenericFactory.h>
72
73#include <VirtualBox_XPCOM.h>
74#include <VirtualBoxImpl.h>
75#include <MachineImpl.h>
76#include <VFSExplorerImpl.h>
77#include <ApplianceImpl.h>
78#include <SnapshotImpl.h>
79#include <MediumImpl.h>
80#include <HardDiskImpl.h>
81#include <HardDiskFormatImpl.h>
82#include <ProgressImpl.h>
83#include <DVDDriveImpl.h>
84#include <FloppyDriveImpl.h>
85#include <VRDPServerImpl.h>
86#include <SharedFolderImpl.h>
87#include <HostImpl.h>
88#include <HostDVDDriveImpl.h>
89#include <HostFloppyDriveImpl.h>
90#include <HostNetworkInterfaceImpl.h>
91#include <GuestOSTypeImpl.h>
92#include <NetworkAdapterImpl.h>
93#include <SerialPortImpl.h>
94#include <ParallelPortImpl.h>
95#include <USBControllerImpl.h>
96#include "DHCPServerRunner.h"
97#include "DHCPServerImpl.h"
98#ifdef VBOX_WITH_USB
99# include <HostUSBDeviceImpl.h>
100# include <USBDeviceImpl.h>
101#endif
102#include <StorageControllerImpl.h>
103#include <AudioAdapterImpl.h>
104#include <SystemPropertiesImpl.h>
105
106/* implement nsISupports parts of our objects with support for nsIClassInfo */
107
108NS_DECL_CLASSINFO(VirtualBox)
109NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBox, IVirtualBox)
110
111NS_DECL_CLASSINFO(Machine)
112NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
113
114NS_DECL_CLASSINFO(VFSExplorer)
115NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer)
116
117NS_DECL_CLASSINFO(Appliance)
118NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Appliance, IAppliance)
119
120NS_DECL_CLASSINFO(VirtualSystemDescription)
121NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualSystemDescription, IVirtualSystemDescription)
122
123NS_DECL_CLASSINFO(SessionMachine)
124NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
125
126NS_DECL_CLASSINFO(SnapshotMachine)
127NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
128
129NS_DECL_CLASSINFO(Snapshot)
130NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
131
132NS_DECL_CLASSINFO(DVDImage)
133NS_IMPL_THREADSAFE_ISUPPORTS2_AMBIGUOUS_CI(DVDImage,
134 IMedium, ImageMediumBase,
135 IDVDImage, DVDImage)
136NS_DECL_CLASSINFO(FloppyImage)
137NS_IMPL_THREADSAFE_ISUPPORTS2_AMBIGUOUS_CI(FloppyImage,
138 IMedium, ImageMediumBase,
139 IFloppyImage, FloppyImage)
140
141NS_DECL_CLASSINFO(HardDisk)
142NS_IMPL_THREADSAFE_ISUPPORTS2_AMBIGUOUS_CI(HardDisk,
143 IMedium, MediumBase,
144 IHardDisk, HardDisk)
145
146NS_DECL_CLASSINFO(HardDiskFormat)
147NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskFormat, IHardDiskFormat)
148
149NS_DECL_CLASSINFO(HardDiskAttachment)
150NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskAttachment, IHardDiskAttachment)
151
152NS_DECL_CLASSINFO(Progress)
153NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
154
155NS_DECL_CLASSINFO(CombinedProgress)
156NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
157
158NS_DECL_CLASSINFO(DVDDrive)
159NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DVDDrive, IDVDDrive)
160
161NS_DECL_CLASSINFO(FloppyDrive)
162NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FloppyDrive, IFloppyDrive)
163
164NS_DECL_CLASSINFO(SharedFolder)
165NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
166
167#ifdef VBOX_WITH_VRDP
168NS_DECL_CLASSINFO(VRDPServer)
169NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPServer, IVRDPServer)
170#endif
171
172NS_DECL_CLASSINFO(Host)
173NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Host, IHost)
174
175NS_DECL_CLASSINFO(HostDVDDrive)
176NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostDVDDrive, IHostDVDDrive)
177
178NS_DECL_CLASSINFO(HostFloppyDrive)
179NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostFloppyDrive, IHostFloppyDrive)
180
181NS_DECL_CLASSINFO(HostNetworkInterface)
182NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostNetworkInterface, IHostNetworkInterface)
183
184NS_DECL_CLASSINFO(DHCPServer)
185NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DHCPServer, IDHCPServer)
186
187NS_DECL_CLASSINFO(GuestOSType)
188NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
189
190NS_DECL_CLASSINFO(NetworkAdapter)
191NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
192
193NS_DECL_CLASSINFO(SerialPort)
194NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SerialPort, ISerialPort)
195
196NS_DECL_CLASSINFO(ParallelPort)
197NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort)
198
199NS_DECL_CLASSINFO(USBController)
200NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
201
202NS_DECL_CLASSINFO(StorageController)
203NS_IMPL_THREADSAFE_ISUPPORTS1_CI(StorageController, IStorageController)
204
205#ifdef VBOX_WITH_USB
206NS_DECL_CLASSINFO(USBDeviceFilter)
207NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilter, IUSBDeviceFilter)
208
209NS_DECL_CLASSINFO(HostUSBDevice)
210NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDevice, IUSBDevice, IHostUSBDevice)
211
212NS_DECL_CLASSINFO(HostUSBDeviceFilter)
213NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDeviceFilter, IUSBDeviceFilter, IHostUSBDeviceFilter)
214#endif
215
216NS_DECL_CLASSINFO(AudioAdapter)
217NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AudioAdapter, IAudioAdapter)
218
219NS_DECL_CLASSINFO(SystemProperties)
220NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SystemProperties, ISystemProperties)
221
222#ifdef VBOX_WITH_RESOURCE_USAGE_API
223NS_DECL_CLASSINFO(PerformanceCollector)
224NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceCollector, IPerformanceCollector)
225NS_DECL_CLASSINFO(PerformanceMetric)
226NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceMetric, IPerformanceMetric)
227#endif /* VBOX_WITH_RESOURCE_USAGE_API */
228
229NS_DECL_CLASSINFO(BIOSSettings)
230NS_IMPL_THREADSAFE_ISUPPORTS1_CI(BIOSSettings, IBIOSSettings)
231
232////////////////////////////////////////////////////////////////////////////////
233
234enum
235{
236 /* Delay before shutting down the VirtualBox server after the last
237 * VirtualBox instance is released, in ms */
238 VBoxSVC_ShutdownDelay = 5000,
239};
240
241static bool gAutoShutdown = false;
242
243static nsIEventQueue* gEventQ = nsnull;
244static PRBool volatile gKeepRunning = PR_TRUE;
245
246/////////////////////////////////////////////////////////////////////////////
247
248/**
249 * Simple but smart PLEvent wrapper.
250 *
251 * @note Instances must be always created with <tt>operator new</tt>!
252 */
253class MyEvent
254{
255public:
256
257 MyEvent()
258 {
259 mEv.that = NULL;
260 };
261
262 /**
263 * Posts this event to the given message queue. This method may only be
264 * called once. @note On success, the event will be deleted automatically
265 * after it is delivered and handled. On failure, the event will delete
266 * itself before this method returns! The caller must not delete it in
267 * either case.
268 */
269 nsresult postTo (nsIEventQueue *aEventQ)
270 {
271 AssertReturn (mEv.that == NULL, NS_ERROR_FAILURE);
272 AssertReturn (aEventQ, NS_ERROR_FAILURE);
273 nsresult rv = aEventQ->InitEvent (&mEv.e, NULL,
274 eventHandler, eventDestructor);
275 if (NS_SUCCEEDED (rv))
276 {
277 mEv.that = this;
278 rv = aEventQ->PostEvent (&mEv.e);
279 if (NS_SUCCEEDED (rv))
280 return rv;
281 }
282 delete this;
283 return rv;
284 }
285
286 virtual void *handler() = 0;
287
288private:
289
290 struct Ev
291 {
292 PLEvent e;
293 MyEvent *that;
294 } mEv;
295
296 static void *PR_CALLBACK eventHandler (PLEvent *self)
297 {
298 return reinterpret_cast <Ev *> (self)->that->handler();
299 }
300
301 static void PR_CALLBACK eventDestructor (PLEvent *self)
302 {
303 delete reinterpret_cast <Ev *> (self)->that;
304 }
305};
306
307////////////////////////////////////////////////////////////////////////////////
308
309/**
310 * VirtualBox class factory that destroys the created instance right after
311 * the last reference to it is released by the client, and recreates it again
312 * when necessary (so VirtualBox acts like a singleton object).
313 */
314class VirtualBoxClassFactory : public VirtualBox
315{
316public:
317
318 virtual ~VirtualBoxClassFactory()
319 {
320 LogFlowFunc (("Deleting VirtualBox...\n"));
321
322 FinalRelease();
323 sInstance = NULL;
324
325 LogFlowFunc (("VirtualBox object deleted.\n"));
326 printf ("Informational: VirtualBox object deleted.\n");
327 }
328
329 NS_IMETHOD_(nsrefcnt) Release()
330 {
331 /* we overload Release() to guarantee the VirtualBox destructor is
332 * always called on the main thread */
333
334 nsrefcnt count = VirtualBox::Release();
335
336 if (count == 1)
337 {
338 /* the last reference held by clients is being released
339 * (see GetInstance()) */
340
341 PRBool onMainThread = PR_TRUE;
342 if (gEventQ)
343 gEventQ->IsOnCurrentThread (&onMainThread);
344
345 PRBool timerStarted = PR_FALSE;
346
347 /* sTimer is null if this call originates from FactoryDestructor()*/
348 if (sTimer != NULL)
349 {
350 LogFlowFunc (("Last VirtualBox instance was released.\n"));
351 LogFlowFunc (("Scheduling server shutdown in %d ms...\n",
352 VBoxSVC_ShutdownDelay));
353
354 /* make sure the previous timer (if any) is stopped;
355 * otherwise RTTimerStart() will definitely fail. */
356 RTTimerLRStop (sTimer);
357
358 int vrc = RTTimerLRStart (sTimer, uint64_t (VBoxSVC_ShutdownDelay) * 1000000);
359 AssertRC (vrc);
360 timerStarted = SUCCEEDED (vrc);
361 }
362 else
363 {
364 LogFlowFunc (("Last VirtualBox instance was released "
365 "on XPCOM shutdown.\n"));
366 Assert (onMainThread);
367 }
368
369 if (!timerStarted)
370 {
371 if (!onMainThread)
372 {
373 /* Failed to start the timer, post the shutdown event
374 * manually if not on the main thread alreay. */
375 ShutdownTimer (NULL, NULL, 0);
376 }
377 else
378 {
379 /* Here we come if:
380 *
381 * a) gEventQ is 0 which means either FactoryDestructor() is called
382 * or the IPC/DCONNECT shutdown sequence is initiated by the
383 * XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
384 * happens on the main thread.
385 *
386 * b) gEventQ has reported we're on the main thread. This means
387 * that DestructEventHandler() has been called, but another
388 * client was faster and requested VirtualBox again.
389 *
390 * In either case, there is nothing to do.
391 *
392 * Note: case b) is actually no more valid since we don't
393 * call Release() from DestructEventHandler() in this case
394 * any more. Thus, we assert below.
395 */
396
397 Assert (gEventQ == NULL);
398 }
399 }
400 }
401
402 return count;
403 }
404
405 class MaybeQuitEvent : public MyEvent
406 {
407 /* called on the main thread */
408 void *handler()
409 {
410 LogFlowFunc (("\n"));
411
412 Assert (RTCritSectIsInitialized (&sLock));
413
414 /* stop accepting GetInstance() requests on other threads during
415 * possible destruction */
416 RTCritSectEnter (&sLock);
417
418 nsrefcnt count = 0;
419
420 /* sInstance is NULL here if it was deleted immediately after
421 * creation due to initialization error. See GetInstance(). */
422 if (sInstance != NULL)
423 {
424 /* Release the guard reference added in GetInstance() */
425 count = sInstance->Release();
426 }
427
428 if (count == 0)
429 {
430 if (gAutoShutdown)
431 {
432 Assert (sInstance == NULL);
433 LogFlowFunc (("Terminating the server process...\n"));
434 /* make it leave the event loop */
435 gKeepRunning = PR_FALSE;
436 }
437 }
438 else
439 {
440 /* This condition is quite rare: a new client happened to
441 * connect after this event has been posted to the main queue
442 * but before it started to process it. */
443 LogFlowFunc (("Destruction is canceled (refcnt=%d).\n", count));
444 }
445
446 RTCritSectLeave (&sLock);
447
448 return NULL;
449 }
450 };
451
452 static void ShutdownTimer (RTTIMERLR hTimerLR, void *pvUser, uint64_t /*iTick*/)
453 {
454 NOREF (hTimerLR);
455 NOREF (pvUser);
456
457 /* A "too late" event is theoretically possible if somebody
458 * manually ended the server after a destruction has been scheduled
459 * and this method was so lucky that it got a chance to run before
460 * the timer was killed. */
461 AssertReturnVoid (gEventQ);
462
463 /* post a quit event to the main queue */
464 MaybeQuitEvent *ev = new MaybeQuitEvent();
465 nsresult rv = ev->postTo (gEventQ);
466 NOREF (rv);
467
468 /* A failure above means we've been already stopped (for example
469 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
470 * will do the job. Nothing to do. */
471 }
472
473 static NS_IMETHODIMP FactoryConstructor()
474 {
475 LogFlowFunc (("\n"));
476
477 /* create a critsect to protect object construction */
478 if (RT_FAILURE (RTCritSectInit (&sLock)))
479 return NS_ERROR_OUT_OF_MEMORY;
480
481 int vrc = RTTimerLRCreateEx (&sTimer, 0, 0, ShutdownTimer, NULL);
482 if (RT_FAILURE (vrc))
483 {
484 LogFlowFunc (("Failed to create a timer! (vrc=%Rrc)\n", vrc));
485 return NS_ERROR_FAILURE;
486 }
487
488 return NS_OK;
489 }
490
491 static NS_IMETHODIMP FactoryDestructor()
492 {
493 LogFlowFunc (("\n"));
494
495 RTTimerLRDestroy (sTimer);
496 sTimer = NULL;
497
498 RTCritSectDelete (&sLock);
499
500 if (sInstance != NULL)
501 {
502 /* Either posting a destruction event falied for some reason (most
503 * likely, the quit event has been received before the last release),
504 * or the client has terminated abnormally w/o releasing its
505 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
506 * Release the guard reference we added in GetInstance(). */
507 sInstance->Release();
508 }
509
510 return NS_OK;
511 }
512
513 static nsresult GetInstance (VirtualBox **inst)
514 {
515 LogFlowFunc (("Getting VirtualBox object...\n"));
516
517 RTCritSectEnter (&sLock);
518
519 if (!gKeepRunning)
520 {
521 LogFlowFunc (("Process termination requested first. Refusing.\n"));
522
523 RTCritSectLeave (&sLock);
524
525 /* this rv is what CreateInstance() on the client side returns
526 * when the server process stops accepting events. Do the same
527 * here. The client wrapper should attempt to start a new process in
528 * response to a failure from us. */
529 return NS_ERROR_ABORT;
530 }
531
532 nsresult rv = NS_OK;
533
534 if (sInstance == NULL)
535 {
536 LogFlowFunc (("Creating new VirtualBox object...\n"));
537 sInstance = new VirtualBoxClassFactory();
538 if (sInstance != NULL)
539 {
540 /* make an extra AddRef to take the full control
541 * on the VirtualBox destruction (see FinalRelease()) */
542 sInstance->AddRef();
543
544 sInstance->AddRef(); /* protect FinalConstruct() */
545 rv = sInstance->FinalConstruct();
546 printf ("Informational: VirtualBox object created (rc=%08X).\n", rv);
547 if (NS_FAILED (rv))
548 {
549 /* On failure diring VirtualBox initialization, delete it
550 * immediately on the current thread by releasing all
551 * references in order to properly schedule the server
552 * shutdown. Since the object is fully deleted here, there
553 * is a chance to fix the error and request a new
554 * instantiation before the server terminates. However,
555 * the main reason to maintain the shoutdown delay on
556 * failure is to let the front-end completely fetch error
557 * info from a server-side IVirtualBoxErrorInfo object. */
558 sInstance->Release();
559 sInstance->Release();
560 Assert (sInstance == NULL);
561 }
562 else
563 {
564 /* On success, make sure the previous timer is stopped to
565 * cancel a scheduled server termination (if any). */
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, "
583 "canceling detruction...\n"));
584
585 /* make sure the previous timer is stopped */
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 = {0};
613
614RTTIMERLR VirtualBoxClassFactory::sTimer = NIL_RTTIMERLR;
615
616NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC
617 (VirtualBox, VirtualBoxClassFactory::GetInstance)
618
619////////////////////////////////////////////////////////////////////////////////
620
621typedef NSFactoryDestructorProcPtr NSFactoryConsructorProcPtr;
622
623/**
624 * Enhanced module component information structure.
625 *
626 * nsModuleComponentInfo lacks the factory construction callback, here we add
627 * it. This callback is called by NS_NewGenericFactoryEx() after a
628 * nsGenericFactory instance is successfully created.
629 */
630struct nsModuleComponentInfoEx : nsModuleComponentInfo
631{
632 nsModuleComponentInfoEx () {}
633 nsModuleComponentInfoEx (int) {}
634
635 nsModuleComponentInfoEx (
636 const char* aDescription,
637 const nsCID& aCID,
638 const char* aContractID,
639 NSConstructorProcPtr aConstructor,
640 NSRegisterSelfProcPtr aRegisterSelfProc,
641 NSUnregisterSelfProcPtr aUnregisterSelfProc,
642 NSFactoryDestructorProcPtr aFactoryDestructor,
643 NSGetInterfacesProcPtr aGetInterfacesProc,
644 NSGetLanguageHelperProcPtr aGetLanguageHelperProc,
645 nsIClassInfo ** aClassInfoGlobal,
646 PRUint32 aFlags,
647 NSFactoryConsructorProcPtr aFactoryConstructor)
648 {
649 mDescription = aDescription;
650 mCID = aCID;
651 mContractID = aContractID;
652 mConstructor = aConstructor;
653 mRegisterSelfProc = aRegisterSelfProc;
654 mUnregisterSelfProc = aUnregisterSelfProc;
655 mFactoryDestructor = aFactoryDestructor;
656 mGetInterfacesProc = aGetInterfacesProc;
657 mGetLanguageHelperProc = aGetLanguageHelperProc;
658 mClassInfoGlobal = aClassInfoGlobal;
659 mFlags = aFlags;
660 mFactoryConstructor = aFactoryConstructor;
661 }
662
663 /** (optional) Factory Construction Callback */
664 NSFactoryConsructorProcPtr mFactoryConstructor;
665};
666
667////////////////////////////////////////////////////////////////////////////////
668
669static const nsModuleComponentInfoEx components[] =
670{
671 nsModuleComponentInfoEx (
672 "VirtualBox component",
673 (nsCID) NS_VIRTUALBOX_CID,
674 NS_VIRTUALBOX_CONTRACTID,
675 VirtualBoxConstructor, // constructor funcion
676 NULL, // registration function
677 NULL, // deregistration function
678 VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
679 NS_CI_INTERFACE_GETTER_NAME(VirtualBox),
680 NULL, // language helper
681 &NS_CLASSINFO_NAME(VirtualBox),
682 0, // flags
683 VirtualBoxClassFactory::FactoryConstructor // factory constructor function
684 )
685};
686
687/////////////////////////////////////////////////////////////////////////////
688
689/**
690 * Extends NS_NewGenericFactory() by immediately calling
691 * nsModuleComponentInfoEx::mFactoryConstructor before returning to the
692 * caller.
693 */
694nsresult
695NS_NewGenericFactoryEx (nsIGenericFactory **result,
696 const nsModuleComponentInfoEx *info)
697{
698 AssertReturn (result, NS_ERROR_INVALID_POINTER);
699
700 nsresult rv = NS_NewGenericFactory (result, info);
701 if (NS_SUCCEEDED (rv) && info && info->mFactoryConstructor)
702 {
703 rv = info->mFactoryConstructor();
704 if (NS_FAILED (rv))
705 NS_RELEASE (*result);
706 }
707
708 return rv;
709}
710
711/////////////////////////////////////////////////////////////////////////////
712
713/**
714 * Helper function to register self components upon start-up
715 * of the out-of-proc server.
716 */
717static nsresult
718RegisterSelfComponents (nsIComponentRegistrar *registrar,
719 const nsModuleComponentInfoEx *components,
720 PRUint32 count)
721{
722 nsresult rc = NS_OK;
723 const nsModuleComponentInfoEx *info = components;
724 for (PRUint32 i = 0; i < count && NS_SUCCEEDED (rc); i++, info++)
725 {
726 /* skip components w/o a constructor */
727 if (!info->mConstructor) 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 char *pszPidFile = NULL;
747
748class ForceQuitEvent : public MyEvent
749{
750 void *handler()
751 {
752 LogFlowFunc (("\n"));
753
754 gKeepRunning = PR_FALSE;
755
756 if (pszPidFile)
757 RTFileDelete(pszPidFile);
758
759 return NULL;
760 }
761};
762
763static void signal_handler (int /* sig */)
764{
765 if (gEventQ && gKeepRunning)
766 {
767 /* post a quit event to the queue */
768 ForceQuitEvent *ev = new ForceQuitEvent();
769 ev->postTo (gEventQ);
770 }
771}
772
773int main (int argc, char **argv)
774{
775 const struct option options[] =
776 {
777 { "automate", no_argument, NULL, 'a' },
778# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
779 { "auto-shutdown", no_argument, NULL, 'A' },
780#endif
781 { "daemonize", no_argument, NULL, 'd' },
782 { "pidfile", required_argument, NULL, 'p' },
783# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
784 { "pipe", required_argument, NULL, 'P' },
785#endif
786 { NULL, 0, NULL, 0 }
787 };
788 int c;
789
790 bool fDaemonize = false;
791#ifndef RT_OS_OS2
792 static int daemon_pipe_fds[2] = {-1, -1};
793#endif
794
795 for (;;)
796 {
797 c = getopt_long(argc, argv, "", options, NULL);
798 if (c == -1)
799 break;
800 switch (c)
801 {
802 case 'a':
803 {
804 /* --automate mode means we are started by XPCOM on
805 * demand. Daemonize ourselves and activate
806 * auto-shutdown. */
807 gAutoShutdown = true;
808 fDaemonize = true;
809 break;
810 }
811
812# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
813 /* Used together with '-P', see below. Internal use only. */
814 case 'A':
815 {
816 gAutoShutdown = true;
817 break;
818 }
819#endif
820
821 case 'd':
822 {
823 fDaemonize = true;
824 break;
825 }
826
827 case 'p':
828 {
829 pszPidFile = optarg;
830 break;
831 }
832
833# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
834 /* we need to exec on darwin, this is just an internal
835 * hack for passing the pipe fd along to the final child. */
836 case 'P':
837 {
838 daemon_pipe_fds[1] = atoi(optarg);
839 break;
840 }
841#endif
842
843 default:
844 {
845 /* exit on invalid options */
846 return 1;
847 }
848 }
849 }
850
851 static RTFILE pidFile = NIL_RTFILE;
852
853#ifdef RT_OS_OS2
854
855 /* nothing to do here, the process is supposed to be already
856 * started daemonized when it is necessary */
857 NOREF(fDaemonize);
858
859#else // ifdef RT_OS_OS2
860
861 if (fDaemonize)
862 {
863 /* create a pipe for communication between child and parent */
864 if (pipe(daemon_pipe_fds) < 0)
865 {
866 printf("ERROR: pipe() failed (errno = %d)\n", errno);
867 return 1;
868 }
869
870 pid_t childpid = fork();
871 if (childpid == -1)
872 {
873 printf("ERROR: fork() failed (errno = %d)\n", errno);
874 return 1;
875 }
876
877 if (childpid != 0)
878 {
879 /* we're the parent process */
880 bool fSuccess = false;
881
882 /* close the writing end of the pipe */
883 close(daemon_pipe_fds[1]);
884
885 /* try to read a message from the pipe */
886 char msg[10] = {0}; /* initialize so it's NULL terminated */
887 if (read(daemon_pipe_fds[0], msg, sizeof(msg)) > 0)
888 {
889 if (strcmp(msg, "READY") == 0)
890 fSuccess = true;
891 else
892 printf ("ERROR: Unknown message from child "
893 "process (%s)\n", msg);
894 }
895 else
896 printf ("ERROR: 0 bytes read from child process\n");
897
898 /* close the reading end of the pipe as well and exit */
899 close(daemon_pipe_fds[0]);
900 return fSuccess ? 0 : 1;
901 }
902 /* we're the child process */
903
904 /* Create a new SID for the child process */
905 pid_t sid = setsid();
906 if (sid < 0)
907 {
908 printf("ERROR: setsid() failed (errno = %d)\n", errno);
909 return 1;
910 }
911
912 /* Need to do another for to get rid of the session leader status.
913 * Otherwise any accidentally opened tty will automatically become a
914 * controlling tty for the daemon process. */
915 childpid = fork();
916 if (childpid == -1)
917 {
918 printf("ERROR: second fork() failed (errno = %d)\n", errno);
919 return 1;
920 }
921
922 if (childpid != 0)
923 {
924 /* we're the parent process, just a dummy so terminate now */
925 exit(0);
926 }
927
928 /* Redirect standard i/o streams to /dev/null */
929 if (daemon_pipe_fds[0] > 2)
930 {
931 freopen ("/dev/null", "r", stdin);
932 freopen ("/dev/null", "w", stdout);
933 freopen ("/dev/null", "w", stderr);
934 }
935
936 /* close the reading end of the pipe */
937 close(daemon_pipe_fds[0]);
938
939# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
940 /*
941 * On leopard we're no longer allowed to use some of the core API's
942 * after forking - this will cause us to hit an int3.
943 * So, we'll have to execv VBoxSVC once again and hand it the pipe
944 * and all other relevant options.
945 *
946 * On FreeBSD the fork approach doesn't work. The child fails
947 * during initialization of XPCOM for some unknown reason and
948 * exits making it impossible to autostart VBoxSVC when starting
949 * a frontend (debugger and strace don't contain any useful info).
950 */
951 const char *apszArgs[7];
952 unsigned i = 0;
953 apszArgs[i++] = argv[0];
954 apszArgs[i++] = "--pipe";
955 char szPipeArg[32];
956 RTStrPrintf (szPipeArg, sizeof (szPipeArg), "%d", daemon_pipe_fds[1]);
957 apszArgs[i++] = szPipeArg;
958 if (pszPidFile)
959 {
960 apszArgs[i++] = "--pidfile";
961 apszArgs[i++] = pszPidFile;
962 }
963 if (gAutoShutdown)
964 apszArgs[i++] = "--auto-shutdown";
965 apszArgs[i++] = NULL; Assert(i <= RT_ELEMENTS(apszArgs));
966 execv (apszArgs[0], (char * const *)apszArgs);
967 exit (0);
968# endif
969 }
970
971#endif // ifdef RT_OS_OS2
972
973 /*
974 * Initialize the VBox runtime without loading
975 * the support driver
976 */
977 RTR3Init();
978
979 nsresult rc;
980
981 do
982 {
983 rc = com::Initialize();
984 if (NS_FAILED (rc))
985 {
986 printf ("ERROR: Failed to initialize XPCOM! (rc=%08X)\n", rc);
987 break;
988 }
989
990 nsCOMPtr <nsIComponentRegistrar> registrar;
991 rc = NS_GetComponentRegistrar (getter_AddRefs (registrar));
992 if (NS_FAILED (rc))
993 {
994 printf ("ERROR: Failed to get component registrar! (rc=%08X)\n", rc);
995 break;
996 }
997
998 registrar->AutoRegister (nsnull);
999 rc = RegisterSelfComponents (registrar, components,
1000 NS_ARRAY_LENGTH (components));
1001 if (NS_FAILED (rc))
1002 {
1003 printf ("ERROR: Failed to register server components! (rc=%08X)\n", rc);
1004 break;
1005 }
1006
1007 /* get the main thread's event queue (afaik, the dconnect service always
1008 * gets created upon XPCOM startup, so it will use the main (this)
1009 * thread's event queue to receive IPC events) */
1010 rc = NS_GetMainEventQ (&gEventQ);
1011 if (NS_FAILED (rc))
1012 {
1013 printf ("ERROR: Failed to get the main event queue! (rc=%08X)\n", rc);
1014 break;
1015 }
1016
1017 nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1018 if (NS_FAILED (rc))
1019 {
1020 printf ("ERROR: Failed to get IPC service! (rc=%08X)\n", rc);
1021 break;
1022 }
1023
1024 NS_ADDREF (gIpcServ = ipcServ);
1025
1026 LogFlowFunc (("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1027
1028 rc = gIpcServ->AddName (VBOXSVC_IPC_NAME);
1029 if (NS_FAILED (rc))
1030 {
1031 LogFlowFunc (("Failed to register the server name (rc=%08X)!\n"
1032 "Is another server already running?\n", rc));
1033
1034 printf ("ERROR: Failed to register the server name \"%s\" (rc=%08X)!\n"
1035 "Is another server already running?\n",
1036 VBOXSVC_IPC_NAME, rc);
1037 NS_RELEASE (gIpcServ);
1038 break;
1039 }
1040
1041 {
1042 /* setup signal handling to convert some signals to a quit event */
1043 struct sigaction sa;
1044 sa.sa_handler = signal_handler;
1045 sigemptyset (&sa.sa_mask);
1046 sa.sa_flags = 0;
1047 sigaction (SIGINT, &sa, NULL);
1048 sigaction (SIGQUIT, &sa, NULL);
1049 sigaction (SIGTERM, &sa, NULL);
1050 sigaction (SIGTRAP, &sa, NULL);
1051 }
1052
1053 {
1054 char szBuf[80];
1055 int iSize;
1056
1057 iSize = snprintf (szBuf, sizeof(szBuf),
1058 "Sun VirtualBox XPCOM Server Version "
1059 VBOX_VERSION_STRING);
1060 for (int i=iSize; i>0; i--)
1061 putchar('*');
1062 printf ("\n%s\n", szBuf);
1063 printf ("(C) 2008-2009 Sun Microsystems, Inc.\n"
1064 "All rights reserved.\n");
1065#ifdef DEBUG
1066 printf ("Debug version.\n");
1067#endif
1068#if 0
1069 /* in my opinion two lines enclosing the text look better */
1070 for (int i=iSize; i>0; i--)
1071 putchar('*');
1072 putchar('\n');
1073#endif
1074 }
1075
1076#ifndef RT_OS_OS2
1077 if (daemon_pipe_fds[1] >= 0)
1078 {
1079 printf ("\nStarting event loop....\n[send TERM signal to quit]\n");
1080 /* now we're ready, signal the parent process */
1081 write(daemon_pipe_fds[1], "READY", strlen("READY"));
1082 }
1083 else
1084#endif
1085 {
1086 printf ("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1087 }
1088
1089 if (pszPidFile)
1090 {
1091 char szBuf[32];
1092 const char *lf = "\n";
1093 RTFileOpen(&pidFile, pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE);
1094 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1095 RTFileWrite(pidFile, szBuf, strlen(szBuf), NULL);
1096 RTFileWrite(pidFile, lf, strlen(lf), NULL);
1097 RTFileClose(pidFile);
1098 }
1099
1100#ifndef RT_OS_OS2
1101 // Increase the file table size to 10240 or as high as possible.
1102 struct rlimit lim;
1103 if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
1104 {
1105 if ( lim.rlim_cur < 10240
1106 && lim.rlim_cur < lim.rlim_max)
1107 {
1108 lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
1109 if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
1110 printf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
1111 }
1112 }
1113 else
1114 printf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
1115#endif
1116
1117 PLEvent *ev;
1118 while (gKeepRunning)
1119 {
1120 gEventQ->WaitForEvent (&ev);
1121 gEventQ->HandleEvent (ev);
1122 }
1123
1124 /* stop accepting new events. Clients that happen to resolve our
1125 * name and issue a CreateInstance() request after this point will
1126 * get NS_ERROR_ABORT once we hande the remaining messages. As a
1127 * result, they should try to start a new server process. */
1128 gEventQ->StopAcceptingEvents();
1129
1130 /* unregister ourselves. After this point, clients will start a new
1131 * process because they won't be able to resolve the server name.*/
1132 gIpcServ->RemoveName (VBOXSVC_IPC_NAME);
1133
1134 /* process any remaining events. These events may include
1135 * CreateInstance() requests received right before we called
1136 * StopAcceptingEvents() above. We will detect this case below,
1137 * restore gKeepRunning and continue to serve. */
1138 gEventQ->ProcessPendingEvents();
1139
1140 printf ("Terminated event loop.\n");
1141 }
1142 while (0); // this scopes the nsCOMPtrs
1143
1144 NS_IF_RELEASE (gIpcServ);
1145 NS_IF_RELEASE (gEventQ);
1146
1147 /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
1148
1149 LogFlowFunc (("Calling com::Shutdown()...\n"));
1150 rc = com::Shutdown();
1151 LogFlowFunc (("Finished com::Shutdown() (rc=%08X)\n", rc));
1152
1153 if (NS_FAILED (rc))
1154 printf ("ERROR: Failed to shutdown XPCOM! (rc=%08X)\n", rc);
1155
1156 printf ("XPCOM server has shutdown.\n");
1157
1158 if (pszPidFile)
1159 {
1160 RTFileDelete(pszPidFile);
1161 }
1162
1163#ifndef RT_OS_OS2
1164 if (daemon_pipe_fds[1] >= 0)
1165 {
1166 /* close writing end of the pipe as well */
1167 close(daemon_pipe_fds[1]);
1168 }
1169#endif
1170
1171 return 0;
1172}
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