VirtualBox

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

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

Main/dhcp API, E_NOTIMPL yet

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