VirtualBox

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

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

more rebranding

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