VirtualBox

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

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

Main/FreeBSD: Use the same approach as on Darwin for daemonizing VBoxSVC. The fork approach doesn not work. The second child fails for some unknown reason when initializing XPCOM and the debugger or strace do not contain any information

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.4 KB
Line 
1/* $Id: server.cpp 19296 2009-05-01 16:56:44Z 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# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
775 { "auto-shutdown", no_argument, NULL, 'A' },
776#endif
777 { "daemonize", no_argument, NULL, 'd' },
778 { "pidfile", required_argument, NULL, 'p' },
779# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
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# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
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# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
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# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
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 * On FreeBSD the fork approach doesn't work. The child fails
943 * during initialization of XPCOM for some unknown reason and
944 * exits making it impossible to autostart VBoxSVC when starting
945 * a frontend (debugger and strace don't contain any useful info).
946 */
947 const char *apszArgs[7];
948 unsigned i = 0;
949 apszArgs[i++] = argv[0];
950 apszArgs[i++] = "--pipe";
951 char szPipeArg[32];
952 RTStrPrintf (szPipeArg, sizeof (szPipeArg), "%d", daemon_pipe_fds[1]);
953 apszArgs[i++] = szPipeArg;
954 if (pszPidFile)
955 {
956 apszArgs[i++] = "--pidfile";
957 apszArgs[i++] = pszPidFile;
958 }
959 if (gAutoShutdown)
960 apszArgs[i++] = "--auto-shutdown";
961 apszArgs[i++] = NULL; Assert(i <= RT_ELEMENTS(apszArgs));
962 execv (apszArgs[0], (char * const *)apszArgs);
963 exit (0);
964# endif
965 }
966
967#endif // ifdef RT_OS_OS2
968
969 /*
970 * Initialize the VBox runtime without loading
971 * the support driver
972 */
973 RTR3Init();
974
975 nsresult rc;
976
977 do
978 {
979 rc = com::Initialize();
980 if (NS_FAILED (rc))
981 {
982 printf ("ERROR: Failed to initialize XPCOM! (rc=%08X)\n", rc);
983 break;
984 }
985
986 nsCOMPtr <nsIComponentRegistrar> registrar;
987 rc = NS_GetComponentRegistrar (getter_AddRefs (registrar));
988 if (NS_FAILED (rc))
989 {
990 printf ("ERROR: Failed to get component registrar! (rc=%08X)\n", rc);
991 break;
992 }
993
994 registrar->AutoRegister (nsnull);
995 rc = RegisterSelfComponents (registrar, components,
996 NS_ARRAY_LENGTH (components));
997 if (NS_FAILED (rc))
998 {
999 printf ("ERROR: Failed to register server components! (rc=%08X)\n", rc);
1000 break;
1001 }
1002
1003 /* get the main thread's event queue (afaik, the dconnect service always
1004 * gets created upon XPCOM startup, so it will use the main (this)
1005 * thread's event queue to receive IPC events) */
1006 rc = NS_GetMainEventQ (&gEventQ);
1007 if (NS_FAILED (rc))
1008 {
1009 printf ("ERROR: Failed to get the main event queue! (rc=%08X)\n", rc);
1010 break;
1011 }
1012
1013 nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1014 if (NS_FAILED (rc))
1015 {
1016 printf ("ERROR: Failed to get IPC service! (rc=%08X)\n", rc);
1017 break;
1018 }
1019
1020 NS_ADDREF (gIpcServ = ipcServ);
1021
1022 LogFlowFunc (("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1023
1024 rc = gIpcServ->AddName (VBOXSVC_IPC_NAME);
1025 if (NS_FAILED (rc))
1026 {
1027 LogFlowFunc (("Failed to register the server name (rc=%08X)!\n"
1028 "Is another server already running?\n", rc));
1029
1030 printf ("ERROR: Failed to register the server name \"%s\" (rc=%08X)!\n"
1031 "Is another server already running?\n",
1032 VBOXSVC_IPC_NAME, rc);
1033 NS_RELEASE (gIpcServ);
1034 break;
1035 }
1036
1037 {
1038 /* setup signal handling to convert some signals to a quit event */
1039 struct sigaction sa;
1040 sa.sa_handler = signal_handler;
1041 sigemptyset (&sa.sa_mask);
1042 sa.sa_flags = 0;
1043 sigaction (SIGINT, &sa, NULL);
1044 sigaction (SIGQUIT, &sa, NULL);
1045 sigaction (SIGTERM, &sa, NULL);
1046 sigaction (SIGTRAP, &sa, NULL);
1047 }
1048
1049 {
1050 char szBuf[80];
1051 int iSize;
1052
1053 iSize = snprintf (szBuf, sizeof(szBuf),
1054 "Sun VirtualBox XPCOM Server Version "
1055 VBOX_VERSION_STRING);
1056 for (int i=iSize; i>0; i--)
1057 putchar('*');
1058 printf ("\n%s\n", szBuf);
1059 printf ("(C) 2008-2009 Sun Microsystems, Inc.\n"
1060 "All rights reserved.\n");
1061#ifdef DEBUG
1062 printf ("Debug version.\n");
1063#endif
1064#if 0
1065 /* in my opinion two lines enclosing the text look better */
1066 for (int i=iSize; i>0; i--)
1067 putchar('*');
1068 putchar('\n');
1069#endif
1070 }
1071
1072#ifndef RT_OS_OS2
1073 if (daemon_pipe_fds[1] >= 0)
1074 {
1075 printf ("\nStarting event loop....\n[send TERM signal to quit]\n");
1076 /* now we're ready, signal the parent process */
1077 write(daemon_pipe_fds[1], "READY", strlen("READY"));
1078 }
1079 else
1080#endif
1081 {
1082 printf ("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1083 }
1084
1085 if (pszPidFile)
1086 {
1087 char szBuf[32];
1088 const char *lf = "\n";
1089 RTFileOpen(&pidFile, pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE);
1090 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1091 RTFileWrite(pidFile, szBuf, strlen(szBuf), NULL);
1092 RTFileWrite(pidFile, lf, strlen(lf), NULL);
1093 RTFileClose(pidFile);
1094 }
1095
1096#ifndef RT_OS_OS2
1097 // Increase the file table size to 10240 or as high as possible.
1098 struct rlimit lim;
1099 if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
1100 {
1101 if ( lim.rlim_cur < 10240
1102 && lim.rlim_cur < lim.rlim_max)
1103 {
1104 lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
1105 if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
1106 printf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
1107 }
1108 }
1109 else
1110 printf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
1111#endif
1112
1113 PLEvent *ev;
1114 while (gKeepRunning)
1115 {
1116 gEventQ->WaitForEvent (&ev);
1117 gEventQ->HandleEvent (ev);
1118 }
1119
1120 /* stop accepting new events. Clients that happen to resolve our
1121 * name and issue a CreateInstance() request after this point will
1122 * get NS_ERROR_ABORT once we hande the remaining messages. As a
1123 * result, they should try to start a new server process. */
1124 gEventQ->StopAcceptingEvents();
1125
1126 /* unregister ourselves. After this point, clients will start a new
1127 * process because they won't be able to resolve the server name.*/
1128 gIpcServ->RemoveName (VBOXSVC_IPC_NAME);
1129
1130 /* process any remaining events. These events may include
1131 * CreateInstance() requests received right before we called
1132 * StopAcceptingEvents() above. We will detect this case below,
1133 * restore gKeepRunning and continue to serve. */
1134 gEventQ->ProcessPendingEvents();
1135
1136 printf ("Terminated event loop.\n");
1137 }
1138 while (0); // this scopes the nsCOMPtrs
1139
1140 NS_IF_RELEASE (gIpcServ);
1141 NS_IF_RELEASE (gEventQ);
1142
1143 /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
1144
1145 LogFlowFunc (("Calling com::Shutdown()...\n"));
1146 rc = com::Shutdown();
1147 LogFlowFunc (("Finished com::Shutdown() (rc=%08X)\n", rc));
1148
1149 if (NS_FAILED (rc))
1150 printf ("ERROR: Failed to shutdown XPCOM! (rc=%08X)\n", rc);
1151
1152 printf ("XPCOM server has shutdown.\n");
1153
1154 if (pszPidFile)
1155 {
1156 RTFileDelete(pszPidFile);
1157 }
1158
1159#ifndef RT_OS_OS2
1160 if (daemon_pipe_fds[1] >= 0)
1161 {
1162 /* close writing end of the pipe as well */
1163 close(daemon_pipe_fds[1]);
1164 }
1165#endif
1166
1167 return 0;
1168}
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