VirtualBox

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

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

Main-S3: backed out r47779 because of Win (mkdtemp)

  • 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 20045 2009-05-26 15:44:07Z 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.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * 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.

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