VirtualBox

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

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

typo

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