VirtualBox

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

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

#3551: “Main: Replace remaining collections with safe arrays”
Replace SnapshotCollection. Reviewed by dmik. Tested with GUI.

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