VirtualBox

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

Last change on this file since 19222 was 19222, checked in by vboxsync, 16 years ago

Main: remove debugging signal handler from VBoxSVC that prevented it from dumping core

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