VirtualBox

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

最後變更 在這個檔案從11442是 11442,由 vboxsync 提交於 17 年 前

VBoxHeadless: added -vrdp on|off|config setting to allow to disable the RDP server or to enable it only if enabled in the .xml config

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.6 KB
 
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.alldomusa.eu.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 " -v, -vrdp, --vrdp on|off|config Enable (default) or disable the VRDP\n"
342 " server or don't change the setting\n"
343 " -p, -vrdpport, --vrdpport <port> Port number the VRDP server will bind\n"
344 " to\n"
345 " -a, -vrdpaddress, --vrdpaddress <ip> Interface IP the VRDP will bind to \n"
346#endif
347#ifdef VBOX_FFMPEG
348 " -c, -capture, --capture Record the VM screen output to a file\n"
349 " -w, --width Frame width when recording\n"
350 " -h, --height Frame height when recording\n"
351 " -r, --bitrate Recording bit rate when recording\n"
352 " -f, --filename File name when recording. The codec\n"
353 " used will be chosen based on the\n"
354 " file extension\n"
355#endif
356 "\n");
357}
358
359#ifdef VBOX_FFMPEG
360/**
361 * Parse the environment for variables which can influence the FFMPEG settings.
362 * purely for backwards compatibility.
363 * @param pulFrameWidth may be updated with a desired frame width
364 * @param pulFrameHeight may be updated with a desired frame height
365 * @param pulBitRate may be updated with a desired bit rate
366 * @param ppszFileName may be updated with a desired file name
367 */
368static void parse_environ(unsigned long *pulFrameWidth, unsigned long *pulFrameHeight,
369 unsigned long *pulBitRate, const char **ppszFileName)
370{
371 const char *pszEnvTemp;
372
373 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREWIDTH")) != 0)
374 {
375 errno = 0;
376 unsigned long ulFrameWidth = strtoul(pszEnvTemp, 0, 10);
377 if (errno != 0)
378 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREWIDTH environment variable", 0);
379 else
380 *pulFrameWidth = ulFrameWidth;
381 }
382 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREHEIGHT")) != 0)
383 {
384 errno = 0;
385 unsigned long ulFrameHeight = strtoul(pszEnvTemp, 0, 10);
386 if (errno != 0)
387 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREHEIGHT environment variable", 0);
388 else
389 *pulFrameHeight = ulFrameHeight;
390 }
391 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREBITRATE")) != 0)
392 {
393 errno = 0;
394 unsigned long ulBitRate = strtoul(pszEnvTemp, 0, 10);
395 if (errno != 0)
396 LogError("VBoxHeadless: ERROR: invalid VBOX_CAPTUREBITRATE environment variable", 0);
397 else
398 *pulBitRate = ulBitRate;
399 }
400 if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREFILE")) != 0)
401 *ppszFileName = pszEnvTemp;
402}
403#endif /* VBOX_FFMPEG defined */
404
405/**
406 * Entry point.
407 */
408int main (int argc, char **argv)
409{
410#ifdef VBOX_WITH_VRDP
411 ULONG vrdpPort = ~0U;
412 const char *vrdpAddress = NULL;
413 const char *vrdpEnabled = NULL;
414#endif
415 unsigned fRawR0 = ~0U;
416 unsigned fRawR3 = ~0U;
417 unsigned fPATM = ~0U;
418 unsigned fCSAM = ~0U;
419#ifdef VBOX_FFMPEG
420 unsigned fFFMPEG = 0;
421 unsigned long ulFrameWidth = 800;
422 unsigned long ulFrameHeight = 600;
423 unsigned long ulBitRate = 300000;
424 char pszMPEGFile[RTPATH_MAX];
425 const char *pszFileNameParam = "VBox-%d.vob";
426#endif /* VBOX_FFMPEG */
427
428 /* Make sure that DISPLAY is unset, so that X11 bits do not get initialised
429 * on X11-using OSes. */
430 /** @todo this should really be taken care of in Main. */
431 RTEnvUnset("DISPLAY");
432 // initialize VBox Runtime
433 RTR3Init(true, ~(size_t)0);
434
435 LogFlow (("VBoxHeadless STARTED.\n"));
436 RTPrintf ("VirtualBox Headless Interface %s\n"
437 "(C) 2008 Sun Microsystems, Inc.\n"
438 "All rights reserved\n\n",
439 VBOX_VERSION_STRING);
440
441 Guid id;
442 /* the below cannot be Bstr because on Linux Bstr doesn't work until XPCOM (nsMemory) is initialized */
443 const char *name = NULL;
444
445#ifdef VBOX_FFMPEG
446 /* Parse the environment */
447 parse_environ(&ulFrameWidth, &ulFrameHeight, &ulBitRate, &pszFileNameParam);
448#endif
449
450 enum eHeadlessOptions
451 {
452 OPT_RAW_R0 = 0x100,
453 OPT_NO_RAW_R0,
454 OPT_RAW_R3,
455 OPT_NO_RAW_R3,
456 OPT_PATM,
457 OPT_NO_PATM,
458 OPT_CSAM,
459 OPT_NO_CSAM,
460 OPT_COMMENT,
461 };
462
463 static const RTOPTIONDEF g_aOptions[] =
464 {
465 { "-startvm", 's', RTGETOPT_REQ_STRING },
466 { "--startvm", 's', RTGETOPT_REQ_STRING },
467#ifdef VBOX_WITH_VRDP
468 { "-vrdpport", 'p', RTGETOPT_REQ_UINT32 },
469 { "--vrdpport", 'p', RTGETOPT_REQ_UINT32 },
470 { "-vrdpaddress", 'a', RTGETOPT_REQ_STRING },
471 { "--vrdpaddress", 'a', RTGETOPT_REQ_STRING },
472 { "-vrdp", 'v', RTGETOPT_REQ_STRING },
473 { "--vrdp", 'v', RTGETOPT_REQ_STRING },
474#endif /* VBOX_WITH_VRDP defined */
475 { "-rawr0", OPT_RAW_R0, 0 },
476 { "--rawr0", OPT_RAW_R0, 0 },
477 { "-norawr0", OPT_NO_RAW_R0, 0 },
478 { "--norawr0", OPT_NO_RAW_R0, 0 },
479 { "-rawr3", OPT_RAW_R3, 0 },
480 { "--rawr3", OPT_RAW_R3, 0 },
481 { "-norawr3", OPT_NO_RAW_R3, 0 },
482 { "--norawr3", OPT_NO_RAW_R3, 0 },
483 { "-patm", OPT_PATM, 0 },
484 { "--patm", OPT_PATM, 0 },
485 { "-nopatm", OPT_NO_PATM, 0 },
486 { "--nopatm", OPT_NO_PATM, 0 },
487 { "-csam", OPT_CSAM, 0 },
488 { "--csam", OPT_CSAM, 0 },
489 { "-nocsam", OPT_NO_CSAM, 0 },
490 { "--nocsam", OPT_NO_CSAM, 0 },
491#ifdef VBOX_FFMPEG
492 { "-capture", 'c', 0 },
493 { "--capture", 'c', 0 },
494 { "--width", 'w', RTGETOPT_REQ_UINT32 },
495 { "--height", 'h', RTGETOPT_REQ_UINT32 },
496 { "--bitrate", 'r', RTGETOPT_REQ_UINT32 },
497 { "--filename", 'f', RTGETOPT_REQ_STRING },
498#endif /* VBOX_FFMPEG defined */
499 { "-comment", OPT_COMMENT, RTGETOPT_REQ_STRING },
500 { "--comment", OPT_COMMENT, RTGETOPT_REQ_STRING }
501 };
502
503 // parse the command line
504 int ch;
505 int i = 1;
506 RTOPTIONUNION ValueUnion;
507 while ((ch = RTGetOpt(argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), &i, &ValueUnion)))
508 {
509 if (ch < 0)
510 {
511 show_usage();
512 exit(-1);
513 }
514 switch(ch)
515 {
516 case 's':
517 id = ValueUnion.psz;
518 /* If the argument was not a UUID, then it must be a name. */
519 if (!id)
520 name = ValueUnion.psz;
521 break;
522#ifdef VBOX_WITH_VRDP
523 case 'p':
524 vrdpPort = ValueUnion.u32;
525 break;
526 case 'a':
527 vrdpAddress = ValueUnion.psz;
528 break;
529 case 'v':
530 vrdpEnabled = ValueUnion.psz;
531 break;
532#endif /* VBOX_WITH_VRDP defined */
533 case OPT_RAW_R0:
534 fRawR0 = true;
535 break;
536 case OPT_NO_RAW_R0:
537 fRawR0 = false;
538 break;
539 case OPT_RAW_R3:
540 fRawR3 = true;
541 break;
542 case OPT_NO_RAW_R3:
543 fRawR3 = false;
544 break;
545 case OPT_PATM:
546 fPATM = true;
547 break;
548 case OPT_NO_PATM:
549 fPATM = false;
550 break;
551 case OPT_CSAM:
552 fCSAM = true;
553 break;
554 case OPT_NO_CSAM:
555 fCSAM = false;
556 break;
557#ifdef VBOX_FFMPEG
558 case 'c':
559 fFFMPEG = true;
560 break;
561 case 'w':
562 ulFrameWidth = ValueUnion.u32;
563 break;
564 case 'h':
565 ulFrameHeight = ValueUnion.u32;
566 break;
567 case 'r':
568 ulBitRate = ValueUnion.u32;
569 break;
570 case 'f':
571 pszFileNameParam = ValueUnion.psz;
572 break;
573#endif /* VBOX_FFMPEG defined */
574 default: /* comment */
575 break;
576 }
577 }
578
579#ifdef VBOX_FFMPEG
580 if (ulFrameWidth < 512 || ulFrameWidth > 2048 || ulFrameWidth % 2)
581 {
582 LogError("VBoxHeadless: ERROR: please specify an even frame width between 512 and 2048", 0);
583 return -1;
584 }
585 if (ulFrameHeight < 384 || ulFrameHeight > 1536 || ulFrameHeight % 2)
586 {
587 LogError("VBoxHeadless: ERROR: please specify an even frame height between 384 and 1536", 0);
588 return -1;
589 }
590 if (ulBitRate < 300000 || ulBitRate > 1000000)
591 {
592 LogError("VBoxHeadless: ERROR: please specify an even bitrate between 300000 and 1000000", 0);
593 return -1;
594 }
595 /* Make sure we only have %d or %u (or none) in the file name specified */
596 char *pcPercent = (char*)strchr(pszFileNameParam, '%');
597 if (pcPercent != 0 && *(pcPercent + 1) != 'd' && *(pcPercent + 1) != 'u')
598 {
599 LogError("VBoxHeadless: ERROR: Only %%d and %%u are allowed in the capture file name.", -1);
600 return -1;
601 }
602 /* And no more than one % in the name */
603 if (pcPercent != 0 && strchr(pcPercent + 1, '%') != 0)
604 {
605 LogError("VBoxHeadless: ERROR: Only one format modifier is allowed in the capture file name.", -1);
606 return -1;
607 }
608 RTStrPrintf(&pszMPEGFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
609#endif /* defined VBOX_FFMPEG */
610
611 if (!id && !name)
612 {
613 show_usage();
614 return -1;
615 }
616
617 HRESULT rc;
618
619 rc = com::Initialize();
620 if (FAILED (rc))
621 return rc;
622
623 do
624 {
625 ComPtr <IVirtualBox> virtualBox;
626 ComPtr <ISession> session;
627
628 /* create VirtualBox object */
629 rc = virtualBox.createLocalObject (CLSID_VirtualBox);
630 if (FAILED (rc))
631 {
632 com::ErrorInfo info;
633 if (info.isFullAvailable())
634 {
635 RTPrintf("Failed to create VirtualBox object! Error info: '%lS' (component %lS).\n",
636 info.getText().raw(), info.getComponent().raw());
637 }
638 else
639 RTPrintf("Failed to create VirtualBox object! No error information available (rc = 0x%x).\n", rc);
640 break;
641 }
642
643 /* create Session object */
644 rc = session.createInprocObject (CLSID_Session);
645 if (FAILED (rc))
646 {
647 LogError ("Cannot create Session object!", rc);
648 break;
649 }
650
651 /* find ID by name */
652 if (!id)
653 {
654 ComPtr <IMachine> m;
655 rc = virtualBox->FindMachine (Bstr (name), m.asOutParam());
656 if (FAILED (rc))
657 {
658 LogError ("Invalid machine name!\n", rc);
659 break;
660 }
661 m->COMGETTER(Id) (id.asOutParam());
662 AssertComRC (rc);
663 if (FAILED (rc))
664 break;
665 }
666
667 Log (("VBoxHeadless: Opening a session with machine (id={%s})...\n",
668 id.toString().raw()));
669
670 // open a session
671 CHECK_ERROR_BREAK(virtualBox, OpenSession (session, id));
672
673 /* get the console */
674 ComPtr <IConsole> console;
675 CHECK_ERROR_BREAK(session, COMGETTER (Console) (console.asOutParam()));
676
677 /* get the machine */
678 ComPtr <IMachine> machine;
679 CHECK_ERROR_BREAK(console, COMGETTER(Machine) (machine.asOutParam()));
680
681 ComPtr <IDisplay> display;
682 CHECK_ERROR_BREAK(console, COMGETTER(Display) (display.asOutParam()));
683
684#ifdef VBOX_FFMPEG
685 IFramebuffer *pFramebuffer = 0;
686 RTLDRMOD hLdrFFmpegFB;
687 PFNREGISTERFFMPEGFB pfnRegisterFFmpegFB;
688
689 if (fFFMPEG)
690 {
691 int rrc = VINF_SUCCESS, rcc = S_OK;
692
693 Log2(("VBoxHeadless: loading VBoxFFmpegFB shared library\n"));
694 rrc = RTLdrLoad("VBoxFFmpegFB", &hLdrFFmpegFB);
695
696 if (RT_SUCCESS(rrc))
697 {
698 Log2(("VBoxHeadless: looking up symbol VBoxRegisterFFmpegFB\n"));
699 rrc = RTLdrGetSymbol(hLdrFFmpegFB, "VBoxRegisterFFmpegFB",
700 reinterpret_cast<void **>(&pfnRegisterFFmpegFB));
701 if (RT_FAILURE(rrc))
702 LogError("Failed to load the video capture extension, possibly due to a damaged file\n", rrc);
703 }
704 else
705 LogError("Failed to load the video capture extension\n", rrc);
706 if (RT_SUCCESS(rrc))
707 {
708 Log2(("VBoxHeadless: calling pfnRegisterFFmpegFB\n"));
709 rcc = pfnRegisterFFmpegFB(ulFrameWidth, ulFrameHeight, ulBitRate,
710 pszMPEGFile, &pFramebuffer);
711 if (rcc != S_OK)
712 LogError("Failed to initialise video capturing - make sure that the file format\n"
713 "you wish to use is supported on your system\n", rcc);
714 }
715 if (RT_SUCCESS(rrc) && (S_OK == rcc))
716 {
717 Log2(("VBoxHeadless: Registering framebuffer\n"));
718 pFramebuffer->AddRef();
719 display->RegisterExternalFramebuffer(pFramebuffer);
720 }
721 if (!RT_SUCCESS(rrc) || (rcc != S_OK))
722 rc = E_FAIL;
723 }
724 if (rc != S_OK)
725 {
726 return -1;
727 }
728#endif /* defined(VBOX_FFMPEG) */
729
730 ULONG cMonitors = 1;
731 machine->COMGETTER(MonitorCount)(&cMonitors);
732
733#ifdef VBOX_WITH_VRDP
734 unsigned uScreenId;
735 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
736 {
737#ifdef VBOX_FFMPEG
738 if (fFFMPEG && uScreenId == 0)
739 {
740 /* Already registered. */
741 continue;
742 }
743#endif /* defined(VBOX_FFMPEG) */
744 VRDPFramebuffer *pFramebuffer = new VRDPFramebuffer ();
745 if (!pFramebuffer)
746 {
747 RTPrintf("Error: could not create framebuffer object %d\n", uScreenId);
748 return -1;
749 }
750 pFramebuffer->AddRef();
751 display->SetFramebuffer(uScreenId, pFramebuffer);
752 }
753#endif
754
755 /* get the machine debugger (isn't necessarily available) */
756 ComPtr <IMachineDebugger> machineDebugger;
757 console->COMGETTER(Debugger)(machineDebugger.asOutParam());
758 if (machineDebugger)
759 {
760 Log(("Machine debugger available!\n"));
761 }
762
763 if (fRawR0 != ~0U)
764 {
765 if (!machineDebugger)
766 {
767 RTPrintf("Error: No debugger object; -%srawr0 cannot be executed!\n", fRawR0 ? "" : "no");
768 break;
769 }
770 machineDebugger->COMSETTER(RecompileSupervisor)(!fRawR0);
771 }
772 if (fRawR3 != ~0U)
773 {
774 if (!machineDebugger)
775 {
776 RTPrintf("Error: No debugger object; -%srawr3 cannot be executed!\n", fRawR0 ? "" : "no");
777 break;
778 }
779 machineDebugger->COMSETTER(RecompileUser)(!fRawR3);
780 }
781 if (fPATM != ~0U)
782 {
783 if (!machineDebugger)
784 {
785 RTPrintf("Error: No debugger object; -%spatm cannot be executed!\n", fRawR0 ? "" : "no");
786 break;
787 }
788 machineDebugger->COMSETTER(PATMEnabled)(fPATM);
789 }
790 if (fCSAM != ~0U)
791 {
792 if (!machineDebugger)
793 {
794 RTPrintf("Error: No debugger object; -%scsam cannot be executed!\n", fRawR0 ? "" : "no");
795 break;
796 }
797 machineDebugger->COMSETTER(CSAMEnabled)(fCSAM);
798 }
799
800 /* create an event queue */
801 EventQueue eventQ;
802
803 /* initialize global references */
804 gSession = session;
805 gConsole = console;
806 gEventQ = &eventQ;
807
808 /* register a callback for machine events */
809 {
810 ConsoleCallback *callback = new ConsoleCallback ();
811 callback->AddRef();
812 CHECK_ERROR(console, RegisterCallback (callback));
813 callback->Release();
814 if (FAILED (rc))
815 break;
816 }
817
818#ifdef VBOX_WITH_VRDP
819 /* default is to enable the RDP server (backward compatibility) */
820 BOOL fVRDPEnable = true;
821 BOOL fVRDPEnabled;
822 ComPtr <IVRDPServer> vrdpServer;
823 CHECK_ERROR_BREAK(machine, COMGETTER (VRDPServer) (vrdpServer.asOutParam()));
824 CHECK_ERROR_BREAK(vrdpServer, COMGETTER(Enabled) (&fVRDPEnabled));
825
826 if (vrdpEnabled != NULL)
827 {
828 /* -vrdp on|off|config */
829 if (!strcmp(vrdpEnabled, "off") || !strcmp(vrdpEnabled, "disable"))
830 fVRDPEnable = false;
831 else if (!strcmp(vrdpEnabled, "config"))
832 {
833 if (!fVRDPEnabled)
834 fVRDPEnable = false;
835 }
836 else if (strcmp(vrdpEnabled, "on") && strcmp(vrdpEnabled, "enable"))
837 {
838 RTPrintf("-vrdp requires an argument (on|off|config)\n");
839 break;
840 }
841 }
842
843 if (fVRDPEnable)
844 {
845 Log (("VBoxHeadless: Enabling VRDP server...\n"));
846
847 /* set VRDP port if requested by the user */
848 if (vrdpPort != ~0U)
849 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(Port)(vrdpPort));
850 else
851 CHECK_ERROR_BREAK(vrdpServer, COMGETTER(Port)(&vrdpPort));
852 /* set VRDP address if requested by the user */
853 if (vrdpAddress != NULL)
854 {
855 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(NetAddress)(Bstr(vrdpAddress)));
856 }
857 /* enable VRDP server (only if currently disabled) */
858 if (!fVRDPEnabled)
859 {
860 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(Enabled) (TRUE));
861 }
862 }
863 else
864 {
865 /* disable VRDP server (only if currently enabled */
866 if (fVRDPEnabled)
867 {
868 CHECK_ERROR_BREAK(vrdpServer, COMSETTER(Enabled) (FALSE));
869 }
870 }
871#endif
872 Log (("VBoxHeadless: Powering up the machine...\n"));
873#ifdef VBOX_WITH_VRDP
874 if (fVRDPEnable)
875 RTPrintf("Listening on port %d\n", !vrdpPort ? VRDP_DEFAULT_PORT : vrdpPort);
876#endif
877
878 ComPtr <IProgress> progress;
879 CHECK_ERROR_BREAK(console, PowerUp (progress.asOutParam()));
880
881 /* wait for result because there can be errors */
882 if (SUCCEEDED(progress->WaitForCompletion (-1)))
883 {
884 progress->COMGETTER(ResultCode)(&rc);
885 if (FAILED(rc))
886 {
887 com::ProgressErrorInfo info(progress);
888 if (info.isBasicAvailable())
889 {
890 RTPrintf("Error: failed to start machine. Error message: %lS\n", info.getText().raw());
891 }
892 else
893 {
894 RTPrintf("Error: failed to start machine. No error message available!\n");
895 }
896 }
897 }
898
899#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
900 signal(SIGINT, SaveState);
901 signal(SIGTERM, SaveState);
902#endif
903
904 Log (("VBoxHeadless: Waiting for PowerDown...\n"));
905
906 Event *e;
907
908 while (eventQ.waitForEvent (&e) && e)
909 eventQ.handleEvent (e);
910
911 Log (("VBoxHeadless: event loop has terminated...\n"));
912
913#ifdef VBOX_FFMPEG
914 if (pFramebuffer)
915 {
916 pFramebuffer->Release ();
917 Log(("Released framebuffer\n"));
918 pFramebuffer = NULL;
919 }
920#endif /* defined(VBOX_FFMPEG) */
921
922 /* we don't have to disable VRDP here because we don't save the settings of the VM */
923
924 /*
925 * Close the session. This will also uninitialize the console and
926 * unregister the callback we've registered before.
927 */
928 Log (("VBoxHeadless: Closing the session...\n"));
929 session->Close();
930 }
931 while (0);
932
933 com::Shutdown();
934
935 LogFlow (("VBoxHeadless FINISHED.\n"));
936
937 return rc;
938}
939
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette