VirtualBox

source: vbox/trunk/src/VBox/Main/linux/server.cpp@ 1806

Last change on this file since 1806 was 1806, checked in by vboxsync, 18 years ago

Main: Don't distinguish between VBoxSVC exe locations when taking a decision whether to start a server process or use an existing (instead, use VBox version number for that). This ensures two build flavors of the samve version will use the same server instance, while two different versions will start two independent VBoxSVC instances.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.6 KB
Line 
1/** @file
2 *
3 * XPCOM server process start point
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include <ipcIService.h>
23#include <ipcCID.h>
24
25#include <nsIServiceManager.h>
26#include <nsIComponentRegistrar.h>
27
28#include <nsXPCOMGlue.h>
29#include <nsEventQueueUtils.h>
30
31// for NS_InitXPCOM2 with bin dir parameter
32#include <nsEmbedString.h>
33#include <nsIFile.h>
34#include <nsILocalFile.h>
35
36#include "linux/server.h"
37#include "Logging.h"
38
39#include <iprt/runtime.h>
40#include <iprt/path.h>
41#include <iprt/critsect.h>
42#include <iprt/timer.h>
43
44#include <VBox/param.h>
45#include <VBox/version.h>
46
47// for nsMyFactory
48#include "nsIGenericFactory.h"
49#include "nsIClassInfo.h"
50
51#include <stdio.h>
52
53// for the signal handler
54#include <signal.h>
55#include <stdlib.h>
56#include <unistd.h>
57#include <errno.h>
58#include <getopt.h>
59
60// for the backtrace signal handler
61#if defined(DEBUG) && defined(__LINUX__)
62# define USE_BACKTRACE
63#endif
64#if defined(USE_BACKTRACE)
65# include <execinfo.h>
66// get REG_EIP/RIP from ucontext.h
67# ifndef __USE_GNU
68# define __USE_GNU
69# endif
70# include <ucontext.h>
71# ifdef __AMD64__
72# define REG_PC REG_RIP
73# else
74# define REG_PC REG_EIP
75# endif
76#endif
77
78/////////////////////////////////////////////////////////////////////////////
79// VirtualBox component instantiation
80/////////////////////////////////////////////////////////////////////////////
81
82#include <nsIGenericFactory.h>
83
84#include <VirtualBox_XPCOM.h>
85#include <VirtualBoxImpl.h>
86#include <MachineImpl.h>
87#include <SnapshotImpl.h>
88#include <HardDiskImpl.h>
89#include <ProgressImpl.h>
90#include <DVDDriveImpl.h>
91#include <FloppyDriveImpl.h>
92#include <VRDPServerImpl.h>
93#include <DVDImageImpl.h>
94#include <FloppyImageImpl.h>
95#include <SharedFolderImpl.h>
96#include <HostImpl.h>
97#include <HostDVDDriveImpl.h>
98#include <HostFloppyDriveImpl.h>
99#include <HostUSBDeviceImpl.h>
100#include <GuestOSTypeImpl.h>
101#include <NetworkAdapterImpl.h>
102#include <USBControllerImpl.h>
103#include <USBDeviceImpl.h>
104#include <AudioAdapterImpl.h>
105#include <SystemPropertiesImpl.h>
106#include <Collection.h>
107
108// implement nsISupports parts of our objects with support for nsIClassInfo
109NS_DECL_CLASSINFO(VirtualBox)
110NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBox, IVirtualBox)
111NS_DECL_CLASSINFO(Machine)
112NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
113NS_DECL_CLASSINFO(SessionMachine)
114NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
115NS_DECL_CLASSINFO(SnapshotMachine)
116NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
117NS_DECL_CLASSINFO(Snapshot)
118NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
119NS_DECL_CLASSINFO(HardDisk)
120NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDisk, IHardDisk)
121NS_DECL_CLASSINFO(HVirtualDiskImage)
122NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVirtualDiskImage, IHardDisk, IVirtualDiskImage)
123NS_DECL_CLASSINFO(HISCSIHardDisk)
124NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HISCSIHardDisk, IHardDisk, IISCSIHardDisk)
125NS_DECL_CLASSINFO(HVMDKImage)
126NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVMDKImage, IHardDisk, IVMDKImage)
127NS_DECL_CLASSINFO(HardDiskAttachment)
128NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskAttachment, IHardDiskAttachment)
129NS_DECL_CLASSINFO(Progress)
130NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
131NS_DECL_CLASSINFO(CombinedProgress)
132NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
133NS_DECL_CLASSINFO(DVDDrive)
134NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DVDDrive, IDVDDrive)
135NS_DECL_CLASSINFO(FloppyDrive)
136NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FloppyDrive, IFloppyDrive)
137NS_DECL_CLASSINFO(SharedFolder)
138NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
139#ifdef VBOX_VRDP
140NS_DECL_CLASSINFO(VRDPServer)
141NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPServer, IVRDPServer)
142#endif
143NS_DECL_CLASSINFO(DVDImage)
144NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DVDImage, IDVDImage)
145NS_DECL_CLASSINFO(FloppyImage)
146NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FloppyImage, IFloppyImage)
147NS_DECL_CLASSINFO(Host)
148NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Host, IHost)
149NS_DECL_CLASSINFO(HostDVDDrive)
150NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostDVDDrive, IHostDVDDrive)
151NS_DECL_CLASSINFO(HostFloppyDrive)
152NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostFloppyDrive, IHostFloppyDrive)
153NS_DECL_CLASSINFO(GuestOSType)
154NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
155NS_DECL_CLASSINFO(NetworkAdapter)
156NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
157NS_DECL_CLASSINFO(USBController)
158NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
159NS_DECL_CLASSINFO(USBDeviceFilter)
160NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilter, IUSBDeviceFilter)
161NS_DECL_CLASSINFO(HostUSBDevice)
162NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDevice, IUSBDevice, IHostUSBDevice)
163NS_DECL_CLASSINFO(HostUSBDeviceFilter)
164NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostUSBDeviceFilter, IHostUSBDeviceFilter)
165NS_DECL_CLASSINFO(AudioAdapter)
166NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AudioAdapter, IAudioAdapter)
167NS_DECL_CLASSINFO(SystemProperties)
168NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SystemProperties, ISystemProperties)
169NS_DECL_CLASSINFO(BIOSSettings)
170NS_IMPL_THREADSAFE_ISUPPORTS1_CI(BIOSSettings, IBIOSSettings)
171
172// collections and enumerators
173COM_IMPL_READONLY_ENUM_AND_COLLECTION(Machine)
174COM_IMPL_READONLY_ENUM_AND_COLLECTION(Snapshot)
175COM_IMPL_READONLY_ENUM_AND_COLLECTION(HardDiskAttachment)
176COM_IMPL_READONLY_ENUM_AND_COLLECTION(GuestOSType)
177COM_IMPL_READONLY_ENUM_AND_COLLECTION(USBDeviceFilter)
178COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostDVDDrive)
179COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostFloppyDrive)
180COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostUSBDevice)
181COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostUSBDeviceFilter)
182COM_IMPL_READONLY_ENUM_AND_COLLECTION(HardDisk)
183COM_IMPL_READONLY_ENUM_AND_COLLECTION(DVDImage)
184COM_IMPL_READONLY_ENUM_AND_COLLECTION(FloppyImage)
185COM_IMPL_READONLY_ENUM_AND_COLLECTION(SharedFolder)
186
187COM_IMPL_READONLY_ENUM_AND_COLLECTION_AS(Progress, IProgress)
188COM_IMPL_READONLY_ENUM_AND_COLLECTION_AS(IfaceUSBDevice, IUSBDevice)
189
190////////////////////////////////////////////////////////////////////////////////
191
192enum
193{
194 /* Delay before shutting down the VirtualBox server after the last
195 * VirtualBox instance is released, in ms */
196 VBoxSVC_ShutdownDelay = 5000,
197};
198
199static bool gAutoShutdown = false;
200
201static nsIEventQueue* gEventQ = nsnull;
202static PRBool volatile gKeepRunning = PR_TRUE;
203
204////////////////////////////////////////////////////////////////////////////////
205
206/**
207 * VirtualBox class factory that destroys the created instance right after
208 * the last reference to it is released by the client, and recreates it again
209 * when necessary (so VirtualBox acts like a singleton object).
210 */
211class VirtualBoxClassFactory : public VirtualBox
212{
213public:
214
215 virtual ~VirtualBoxClassFactory()
216 {
217 LogFlowFunc (("Deleting VirtualBox...\n"));
218
219 FinalRelease();
220 sInstance = 0;
221
222 LogFlowFunc (("VirtualBox object deleted.\n"));
223 printf ("Informational: VirtualBox object deleted.\n");
224
225 /* Instruct the main event loop to terminate. Note that it's enough
226 * to set gKeepRunning to false because we are on the main thread
227 * already (i.e. no need to post events there). */
228 if (gAutoShutdown)
229 gKeepRunning = PR_FALSE;
230 }
231
232 NS_IMETHOD_(nsrefcnt) Release()
233 {
234 /* we overload Release() to guarantee the VirtualBox destructor is
235 * always called on the main thread */
236
237 nsrefcnt count = VirtualBox::Release();
238
239 if (count == 1)
240 {
241 /* the last reference held by clients is being released
242 * (see GetInstance()) */
243
244 PRBool onMainThread = PR_TRUE;
245 if (gEventQ)
246 gEventQ->IsOnCurrentThread (&onMainThread);
247
248 if (!onMainThread)
249 {
250 LogFlowFunc (("Last VirtualBox instance was released, "
251 "scheduling server shutdown in %d ms...\n",
252 VBoxSVC_ShutdownDelay));
253
254 /* Start a shutdown timer to provide some delay */
255 int vrc = RTTimerStart (sTimer, 0);
256/// @todo uncomment when implemented
257// AssertRC (vrc);
258 if (VBOX_FAILURE (vrc))
259 {
260 /* failed to start the timer, post the shutdown event
261 * manually */
262 ShutdownTimer (NULL, NULL);
263 }
264 }
265 else
266 {
267 /* Here we come if:
268 *
269 * a) gEventQ is 0 which means either FactoryDestructor() is called
270 * or the IPC/DCONNECT shutdown sequence is initiated by the
271 * XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
272 * happens on the main thread.
273 *
274 * b) gEventQ has reported we're on the main thread. This means
275 * that DestructEventHandler() has been called, but another
276 * client was faster and requested VirtualBox again.
277 *
278 * We have nothing to do in these cases.
279 */
280 }
281 }
282
283 return count;
284 }
285
286 static void *PR_CALLBACK DestructEventHandler (PLEvent* self)
287 {
288 Assert (RTCritSectIsInitialized (&sLock));
289
290 /* stop accepting GetInstance() requests during possible destruction */
291 RTCritSectEnter (&sLock);
292
293 Assert (sInstance);
294
295 /* release the reference we added in GetInstance()
296 * (will call the destructor if nobody referenced us again) */
297 nsrefcnt count = sInstance->Release();
298 if (count != 0)
299 {
300 LogFlowFunc (("Destruction is canceled.\n"));
301 }
302
303 RTCritSectLeave (&sLock);
304
305 return 0;
306 }
307
308 static void PR_CALLBACK DestructEventDestructor (PLEvent* self)
309 {
310 delete self;
311 }
312
313 static void ShutdownTimer (PRTTIMER pTimer, void *pvUser)
314 {
315 NOREF (pvUser);
316
317 if (pTimer)
318 {
319 /* it's a single shot timer */
320 int vrc = RTTimerStop (pTimer);
321/// @todo uncomment when implemented
322// AssertRC (vrc);
323 NOREF (vrc);
324 }
325
326 /* post a destruction event to the main thread to safely release the
327 * extra reference added in VirtualBoxClassFactory::GetInstance() */
328
329 LogFlowFunc (("Posting VirtualBox destruction & shtutdown event...\n"));
330
331 PLEvent *ev = new PLEvent;
332 gEventQ->InitEvent (ev, NULL, DestructEventHandler,
333 DestructEventDestructor);
334 nsresult rv = gEventQ->PostEvent (ev);
335 if (NS_FAILED (rv))
336 {
337 /* this means we've been already stopped (for example
338 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
339 * will do the job. */
340 PL_DestroyEvent (ev);
341 }
342 }
343
344 static NS_IMETHODIMP FactoryConstructor()
345 {
346 LogFlowFunc (("\n"));
347
348 /* create a critsect to protect object construction */
349 if (VBOX_FAILURE (RTCritSectInit (&sLock)))
350 return NS_ERROR_OUT_OF_MEMORY;
351
352 int vrc = RTTimerCreateEx (&sTimer,
353 uint64_t (VBoxSVC_ShutdownDelay) * 1000000,
354 0, ShutdownTimer, NULL);
355 NOREF (vrc);
356/// @todo uncomment when implemented
357// if (VBOX_FAILURE (vrc))
358// {
359// LogFlowFunc (("Failed to create a timer! (vrc=%Vrc)\n", vrc));
360// return NS_ERROR_FAILURE;
361// }
362
363 return NS_OK;
364 }
365
366 static NS_IMETHODIMP FactoryDestructor()
367 {
368 LogFlowFunc (("\n"));
369
370 RTTimerDestroy (sTimer);
371 sTimer = NULL;
372
373 RTCritSectDelete (&sLock);
374
375 if (sInstance)
376 {
377 /* Either posting a destruction event falied for some reason (most
378 * likely, the quit event has been received before the last release),
379 * or the client has terminated abnormally w/o releasing its
380 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
381 * Release the extra reference we added in GetInstance(). */
382 sInstance->Release();
383 }
384
385 return NS_OK;
386 }
387
388 static nsresult GetInstance (VirtualBox **inst)
389 {
390 LogFlowFunc (("Getting VirtualBox object...\n"));
391
392 RTCritSectEnter (&sLock);
393
394 int rv = NS_OK;
395
396 if (sInstance == 0)
397 {
398 LogFlowFunc (("Creating new VirtualBox object...\n"));
399 sInstance = new VirtualBoxClassFactory();
400 if (sInstance)
401 {
402 /* make an extra AddRef to take the full control
403 * on the VirtualBox destruction (see FinalRelease()) */
404 sInstance->AddRef();
405
406 sInstance->AddRef(); /* protect FinalConstruct() */
407 rv = sInstance->FinalConstruct();
408 printf ("Informational: VirtualBox object created (rc=%08X).\n", rv);
409 if (NS_FAILED (rv))
410 {
411 /* on failure diring VirtualBox initialization, delete it
412 * immediately on the current thread, ignoring the reference
413 * count (VirtualBox should be aware of that meaning that it
414 * has already completely unintialized itself in this
415 * case) */
416 LogFlowFunc (("VirtualBox creation failed "
417 "(rc=%08X), deleting immediately...\n", rv));
418 delete sInstance;
419 sInstance = 0;
420 }
421 }
422 else
423 {
424 rv = NS_ERROR_OUT_OF_MEMORY;
425 }
426 }
427 else
428 {
429 LogFlowFunc (("Using existing VirtualBox object...\n"));
430 nsrefcnt count = sInstance->AddRef();
431 Assert (count > 1);
432
433 if (count == 2)
434 {
435 LogFlowFunc (("Another client has requested "
436 "a reference of VirtualBox scheduled for destruction, "
437 "canceling detruction...\n"));
438
439 /* add a reference to compensate one that DestructEventHandler()
440 * will release */
441 sInstance->AddRef();
442 }
443 }
444
445 *inst = sInstance;
446
447 RTCritSectLeave (&sLock);
448
449 return rv;
450 }
451
452private:
453
454 static VirtualBox *sInstance;
455 static RTCRITSECT sLock;
456
457 static PRTTIMER sTimer;
458};
459
460VirtualBox *VirtualBoxClassFactory::sInstance = 0;
461RTCRITSECT VirtualBoxClassFactory::sLock = {0};
462
463PRTTIMER VirtualBoxClassFactory::sTimer = NULL;
464
465NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC
466 (VirtualBox, VirtualBoxClassFactory::GetInstance)
467
468////////////////////////////////////////////////////////////////////////////////
469
470typedef NSFactoryDestructorProcPtr NSFactoryConsructorProcPtr;
471
472/**
473 * Enhanced module component information structure.
474 * nsModuleComponentInfo lacks the factory construction callback,
475 * here we add it. This callback is called by NS_NewMyFactory() after
476 * a nsMyFactory instance is successfully created.
477 */
478struct nsMyModuleComponentInfo : nsModuleComponentInfo
479{
480 nsMyModuleComponentInfo () {}
481 nsMyModuleComponentInfo (int) {}
482
483 nsMyModuleComponentInfo (
484 const char* aDescription,
485 const nsCID& aCID,
486 const char* aContractID,
487 NSConstructorProcPtr aConstructor,
488 NSRegisterSelfProcPtr aRegisterSelfProc,
489 NSUnregisterSelfProcPtr aUnregisterSelfProc,
490 NSFactoryDestructorProcPtr aFactoryDestructor,
491 NSGetInterfacesProcPtr aGetInterfacesProc,
492 NSGetLanguageHelperProcPtr aGetLanguageHelperProc,
493 nsIClassInfo ** aClassInfoGlobal,
494 PRUint32 aFlags,
495 NSFactoryConsructorProcPtr aFactoryConstructor)
496 {
497 mDescription = aDescription;
498 mCID = aCID;
499 mContractID = aContractID;
500 mConstructor = aConstructor;
501 mRegisterSelfProc = aRegisterSelfProc;
502 mUnregisterSelfProc = aUnregisterSelfProc;
503 mFactoryDestructor = aFactoryDestructor;
504 mGetInterfacesProc = aGetInterfacesProc;
505 mGetLanguageHelperProc = aGetLanguageHelperProc;
506 mClassInfoGlobal = aClassInfoGlobal;
507 mFlags = aFlags;
508 mFactoryConstructor = aFactoryConstructor;
509 }
510
511 /** (optional) Factory Construction Callback */
512 NSFactoryConsructorProcPtr mFactoryConstructor;
513};
514
515////////////////////////////////////////////////////////////////////////////////
516
517static const nsMyModuleComponentInfo components[] =
518{
519 nsMyModuleComponentInfo (
520 "VirtualBox component",
521 (nsCID) NS_VIRTUALBOX_CID,
522 NS_VIRTUALBOX_CONTRACTID,
523 VirtualBoxConstructor, // constructor funcion
524 NULL, // registration function
525 NULL, // deregistration function
526 VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
527 NS_CI_INTERFACE_GETTER_NAME(VirtualBox),
528 NULL, // language helper
529 &NS_CLASSINFO_NAME(VirtualBox),
530 0, // flags
531 VirtualBoxClassFactory::FactoryConstructor // factory constructor function
532 )
533};
534
535/////////////////////////////////////////////////////////////////////////////
536
537/**
538 * Generic component factory.
539 *
540 * The code below is stolen from nsGenericFactory.h / nsGenericFactory.cpp,
541 * because we get a segmentation fault for some unknown reason when VBoxSVC
542 * starts up (somewhere during the initialization of the libipcdc.so module)
543 * when we just reference XPCOM's NS_NewGenericFactory() from here (i.e. even
544 * before actually calling it) and run VBoxSVC using the debug XPCOM
545 * libraries.
546 *
547 * Actually, I know why, but I find it too stupid even to discuss.
548 */
549class nsMyFactory : public nsIGenericFactory, public nsIClassInfo {
550public:
551 NS_DEFINE_STATIC_CID_ACCESSOR(NS_GENERICFACTORY_CID);
552
553 nsMyFactory(const nsModuleComponentInfo *info = NULL);
554
555 NS_DECL_ISUPPORTS
556 NS_DECL_NSICLASSINFO
557
558 /* nsIGenericFactory methods */
559 NS_IMETHOD SetComponentInfo(const nsModuleComponentInfo *info);
560 NS_IMETHOD GetComponentInfo(const nsModuleComponentInfo **infop);
561
562 NS_IMETHOD CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
563
564 NS_IMETHOD LockFactory(PRBool aLock);
565
566 static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
567private:
568 ~nsMyFactory();
569
570 const nsModuleComponentInfo *mInfo;
571};
572
573nsMyFactory::nsMyFactory(const nsModuleComponentInfo *info)
574 : mInfo(info)
575{
576 if (mInfo && mInfo->mClassInfoGlobal)
577 *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this);
578}
579
580nsMyFactory::~nsMyFactory()
581{
582 if (mInfo) {
583 if (mInfo->mFactoryDestructor)
584 mInfo->mFactoryDestructor();
585 if (mInfo->mClassInfoGlobal)
586 *mInfo->mClassInfoGlobal = 0;
587 }
588}
589
590NS_IMPL_THREADSAFE_ISUPPORTS3(nsMyFactory,
591 nsIGenericFactory,
592 nsIFactory,
593 nsIClassInfo)
594
595NS_IMETHODIMP nsMyFactory::CreateInstance(nsISupports *aOuter,
596 REFNSIID aIID, void **aResult)
597{
598 if (mInfo->mConstructor)
599 return mInfo->mConstructor(aOuter, aIID, aResult);
600
601 return NS_ERROR_FACTORY_NOT_REGISTERED;
602}
603
604NS_IMETHODIMP nsMyFactory::LockFactory(PRBool aLock)
605{
606 // XXX do we care if (mInfo->mFlags & THREADSAFE)?
607 return NS_OK;
608}
609
610NS_IMETHODIMP nsMyFactory::GetInterfaces(PRUint32 *countp,
611 nsIID* **array)
612{
613 if (!mInfo->mGetInterfacesProc) {
614 *countp = 0;
615 *array = nsnull;
616 return NS_OK;
617 }
618 return mInfo->mGetInterfacesProc(countp, array);
619}
620
621NS_IMETHODIMP nsMyFactory::GetHelperForLanguage(PRUint32 language,
622 nsISupports **helper)
623{
624 if (mInfo->mGetLanguageHelperProc)
625 return mInfo->mGetLanguageHelperProc(language, helper);
626 *helper = nsnull;
627 return NS_OK;
628}
629
630NS_IMETHODIMP nsMyFactory::GetContractID(char **aContractID)
631{
632 if (mInfo->mContractID) {
633 *aContractID = (char *)nsMemory::Alloc(strlen(mInfo->mContractID) + 1);
634 if (!*aContractID)
635 return NS_ERROR_OUT_OF_MEMORY;
636 strcpy(*aContractID, mInfo->mContractID);
637 } else {
638 *aContractID = nsnull;
639 }
640 return NS_OK;
641}
642
643NS_IMETHODIMP nsMyFactory::GetClassDescription(char * *aClassDescription)
644{
645 if (mInfo->mDescription) {
646 *aClassDescription = (char *)
647 nsMemory::Alloc(strlen(mInfo->mDescription) + 1);
648 if (!*aClassDescription)
649 return NS_ERROR_OUT_OF_MEMORY;
650 strcpy(*aClassDescription, mInfo->mDescription);
651 } else {
652 *aClassDescription = nsnull;
653 }
654 return NS_OK;
655}
656
657NS_IMETHODIMP nsMyFactory::GetClassID(nsCID * *aClassID)
658{
659 *aClassID =
660 NS_REINTERPRET_CAST(nsCID*,
661 nsMemory::Clone(&mInfo->mCID, sizeof mInfo->mCID));
662 if (! *aClassID)
663 return NS_ERROR_OUT_OF_MEMORY;
664 return NS_OK;
665}
666
667NS_IMETHODIMP nsMyFactory::GetClassIDNoAlloc(nsCID *aClassID)
668{
669 *aClassID = mInfo->mCID;
670 return NS_OK;
671}
672
673NS_IMETHODIMP nsMyFactory::GetImplementationLanguage(PRUint32 *langp)
674{
675 *langp = nsIProgrammingLanguage::CPLUSPLUS;
676 return NS_OK;
677}
678
679NS_IMETHODIMP nsMyFactory::GetFlags(PRUint32 *flagsp)
680{
681 *flagsp = mInfo->mFlags;
682 return NS_OK;
683}
684
685// nsIGenericFactory: component-info accessors
686NS_IMETHODIMP nsMyFactory::SetComponentInfo(const nsModuleComponentInfo *info)
687{
688 if (mInfo && mInfo->mClassInfoGlobal)
689 *mInfo->mClassInfoGlobal = 0;
690 mInfo = info;
691 if (mInfo && mInfo->mClassInfoGlobal)
692 *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this);
693 return NS_OK;
694}
695
696NS_IMETHODIMP nsMyFactory::GetComponentInfo(const nsModuleComponentInfo **infop)
697{
698 *infop = mInfo;
699 return NS_OK;
700}
701
702NS_METHOD nsMyFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
703{
704 // sorry, aggregation not spoken here.
705 nsresult res = NS_ERROR_NO_AGGREGATION;
706 if (outer == NULL) {
707 nsMyFactory* factory = new nsMyFactory;
708 if (factory != NULL) {
709 res = factory->QueryInterface(aIID, aInstancePtr);
710 if (res != NS_OK)
711 delete factory;
712 } else {
713 res = NS_ERROR_OUT_OF_MEMORY;
714 }
715 }
716 return res;
717}
718
719/**
720 * Instantiates a new factory and calls
721 * nsMyModuleComponentInfo::mFactoryConstructor.
722 */
723NS_COM nsresult
724NS_NewMyFactory(nsIGenericFactory* *result,
725 const nsMyModuleComponentInfo *info)
726{
727 nsresult rv;
728 nsMyFactory* fact;
729 rv = nsMyFactory::Create(NULL, NS_GET_IID(nsIGenericFactory), (void**)&fact);
730 if (NS_FAILED(rv)) return rv;
731 rv = fact->SetComponentInfo(info);
732 if (NS_FAILED(rv)) goto error;
733 if (info && info->mFactoryConstructor) {
734 rv = info->mFactoryConstructor();
735 if (NS_FAILED(rv)) goto error;
736 }
737 *result = fact;
738 return rv;
739
740 error:
741 NS_RELEASE(fact);
742 return rv;
743}
744
745/////////////////////////////////////////////////////////////////////////////
746
747/**
748 * Hhelper function to register self components upon start-up
749 * of the out-of-proc server.
750 */
751static nsresult
752RegisterSelfComponents (nsIComponentRegistrar *registrar,
753 const nsMyModuleComponentInfo *components,
754 PRUint32 count)
755{
756 nsresult rc = NS_OK;
757 const nsMyModuleComponentInfo *info = components;
758 for (PRUint32 i = 0; i < count && NS_SUCCEEDED (rc); i++, info++)
759 {
760 /* skip components w/o a constructor */
761 if (!info->mConstructor) continue;
762 /* create a new generic factory for a component and register it */
763 nsIGenericFactory *factory;
764 rc = NS_NewGenericFactory (&factory, info);
765 rc = NS_NewMyFactory (&factory, info);
766 if (NS_SUCCEEDED (rc))
767 {
768 rc = registrar->RegisterFactory (info->mCID,
769 info->mDescription,
770 info->mContractID,
771 factory);
772 factory->Release();
773 }
774 }
775 return rc;
776}
777
778/////////////////////////////////////////////////////////////////////////////
779
780static ipcIService *gIpcServ = nsnull;
781static char *pszPidFile = NULL;
782
783void* PR_CALLBACK quitEventHandler (PLEvent* self) { gKeepRunning = PR_FALSE; return 0; }
784void PR_CALLBACK quitEventDestructor (PLEvent* self) { delete self; }
785
786static void signal_handler (int sig)
787{
788 if (gEventQ && gKeepRunning)
789 {
790 /* post a quit event to the queue */
791 PLEvent *ev = new PLEvent;
792 gEventQ->InitEvent (ev, NULL, quitEventHandler, quitEventDestructor);
793 gEventQ->PostEvent (ev);
794 }
795 if (pszPidFile)
796 {
797 RTFileDelete(pszPidFile);
798 }
799};
800
801#if defined(USE_BACKTRACE)
802/**
803 * the signal handler that prints out a backtrace of the call stack.
804 * the code is taken from http://www.linuxjournal.com/article/6391.
805 */
806static void bt_sighandler (int sig, siginfo_t *info, void *secret)
807{
808
809 void *trace[16];
810 char **messages = (char **)NULL;
811 int i, trace_size = 0;
812 ucontext_t *uc = (ucontext_t *)secret;
813
814 // Do something useful with siginfo_t
815 if (sig == SIGSEGV)
816 Log (("Got signal %d, faulty address is %p, from %p\n",
817 sig, info->si_addr, uc->uc_mcontext.gregs[REG_PC]));
818 else
819 Log (("Got signal %d\n", sig));
820
821 trace_size = backtrace (trace, 16);
822 // overwrite sigaction with caller's address
823 trace[1] = (void *) uc->uc_mcontext.gregs [REG_PC];
824
825 messages = backtrace_symbols (trace, trace_size);
826 // skip first stack frame (points here)
827 Log (("[bt] Execution path:\n"));
828 for (i = 1; i < trace_size; ++i)
829 Log (("[bt] %s\n", messages[i]));
830
831 exit (0);
832}
833#endif
834
835int main (int argc, char **argv)
836{
837 const struct option options[] =
838 {
839 { "automate", no_argument, NULL, 'a' },
840 { "daemonize", no_argument, NULL, 'd' },
841 { "pidfile", required_argument, NULL, 'p' },
842 { NULL, 0, NULL, 0 }
843 };
844 int c;
845
846 bool fDaemonize = false;
847
848 for (;;)
849 {
850 c = getopt_long(argc, argv, "", options, NULL);
851 if (c == -1)
852 break;
853 switch (c)
854 {
855 case 'a':
856 {
857 /* --automate mode means we are started by XPCOM on
858 * demand. Daemonize ourselves and activate
859 * auto-shutdown. */
860 gAutoShutdown = true;
861 fDaemonize = true;
862 break;
863 }
864
865 case 'd':
866 {
867 fDaemonize = true;
868 break;
869 }
870
871 case 'p':
872 {
873 pszPidFile = optarg;
874 break;
875 }
876
877 default:
878 {
879 /* exit on invalid options */
880 return 1;
881 }
882 }
883 }
884
885 static int daemon_pipe_fds[2];
886 static RTFILE pidFile = NIL_RTFILE;
887
888 if (fDaemonize)
889 {
890 /* create a pipe for communication between child and parent */
891 if (pipe(daemon_pipe_fds) < 0)
892 {
893 printf("ERROR: pipe() failed (errno = %d)\n", errno);
894 return 1;
895 }
896
897 pid_t childpid = fork();
898 if (childpid == -1)
899 {
900 printf("ERROR: fork() failed (errno = %d)\n", errno);
901 return 1;
902 }
903
904 if (childpid != 0)
905 {
906 /* we're the parent process */
907 bool fSuccess = false;
908
909 /* close the writing end of the pipe */
910 close(daemon_pipe_fds[1]);
911
912 /* try to read a message from the pipe */
913 char msg[10] = {0}; /* initialize so it's NULL terminated */
914 if (read(daemon_pipe_fds[0], msg, sizeof(msg)) > 0)
915 {
916 if (strcmp(msg, "READY") == 0)
917 fSuccess = true;
918 else
919 printf ("ERROR: Unknown message from child "
920 "process (%s)\n", msg);
921 }
922 else
923 printf ("ERROR: 0 bytes read from child process\n");
924
925 /* close the reading end of the pipe as well and exit */
926 close(daemon_pipe_fds[0]);
927 return fSuccess ? 0 : 1;
928 }
929 /* we're the child process */
930
931 /* Create a new SID for the child process */
932 pid_t sid = setsid();
933 if (sid < 0)
934 {
935 printf("ERROR: setsid() failed (errno = %d)\n", errno);
936 return 1;
937 }
938
939 /* Redirect standard i/o streams to /dev/null */
940 freopen ("/dev/null", "r", stdin);
941 freopen ("/dev/null", "w", stdout);
942 freopen ("/dev/null", "w", stderr);
943
944 /* close the reading end of the pipe */
945 close(daemon_pipe_fds[0]);
946 }
947
948#if defined(USE_BACKTRACE)
949 {
950 /* install our signal handler to backtrace the call stack */
951 struct sigaction sa;
952 sa.sa_sigaction = bt_sighandler;
953 sigemptyset (&sa.sa_mask);
954 sa.sa_flags = SA_RESTART | SA_SIGINFO;
955 sigaction (SIGSEGV, &sa, NULL);
956 sigaction (SIGBUS, &sa, NULL);
957 sigaction (SIGUSR1, &sa, NULL);
958 }
959#endif
960
961 /*
962 * Initialize the VBox runtime without loading
963 * the support driver
964 */
965 RTR3Init(false);
966
967 nsresult rc;
968
969 do
970 {
971 XPCOMGlueStartup (nsnull);
972
973 char path [RTPATH_MAX];
974 path [0] = '\0';
975
976 nsCOMPtr<nsIFile> nsAppPath;
977 {
978 /* get the path to the executable */
979 char *appPath = NULL;
980#if defined (DEBUG)
981 appPath = getenv ("VIRTUALBOX_APP_HOME");
982 if (appPath)
983 RTPathReal (appPath, path, RTPATH_MAX);
984 else
985#endif
986 RTPathProgram (path, RTPATH_MAX);
987 appPath = path;
988
989 nsCOMPtr<nsILocalFile> file;
990 rc = NS_NewNativeLocalFile (nsEmbedCString (appPath),
991 PR_FALSE, getter_AddRefs (file));
992 if (NS_SUCCEEDED (rc))
993 nsAppPath = do_QueryInterface (file, &rc);
994 }
995 if (NS_FAILED (rc))
996 {
997 printf ("ERROR: Failed to create file object! (rc=%08X)\n", rc);
998 break;
999 }
1000
1001 /* not really necessary at the moment */
1002#if 0
1003 if (!RTProcGetExecutableName (path, sizeof (path)))
1004 {
1005 printf ("ERROR: Failed to get executable name!\n");
1006 break;
1007 }
1008#endif
1009
1010 nsCOMPtr<nsIServiceManager> servMan;
1011 NS_InitXPCOM2 (getter_AddRefs (servMan), nsAppPath, nsnull);
1012 if (!servMan)
1013 {
1014 printf ("ERROR: Failed to get service manager!\n");
1015 break;
1016 }
1017
1018 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface (servMan);
1019 if (!registrar)
1020 {
1021 printf ("ERROR: Failed to get component registrar!\n");
1022 break;
1023 }
1024
1025 registrar->AutoRegister (nsnull);
1026 rc = RegisterSelfComponents (registrar, components,
1027 NS_ARRAY_LENGTH (components));
1028 if (NS_FAILED (rc))
1029 {
1030 printf ("ERROR: Failed to register server components! (rc=%08X)\n", rc);
1031 break;
1032 }
1033
1034 /* get the main thread's event queue (afaik, the dconnect service always
1035 * gets created upon XPCOM startup, so it will use the main (this)
1036 * thread's event queue to receive IPC events) */
1037 rc = NS_GetMainEventQ (&gEventQ);
1038 if (NS_FAILED (rc))
1039 {
1040 printf ("ERROR: Failed to get the main event queue! (rc=%08X)\n", rc);
1041 break;
1042 }
1043
1044 nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1045 if (NS_FAILED (rc))
1046 {
1047 printf ("ERROR: Failed to get IPC service! (rc=%08X)\n", rc);
1048 break;
1049 }
1050
1051 NS_ADDREF (gIpcServ = ipcServ);
1052
1053 LogFlowFunc (("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1054
1055 rc = gIpcServ->AddName (VBOXSVC_IPC_NAME);
1056 if (NS_FAILED (rc))
1057 {
1058 printf ("ERROR: Failed to register VirtualBoxServer! (rc=%08X)\n", rc);
1059 NS_RELEASE (gIpcServ);
1060 break;
1061 }
1062
1063 {
1064 /* setup signal handling to convert some signals to a quit event */
1065 struct sigaction sa;
1066 sa.sa_handler = signal_handler;
1067 sigemptyset (&sa.sa_mask);
1068 sa.sa_flags = 0;
1069 sigaction (SIGINT, &sa, NULL);
1070 sigaction (SIGQUIT, &sa, NULL);
1071 sigaction (SIGTERM, &sa, NULL);
1072 sigaction (SIGTRAP, &sa, NULL);
1073 }
1074
1075 {
1076 char szBuf[80];
1077 int iSize;
1078
1079 iSize = snprintf (szBuf, sizeof(szBuf),
1080 "InnoTek VirtualBox XPCOM Server Version %s",
1081 VBOX_VERSION_STRING);
1082 for (int i=iSize; i>0; i--)
1083 putchar('*');
1084 printf ("\n%s\n", szBuf);
1085 printf ("(C) 2004-2007 InnoTek Systemberatung GmbH\n");
1086 printf ("All rights reserved.\n");
1087#ifdef DEBUG
1088 printf ("Debug version.\n");
1089#endif
1090#if 0
1091 /* in my opinion two lines enclosing the text look better */
1092 for (int i=iSize; i>0; i--)
1093 putchar('*');
1094 putchar('\n');
1095#endif
1096 }
1097
1098 if (fDaemonize)
1099 {
1100 printf ("\nStarting event loop....\n[send TERM signal to quit]\n");
1101 /* now we're ready, signal the parent process */
1102 write(daemon_pipe_fds[1], "READY", strlen("READY"));
1103 }
1104 else
1105 {
1106 printf ("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1107 }
1108
1109 if (pszPidFile)
1110 {
1111 char szBuf[32];
1112 char *lf = "\n";
1113 RTFileOpen(&pidFile, pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE);
1114 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1115 RTFileWrite(pidFile, szBuf, strlen(szBuf), NULL);
1116 RTFileWrite(pidFile, lf, strlen(lf), NULL);
1117 RTFileClose(pidFile);
1118 }
1119
1120 PLEvent *ev;
1121 while (gKeepRunning)
1122 {
1123 gEventQ->WaitForEvent (&ev);
1124 gEventQ->HandleEvent (ev);
1125 }
1126
1127 gIpcServ->RemoveName (path);
1128
1129 // stop accepting new events
1130 gEventQ->StopAcceptingEvents();
1131 // process any remaining events
1132 gEventQ->ProcessPendingEvents();
1133
1134 printf ("Terminated event loop.\n");
1135
1136 }
1137 while (0); // this scopes the nsCOMPtrs
1138
1139 NS_IF_RELEASE (gIpcServ);
1140 NS_IF_RELEASE (gEventQ);
1141
1142 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
1143 LogFlowFunc (("Calling NS_ShutdownXPCOM()...\n"));
1144 rc = NS_ShutdownXPCOM (nsnull);
1145 LogFlowFunc (("Finished NS_ShutdownXPCOM() (rc=%08X)\n", rc));
1146
1147 if (NS_FAILED (rc))
1148 printf ("ERROR: Failed to shutdown XPCOM! (rc=%08X)\n", rc);
1149
1150 XPCOMGlueShutdown();
1151
1152 printf ("XPCOM server has shutdown.\n");
1153
1154 if (pszPidFile)
1155 {
1156 RTFileDelete(pszPidFile);
1157 }
1158
1159 if (fDaemonize)
1160 {
1161 /* close writing end of the pipe as well */
1162 close(daemon_pipe_fds[1]);
1163 }
1164
1165 return 0;
1166}
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