VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp@ 11378

Last change on this file since 11378 was 11102, checked in by vboxsync, 17 years ago

FE/VBoxHeadless: unset the DISPLAY variable in the frontend to prevent the host clipboard from starting

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.2 KB
Line 
1/** @file
2 *
3 * VBox frontends: VBoxHeadless (headless frontend):
4 * Headless server executable
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <VBox/com/com.h>
24#include <VBox/com/string.h>
25#include <VBox/com/Guid.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/EventQueue.h>
28
29#include <VBox/com/VirtualBox.h>
30
31using namespace com;
32
33#define LOG_GROUP LOG_GROUP_GUI
34
35#include <VBox/log.h>
36#include <VBox/version.h>
37#ifdef VBOX_WITH_VRDP
38# include <VBox/vrdpapi.h>
39#endif
40#include <iprt/runtime.h>
41#include <iprt/stream.h>
42#include <iprt/ldr.h>
43#include <iprt/getopt.h>
44#include <iprt/env.h>
45
46#ifdef VBOX_FFMPEG
47#include <cstdlib>
48#include <cerrno>
49#include "VBoxHeadless.h"
50#include <iprt/env.h>
51#include <iprt/param.h>
52#include <iprt/process.h>
53#endif
54
55//#define VBOX_WITH_SAVESTATE_ON_SIGNAL
56#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
57#include <signal.h>
58#endif
59
60#ifdef VBOX_WITH_VRDP
61# include "Framebuffer.h"
62#endif
63
64////////////////////////////////////////////////////////////////////////////////
65
66#define LogError(m,rc) \
67 do { \
68 Log (("VBoxHeadless: ERROR: " m " [rc=0x%08X]\n", rc)); \
69 RTPrintf ("%s", m); \
70 } while (0)
71
72////////////////////////////////////////////////////////////////////////////////
73
74/* global weak references (for event handlers) */
75static ComPtr <ISession, ComWeakRef> gSession;
76static ComPtr <IConsole, ComWeakRef> gConsole;
77static EventQueue *gEventQ = NULL;
78
79////////////////////////////////////////////////////////////////////////////////
80
81/**
82 * State change event.
83 */
84class StateChangeEvent : public Event
85{
86public:
87 StateChangeEvent (MachineState_T state) : mState (state) {}
88protected:
89 void *handler()
90 {
91 LogFlow (("VBoxHeadless: StateChangeEvent: %d\n", mState));
92 /* post the termination event if the machine has been PoweredDown/Saved/Aborted */
93 if (mState < MachineState_Running)
94 gEventQ->postEvent (NULL);
95 return 0;
96 }
97private:
98 MachineState_T mState;
99};
100
101/**
102 * Callback handler for machine events.
103 */
104class ConsoleCallback : public IConsoleCallback
105{
106public:
107
108 ConsoleCallback ()
109 {
110#ifndef VBOX_WITH_XPCOM
111 refcnt = 0;
112#endif
113 }
114
115 virtual ~ConsoleCallback() {}
116
117 NS_DECL_ISUPPORTS
118
119#ifndef VBOX_WITH_XPCOM
120 STDMETHOD_(ULONG, AddRef)()
121 {
122 return ::InterlockedIncrement(&refcnt);
123 }
124 STDMETHOD_(ULONG, Release)()
125 {
126 long cnt = ::InterlockedDecrement(&refcnt);
127 if (cnt == 0)
128 delete this;
129 return cnt;
130 }
131 STDMETHOD(QueryInterface) (REFIID riid , void **ppObj)
132 {
133 if (riid == IID_IUnknown)
134 {
135 *ppObj = this;
136 AddRef();
137 return S_OK;
138 }
139 if (riid == IID_IConsoleCallback)
140 {
141 *ppObj = this;
142 AddRef();
143 return S_OK;
144 }
145 *ppObj = NULL;
146 return E_NOINTERFACE;
147 }
148#endif
149
150 STDMETHOD(OnMousePointerShapeChange) (BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
151 ULONG width, ULONG height, BYTE *shape)
152 {
153 return S_OK;
154 }
155
156 STDMETHOD(OnMouseCapabilityChange) (BOOL supportsAbsolute, BOOL needsHostCursor)
157 {
158 /* Emit absolute mouse event to actually enable the host mouse cursor. */
159 if (supportsAbsolute && gConsole)
160 {
161 ComPtr<IMouse> mouse;
162 gConsole->COMGETTER(Mouse)(mouse.asOutParam());
163 if (mouse)
164 {
165 mouse->PutMouseEventAbsolute(-1, -1, 0, 0);
166 }
167 }
168 return S_OK;
169 }
170
171 STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock)
172 {
173 return S_OK;
174 }
175
176 STDMETHOD(OnStateChange) (MachineState_T machineState)
177 {
178 gEventQ->postEvent (new StateChangeEvent (machineState));
179 return S_OK;
180 }
181
182 STDMETHOD(OnExtraDataChange) (BSTR key)
183 {
184 return S_OK;
185 }
186
187 STDMETHOD(OnAdditionsStateChange)()
188 {
189 return S_OK;
190 }
191
192 STDMETHOD(OnDVDDriveChange)()
193 {
194 return S_OK;
195 }
196
197 STDMETHOD(OnFloppyDriveChange)()
198 {
199 return S_OK;
200 }
201
202 STDMETHOD(OnNetworkAdapterChange) (INetworkAdapter *aNetworkAdapter)
203 {
204 return S_OK;
205 }
206
207 STDMETHOD(OnSerialPortChange) (ISerialPort *aSerialPort)
208 {
209 return S_OK;
210 }
211
212 STDMETHOD(OnParallelPortChange) (IParallelPort *aParallelPort)
213 {
214 return S_OK;
215 }
216
217 STDMETHOD(OnVRDPServerChange)()
218 {
219 return S_OK;
220 }
221
222 STDMETHOD(OnUSBControllerChange)()
223 {
224 return S_OK;
225 }
226
227 STDMETHOD(OnUSBDeviceStateChange) (IUSBDevice *aDevice, BOOL aAttached,
228 IVirtualBoxErrorInfo *aError)
229 {
230 return S_OK;
231 }
232
233 STDMETHOD(OnSharedFolderChange) (Scope_T aScope)
234 {
235 return S_OK;
236 }
237
238 STDMETHOD(OnRuntimeError)(BOOL fatal, INPTR BSTR id, INPTR BSTR message)
239 {
240 return S_OK;
241 }
242
243 STDMETHOD(OnCanShowWindow)(BOOL *canShow)
244 {
245 if (!canShow)
246 return E_POINTER;
247 /* Headless windows should not be shown */
248 *canShow = FALSE;
249 return S_OK;
250 }
251
252 STDMETHOD(OnShowWindow) (ULONG64 *winId)
253 {
254 /* OnCanShowWindow() always returns FALSE, so this call should never
255 * happen. */
256 AssertFailed();
257 if (!winId)
258 return E_POINTER;
259 *winId = 0;
260 return E_NOTIMPL;
261 }
262
263private:
264
265#ifndef VBOX_WITH_XPCOM
266 long refcnt;
267#endif
268};
269
270#ifdef VBOX_WITH_XPCOM
271NS_DECL_CLASSINFO (ConsoleCallback)
272NS_IMPL_THREADSAFE_ISUPPORTS1_CI (ConsoleCallback, IConsoleCallback)
273#endif
274
275#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
276static void SaveState(int sig)
277{
278 ComPtr <IProgress> progress = NULL;
279
280/** @todo Deal with nested signals, multithreaded signal dispatching (esp. on windows),
281 * and multiple signals (both SIGINT and SIGTERM in some order).
282 * Consider processing the signal request asynchronously since there are lots of things
283 * which aren't safe (like RTPrintf and printf IIRC) in a signal context. */
284
285 RTPrintf("Signal received, saving state.\n");
286
287 HRESULT rc = gConsole->SaveState(progress.asOutParam());
288 if (FAILED(S_OK))
289 {
290 RTPrintf("Error saving state! rc = 0x%x\n", rc);
291 return;
292 }
293 Assert(progress);
294 LONG cPercent = 0;
295
296 RTPrintf("0%%");
297 RTStrmFlush(g_pStdOut);
298 for (;;)
299 {
300 BOOL fCompleted = false;
301 rc = progress->COMGETTER(Completed)(&fCompleted);
302 if (FAILED(rc) || fCompleted)
303 break;
304 LONG cPercentNow;
305 rc = progress->COMGETTER(Percent)(&cPercentNow);
306 if (FAILED(rc))
307 break;
308 if ((cPercentNow / 10) != (cPercent / 10))
309 {
310 cPercent = cPercentNow;
311 RTPrintf("...%d%%", cPercentNow);
312 RTStrmFlush(g_pStdOut);
313 }
314
315 /* wait */
316 rc = progress->WaitForCompletion(100);
317 }
318
319 HRESULT lrc;
320 rc = progress->COMGETTER(ResultCode)(&lrc);
321 if (FAILED(rc))
322 lrc = ~0;
323 if (!lrc)
324 {
325 RTPrintf(" -- Saved the state successfully.\n");
326 RTThreadYield();
327 }
328 else
329 RTPrintf("-- Error saving state, lrc=%d (%#x)\n", lrc, lrc);
330
331}
332#endif /* VBOX_WITH_SAVESTATE_ON_SIGNAL */
333
334////////////////////////////////////////////////////////////////////////////////
335
336static void show_usage()
337{
338 RTPrintf("Usage:\n"
339 " -s, -startvm, --startvm <name|uuid> Start given VM (required argument)\n"
340#ifdef VBOX_WITH_VRDP
341 " -p, -vrdpport, --vrdpport <port> Port number the VRDP server will bind\n"
342 " to\n"
343 " -a, -vrdpaddress, --vrdpaddress <ip> Interface IP the VRDP will bind to \n"
344#endif
345#ifdef VBOX_FFMPEG
346 " -c, -capture, --capture Record the VM screen output to a file\n"
347 " -w, --width Frame width when recording\n"
348 " -h, --height Frame height when recording\n"
349 " -r, --bitrate Recording bit rate when recording\n"
350 " -f, --filename File name when recording. The codec\n"
351 " used will be chosen based on the\n"
352 " file extension\n"
353#endif
354 "\n");
355}
356
357#ifdef VBOX_FFMPEG
358/**
359 * Parse the environment for variables which can influence the FFMPEG settings.
360 * purely for backwards compatibility.
361 * @param pulFrameWidth may be updated with a desired frame width
362 * @param pulFrameHeight may be updated with a desired frame height
363 * @param pulBitRate may be updated with a desired bit rate
364 * @param ppszFileName may be updated with a desired file name
365 */
366static void parse_environ(unsigned long *pulFrameWidth, unsigned long *pulFrameHeight,
367 unsigned long *pulBitRate, const char **ppszFileName)
368{
369 const char *pszEnvTemp;
370
371 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREWIDTH")) != 0)
372 {
373 errno = 0;
374 unsigned long ulFrameWidth = strtoul(pszEnvTemp, 0, 10);
375 if (errno != 0)
376 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREWIDTH environment variable", 0);
377 else
378 *pulFrameWidth = ulFrameWidth;
379 }
380 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREHEIGHT")) != 0)
381 {
382 errno = 0;
383 unsigned long ulFrameHeight = strtoul(pszEnvTemp, 0, 10);
384 if (errno != 0)
385 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREHEIGHT environment variable", 0);
386 else
387 *pulFrameHeight = ulFrameHeight;
388 }
389 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREBITRATE")) != 0)
390 {
391 errno = 0;
392 unsigned long ulBitRate = strtoul(pszEnvTemp, 0, 10);
393 if (errno != 0)
394 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREBITRATE environment variable", 0);
395 else
396 *pulBitRate = ulBitRate;
397 }
398 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREFILE")) != 0)
399 *ppszFileName = pszEnvTemp;
400}
401#endif /* VBOX_FFMPEG defined */
402
403/**
404 * Entry point.
405 */
406int main (int argc, char **argv)
407{
408#ifdef VBOX_WITH_VRDP
409 ULONG vrdpPort = ~0U;
410 const char *vrdpAddress = NULL;
411#endif
412 unsigned fRawR0 = ~0U;
413 unsigned fRawR3 = ~0U;
414 unsigned fPATM = ~0U;
415 unsigned fCSAM = ~0U;
416#ifdef VBOX_FFMPEG
417 unsigned fFFMPEG = 0;
418 unsigned long ulFrameWidth = 800;
419 unsigned long ulFrameHeight = 600;
420 unsigned long ulBitRate = 300000;
421 char pszMPEGFile[RTPATH_MAX];
422 const char *pszFileNameParam = "VBox-%d.vob";
423#endif /* VBOX_FFMPEG */
424
425 /* Make sure that DISPLAY is unset, so that X11 bits do not get initialised
426 * on X11-using OSes. */
427 /** @todo this should really be taken care of in Main. */
428 RTEnvUnset("DISPLAY");
429 // initialize VBox Runtime
430 RTR3Init(true, ~(size_t)0);
431
432 LogFlow (("VBoxHeadless STARTED.\n"));
433 RTPrintf ("VirtualBox Headless Interface %s\n"
434 "(C) 2008 Sun Microsystems, Inc.\n"
435 "All rights reserved\n\n",
436 VBOX_VERSION_STRING);
437
438 Guid id;
439 /* the below cannot be Bstr because on Linux Bstr doesn't work until XPCOM (nsMemory) is initialized */
440 const char *name = NULL;
441
442#ifdef VBOX_FFMPEG
443 /* Parse the environment */
444 parse_environ(&ulFrameWidth, &ulFrameHeight, &ulBitRate, &pszFileNameParam);
445#endif
446
447 enum eHeadlessOptions
448 {
449 OPT_RAW_R0 = 0x100,
450 OPT_NO_RAW_R0,
451 OPT_RAW_R3,
452 OPT_NO_RAW_R3,
453 OPT_PATM,
454 OPT_NO_PATM,
455 OPT_CSAM,
456 OPT_NO_CSAM,
457 OPT_COMMENT
458 };
459
460 static const RTOPTIONDEF g_aOptions[] =
461 {
462 { "-startvm", 's', RTGETOPT_REQ_STRING },
463 { "--startvm", 's', RTGETOPT_REQ_STRING },
464#ifdef VBOX_WITH_VRDP
465 { "-vrdpport", 'p', RTGETOPT_REQ_UINT32 },
466 { "--vrdpport", 'p', RTGETOPT_REQ_UINT32 },
467 { "-vrdpaddress", 'a', RTGETOPT_REQ_STRING },
468 { "--vrdpaddress", 'a', RTGETOPT_REQ_STRING },
469#endif /* VBOX_WITH_VRDP defined */
470 { "-rawr0", OPT_RAW_R0, 0 },
471 { "--rawr0", OPT_RAW_R0, 0 },
472 { "-norawr0", OPT_NO_RAW_R0, 0 },
473 { "--norawr0", OPT_NO_RAW_R0, 0 },
474 { "-rawr3", OPT_RAW_R3, 0 },
475 { "--rawr3", OPT_RAW_R3, 0 },
476 { "-norawr3", OPT_NO_RAW_R3, 0 },
477 { "--norawr3", OPT_NO_RAW_R3, 0 },
478 { "-patm", OPT_PATM, 0 },
479 { "--patm", OPT_PATM, 0 },
480 { "-nopatm", OPT_NO_PATM, 0 },
481 { "--nopatm", OPT_NO_PATM, 0 },
482 { "-csam", OPT_CSAM, 0 },
483 { "--csam", OPT_CSAM, 0 },
484 { "-nocsam", OPT_NO_CSAM, 0 },
485 { "--nocsam", OPT_NO_CSAM, 0 },
486#ifdef VBOX_FFMPEG
487 { "-capture", 'c', 0 },
488 { "--capture", 'c', 0 },
489 { "--width", 'w', RTGETOPT_REQ_UINT32 },
490 { "--height", 'h', RTGETOPT_REQ_UINT32 },
491 { "--bitrate", 'r', RTGETOPT_REQ_UINT32 },
492 { "--filename", 'f', RTGETOPT_REQ_STRING },
493#endif /* VBOX_FFMPEG defined */
494 { "-comment", OPT_COMMENT, RTGETOPT_REQ_STRING },
495 { "--comment", OPT_COMMENT, RTGETOPT_REQ_STRING }
496 };
497
498 // parse the command line
499 int ch;
500 int i = 1;
501 RTOPTIONUNION ValueUnion;
502 while ((ch = RTGetOpt(argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), &i, &ValueUnion)))
503 {
504 if (ch < 0)
505 {
506 show_usage();
507 exit(-1);
508 }
509 switch(ch)
510 {
511 case 's':
512 id = ValueUnion.psz;
513 /* If the argument was not a UUID, then it must be a name. */
514 if (!id)
515 name = ValueUnion.psz;
516 break;
517#ifdef VBOX_WITH_VRDP
518 case 'p':
519 vrdpPort = ValueUnion.u32;
520 break;
521 case 'a':
522 vrdpAddress = ValueUnion.psz;
523 break;
524#endif /* VBOX_WITH_VRDP defined */
525 case OPT_RAW_R0:
526 fRawR0 = true;
527 break;
528 case OPT_NO_RAW_R0:
529 fRawR0 = false;
530 break;
531 case OPT_RAW_R3:
532 fRawR3 = true;
533 break;
534 case OPT_NO_RAW_R3:
535 fRawR3 = false;
536 break;
537 case OPT_PATM:
538 fPATM = true;
539 break;
540 case OPT_NO_PATM:
541 fPATM = false;
542 break;
543 case OPT_CSAM:
544 fCSAM = true;
545 break;
546 case OPT_NO_CSAM:
547 fCSAM = false;
548 break;
549#ifdef VBOX_FFMPEG
550 case 'c':
551 fFFMPEG = true;
552 break;
553 case 'w':
554 ulFrameWidth = ValueUnion.u32;
555 break;
556 case 'h':
557 ulFrameHeight = ValueUnion.u32;
558 break;
559 case 'r':
560 ulBitRate = ValueUnion.u32;
561 break;
562 case 'f':
563 pszFileNameParam = ValueUnion.psz;
564 break;
565#endif /* VBOX_FFMPEG defined */
566 default: /* comment */
567 break;
568 }
569 }
570
571#ifdef VBOX_FFMPEG
572 if (ulFrameWidth < 512 || ulFrameWidth > 2048 || ulFrameWidth % 2)
573 {
574 LogError("VBoxHeadless: ERROR: please specify an even frame width between 512 and 2048", 0);
575 return -1;
576 }
577 if (ulFrameHeight < 384 || ulFrameHeight > 1536 || ulFrameHeight % 2)
578 {
579 LogError("VBoxHeadless: ERROR: please specify an even frame height between 384 and 1536", 0);
580 return -1;
581 }
582 if (ulBitRate < 300000 || ulBitRate > 1000000)
583 {
584 LogError("VBoxHeadless: ERROR: please specify an even bitrate between 300000 and 1000000", 0);
585 return -1;
586 }
587 /* Make sure we only have %d or %u (or none) in the file name specified */
588 char *pcPercent = (char*)strchr(pszFileNameParam, '%');
589 if (pcPercent != 0 && *(pcPercent + 1) != 'd' && *(pcPercent + 1) != 'u')
590 {
591 LogError("VBoxHeadless: ERROR: Only %%d and %%u are allowed in the capture file name.", -1);
592 return -1;
593 }
594 /* And no more than one % in the name */
595 if (pcPercent != 0 && strchr(pcPercent + 1, '%') != 0)
596 {
597 LogError("VBoxHeadless: ERROR: Only one format modifier is allowed in the capture file name.", -1);
598 return -1;
599 }
600 RTStrPrintf(&pszMPEGFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
601#endif /* defined VBOX_FFMPEG */
602
603 if (!id && !name)
604 {
605 show_usage();
606 return -1;
607 }
608
609 HRESULT rc;
610
611 rc = com::Initialize();
612 if (FAILED (rc))
613 return rc;
614
615 do
616 {
617 ComPtr <IVirtualBox> virtualBox;
618 ComPtr <ISession> session;
619
620 /* create VirtualBox object */
621 rc = virtualBox.createLocalObject (CLSID_VirtualBox);
622 if (FAILED (rc))
623 {
624 com::ErrorInfo info;
625 if (info.isFullAvailable())
626 {
627 RTPrintf("Failed to create VirtualBox object! Error info: '%lS' (component %lS).\n",
628 info.getText().raw(), info.getComponent().raw());
629 }
630 else
631 RTPrintf("Failed to create VirtualBox object! No error information available (rc = 0x%x).\n", rc);
632 break;
633 }
634
635 /* create Session object */
636 rc = session.createInprocObject (CLSID_Session);
637 if (FAILED (rc))
638 {
639 LogError ("Cannot create Session object!", rc);
640 break;
641 }
642
643 /* find ID by name */
644 if (!id)
645 {
646 ComPtr <IMachine> m;
647 rc = virtualBox->FindMachine (Bstr (name), m.asOutParam());
648 if (FAILED (rc))
649 {
650 LogError ("Invalid machine name!\n", rc);
651 break;
652 }
653 m->COMGETTER(Id) (id.asOutParam());
654 AssertComRC (rc);
655 if (FAILED (rc))
656 break;
657 }
658
659 Log (("VBoxHeadless: Opening a session with machine (id={%s})...\n",
660 id.toString().raw()));
661
662 // open a session
663 CHECK_ERROR_BREAK(virtualBox, OpenSession (session, id));
664
665 /* get the console */
666 ComPtr <IConsole> console;
667 CHECK_ERROR_BREAK(session, COMGETTER (Console) (console.asOutParam()));
668
669 /* get the machine */
670 ComPtr <IMachine> machine;
671 CHECK_ERROR_BREAK(console, COMGETTER(Machine) (machine.asOutParam()));
672
673 ComPtr <IDisplay> display;
674 CHECK_ERROR_BREAK(console, COMGETTER(Display) (display.asOutParam()));
675
676#ifdef VBOX_FFMPEG
677 IFramebuffer *pFramebuffer = 0;
678 RTLDRMOD hLdrFFmpegFB;
679 PFNREGISTERFFMPEGFB pfnRegisterFFmpegFB;
680
681 if (fFFMPEG)
682 {
683 int rrc = VINF_SUCCESS, rcc = S_OK;
684
685 Log2(("VBoxHeadless: loading VBoxFFmpegFB shared library\n"));
686 rrc = RTLdrLoad("VBoxFFmpegFB", &hLdrFFmpegFB);
687
688 if (RT_SUCCESS(rrc))
689 {
690 Log2(("VBoxHeadless: looking up symbol VBoxRegisterFFmpegFB\n"));
691 rrc = RTLdrGetSymbol(hLdrFFmpegFB, "VBoxRegisterFFmpegFB",
692 reinterpret_cast<void **>(&pfnRegisterFFmpegFB));
693 if (RT_FAILURE(rrc))
694 LogError("Failed to load the video capture extension, possibly due to a damaged file\n", rrc);
695 }
696 else
697 LogError("Failed to load the video capture extension\n", rrc);
698 if (RT_SUCCESS(rrc))
699 {
700 Log2(("VBoxHeadless: calling pfnRegisterFFmpegFB\n"));
701 rcc = pfnRegisterFFmpegFB(ulFrameWidth, ulFrameHeight, ulBitRate,
702 pszMPEGFile, &pFramebuffer);
703 if (rcc != S_OK)
704 LogError("Failed to initialise video capturing - make sure that the file format\n"
705 "you wish to use is supported on your system\n", rcc);
706 }
707 if (RT_SUCCESS(rrc) && (S_OK == rcc))
708 {
709 Log2(("VBoxHeadless: Registering framebuffer\n"));
710 pFramebuffer->AddRef();
711 display->RegisterExternalFramebuffer(pFramebuffer);
712 }
713 if (!RT_SUCCESS(rrc) || (rcc != S_OK))
714 rc = E_FAIL;
715 }
716 if (rc != S_OK)
717 {
718 return -1;
719 }
720#endif /* defined(VBOX_FFMPEG) */
721
722 ULONG cMonitors = 1;
723 machine->COMGETTER(MonitorCount)(&cMonitors);
724
725#ifdef VBOX_WITH_VRDP
726 unsigned uScreenId;
727 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
728 {
729#ifdef VBOX_FFMPEG
730 if (fFFMPEG && uScreenId == 0)
731 {
732 /* Already registered. */
733 continue;
734 }
735#endif /* defined(VBOX_FFMPEG) */
736 VRDPFramebuffer *pFramebuffer = new VRDPFramebuffer ();
737 if (!pFramebuffer)
738 {
739 RTPrintf("Error: could not create framebuffer object %d\n", uScreenId);
740 return -1;
741 }
742 pFramebuffer->AddRef();
743 display->SetFramebuffer(uScreenId, pFramebuffer);
744 }
745#endif
746
747 /* get the machine debugger (isn't necessarily available) */
748 ComPtr <IMachineDebugger> machineDebugger;
749 console->COMGETTER(Debugger)(machineDebugger.asOutParam());
750 if (machineDebugger)
751 {
752 Log(("Machine debugger available!\n"));
753 }
754
755 if (fRawR0 != ~0U)
756 {
757 if (!machineDebugger)
758 {
759 RTPrintf("Error: No debugger object; -%srawr0 cannot be executed!\n", fRawR0 ? "" : "no");
760 break;
761 }
762 machineDebugger->COMSETTER(RecompileSupervisor)(!fRawR0);
763 }
764 if (fRawR3 != ~0U)
765 {
766 if (!machineDebugger)
767 {
768 RTPrintf("Error: No debugger object; -%srawr3 cannot be executed!\n", fRawR0 ? "" : "no");
769 break;
770 }
771 machineDebugger->COMSETTER(RecompileUser)(!fRawR3);
772 }
773 if (fPATM != ~0U)
774 {
775 if (!machineDebugger)
776 {
777 RTPrintf("Error: No debugger object; -%spatm cannot be executed!\n", fRawR0 ? "" : "no");
778 break;
779 }
780 machineDebugger->COMSETTER(PATMEnabled)(fPATM);
781 }
782 if (fCSAM != ~0U)
783 {
784 if (!machineDebugger)
785 {
786 RTPrintf("Error: No debugger object; -%scsam cannot be executed!\n", fRawR0 ? "" : "no");
787 break;
788 }
789 machineDebugger->COMSETTER(CSAMEnabled)(fCSAM);
790 }
791
792 /* create an event queue */
793 EventQueue eventQ;
794
795 /* initialize global references */
796 gSession = session;
797 gConsole = console;
798 gEventQ = &eventQ;
799
800 /* register a callback for machine events */
801 {
802 ConsoleCallback *callback = new ConsoleCallback ();
803 callback->AddRef();
804 CHECK_ERROR(console, RegisterCallback (callback));
805 callback->Release();
806 if (FAILED (rc))
807 break;
808 }
809
810#ifdef VBOX_WITH_VRDP
811 Log (("VBoxHeadless: Enabling VRDP server...\n"));
812
813 ComPtr <IVRDPServer> vrdpServer;
814 CHECK_ERROR_BREAK(machine, COMGETTER (VRDPServer) (vrdpServer.asOutParam()));
815
816 /* set VRDP port if requested by the user */
817 if (vrdpPort != ~0U)
818 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(Port)(vrdpPort));
819 else
820 CHECK_ERROR_BREAK(vrdpServer, COMGETTER(Port)(&vrdpPort));
821 /* set VRDP address if requested by the user */
822 if (vrdpAddress != NULL)
823 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(NetAddress)(Bstr(vrdpAddress)));
824
825 /* enable VRDP server (only if currently disabled) */
826 BOOL fVRDPEnabled;
827 CHECK_ERROR_BREAK(vrdpServer, COMGETTER(Enabled) (&fVRDPEnabled));
828 if (!fVRDPEnabled)
829 {
830 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(Enabled) (TRUE));
831 }
832#endif
833 Log (("VBoxHeadless: Powering up the machine...\n"));
834#ifdef VBOX_WITH_VRDP
835 RTPrintf("Listening on port %d\n", !vrdpPort ? VRDP_DEFAULT_PORT : vrdpPort);
836#endif
837
838 ComPtr <IProgress> progress;
839 CHECK_ERROR_BREAK(console, PowerUp (progress.asOutParam()));
840
841 /* wait for result because there can be errors */
842 if (SUCCEEDED(progress->WaitForCompletion (-1)))
843 {
844 progress->COMGETTER(ResultCode)(&rc);
845 if (FAILED(rc))
846 {
847 com::ProgressErrorInfo info(progress);
848 if (info.isBasicAvailable())
849 {
850 RTPrintf("Error: failed to start machine. Error message: %lS\n", info.getText().raw());
851 }
852 else
853 {
854 RTPrintf("Error: failed to start machine. No error message available!\n");
855 }
856 }
857 }
858
859#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
860 signal(SIGINT, SaveState);
861 signal(SIGTERM, SaveState);
862#endif
863
864 Log (("VBoxHeadless: Waiting for PowerDown...\n"));
865
866 Event *e;
867
868 while (eventQ.waitForEvent (&e) && e)
869 eventQ.handleEvent (e);
870
871 Log (("VBoxHeadless: event loop has terminated...\n"));
872
873#ifdef VBOX_FFMPEG
874 if (pFramebuffer)
875 {
876 pFramebuffer->Release ();
877 Log(("Released framebuffer\n"));
878 pFramebuffer = NULL;
879 }
880#endif /* defined(VBOX_FFMPEG) */
881
882 /* we don't have to disable VRDP here because we don't save the settings of the VM */
883
884 /*
885 * Close the session. This will also uninitialize the console and
886 * unregister the callback we've registered before.
887 */
888 Log (("VBoxHeadless: Closing the session...\n"));
889 session->Close();
890 }
891 while (0);
892
893 com::Shutdown();
894
895 LogFlow (("VBoxHeadless FINISHED.\n"));
896
897 return rc;
898}
899
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