From fb123f93f9f5ce42c8e5785d2f8e0edaf951740e Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Wed, 26 Mar 2014 19:21:20 +0000 Subject: Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2. --- src/VBox/Main/Docs-Intro.cpp | 2 +- src/VBox/Main/Makefile.kmk | 330 +- src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c | 330 + src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.h | 64 + src/VBox/Main/cbinding/Makefile.kmk | 178 +- src/VBox/Main/cbinding/VBoxCAPI.cpp | 924 ++ src/VBox/Main/cbinding/VBoxCAPIGlue.c | 330 + src/VBox/Main/cbinding/VBoxCAPIGlue.h.in | 65 + src/VBox/Main/cbinding/VBoxCAPI_v4_2.h | 8983 ++++++++++++++++++++ src/VBox/Main/cbinding/VBoxXPCOMC.cpp | 269 - src/VBox/Main/cbinding/VBoxXPCOMCGlue.c | 242 - src/VBox/Main/cbinding/VBoxXPCOMCGlue.h.in | 59 - src/VBox/Main/cbinding/capiidl.xsl | 2670 ++++++ src/VBox/Main/cbinding/makefile.tstCAPIGlue | 50 + src/VBox/Main/cbinding/makefile.tstXPCOMCGlue | 45 - src/VBox/Main/cbinding/tstCAPIGlue.c | 1112 +++ src/VBox/Main/cbinding/tstXPCOMCCall.c | 759 -- src/VBox/Main/cbinding/tstXPCOMCGlue.c | 381 - src/VBox/Main/cbinding/xpcidl.xsl | 2107 ----- src/VBox/Main/glue/AutoLock.cpp | 85 +- src/VBox/Main/glue/ErrorInfo.cpp | 22 +- src/VBox/Main/glue/EventQueue.cpp | 670 +- src/VBox/Main/glue/NativeEventQueue.cpp | 655 ++ src/VBox/Main/glue/com.cpp | 77 +- src/VBox/Main/glue/constants-python.xsl | 205 +- src/VBox/Main/glue/errorprint.cpp | 2 +- src/VBox/Main/glue/glue-java.xsl | 3113 ++++--- src/VBox/Main/glue/initterm.cpp | 107 +- src/VBox/Main/glue/string.cpp | 4 +- src/VBox/Main/glue/tests/Makefile | 2 +- src/VBox/Main/glue/tests/TestVBox.java | 88 +- src/VBox/Main/glue/tests/TestVBoxNATEngine.java | 187 + src/VBox/Main/glue/vboxapi.py | 1057 ++- src/VBox/Main/glue/xpcom/helpers.cpp | 5 +- src/VBox/Main/idl/VirtualBox.dtd | 55 +- src/VBox/Main/idl/VirtualBox.xidl | 3932 ++++++--- src/VBox/Main/idl/apiwrap-server.xsl | 1394 +++ src/VBox/Main/idl/comimpl.xsl | 36 +- src/VBox/Main/idl/docstrip.xsl | 2 +- src/VBox/Main/idl/doxygen.xsl | 2 +- src/VBox/Main/idl/midl.xsl | 3 +- src/VBox/Main/idl/typemap-shared.inc.xsl | 360 + src/VBox/Main/idl/xpidl.xsl | 45 +- src/VBox/Main/idl/xpidl_iid.xsl | 154 + src/VBox/Main/include/ApplianceImpl.h | 86 +- src/VBox/Main/include/ApplianceImplPrivate.h | 26 +- src/VBox/Main/include/AudioAdapterImpl.h | 2 +- src/VBox/Main/include/AudioSnifferInterface.h | 2 +- src/VBox/Main/include/AutoCaller.h | 2 +- src/VBox/Main/include/BIOSSettingsImpl.h | 3 +- src/VBox/Main/include/BandwidthGroupImpl.h | 2 +- src/VBox/Main/include/ClientToken.h | 105 + src/VBox/Main/include/ClientTokenHolder.h | 99 + src/VBox/Main/include/ClientWatcher.h | 88 + src/VBox/Main/include/ConsoleEvents.h | 2 +- src/VBox/Main/include/ConsoleImpl.h | 201 +- src/VBox/Main/include/ConsoleVRDPServer.h | 72 +- src/VBox/Main/include/DHCPServerImpl.h | 69 +- src/VBox/Main/include/DHCPServerRunner.h | 80 - src/VBox/Main/include/DisplayImpl.h | 215 +- src/VBox/Main/include/DisplayUtils.h | 2 +- src/VBox/Main/include/EmulatedUSBImpl.h | 85 + src/VBox/Main/include/EventImpl.h | 2 +- src/VBox/Main/include/ExtPackManagerImpl.h | 9 +- src/VBox/Main/include/ExtPackUtil.h | 2 +- src/VBox/Main/include/Global.h | 8 + src/VBox/Main/include/GuestCtrlImplPrivate.h | 531 +- src/VBox/Main/include/GuestDirectoryImpl.h | 15 +- src/VBox/Main/include/GuestFileImpl.h | 64 +- src/VBox/Main/include/GuestImpl.h | 51 +- src/VBox/Main/include/GuestProcessImpl.h | 90 +- src/VBox/Main/include/GuestSessionImpl.h | 146 +- src/VBox/Main/include/HGCM.h | 2 +- src/VBox/Main/include/HGCMObjects.h | 2 +- src/VBox/Main/include/HGCMThread.h | 2 +- src/VBox/Main/include/HostHardwareLinux.h | 2 +- src/VBox/Main/include/HostImpl.h | 13 +- src/VBox/Main/include/HostNetworkInterfaceImpl.h | 5 +- src/VBox/Main/include/HostPower.h | 38 +- src/VBox/Main/include/HostUSBDeviceImpl.h | 2 +- src/VBox/Main/include/HostVideoInputDeviceImpl.h | 71 + src/VBox/Main/include/KeyboardImpl.h | 5 +- src/VBox/Main/include/Logging.h | 3 + src/VBox/Main/include/MachineDebuggerImpl.h | 9 +- src/VBox/Main/include/MachineImpl.h | 335 +- src/VBox/Main/include/Matching.h | 2 +- src/VBox/Main/include/MediumAttachmentImpl.h | 8 +- src/VBox/Main/include/MediumFormatImpl.h | 99 +- src/VBox/Main/include/MediumImpl.h | 33 +- src/VBox/Main/include/MediumLock.h | 20 +- src/VBox/Main/include/MouseImpl.h | 72 +- src/VBox/Main/include/NATNetworkImpl.h | 147 + src/VBox/Main/include/NATNetworkServiceRunner.h | 70 + src/VBox/Main/include/NetworkAdapterImpl.h | 2 + src/VBox/Main/include/NetworkServiceRunner.h | 57 + src/VBox/Main/include/Nvram.h | 9 +- src/VBox/Main/include/PCIDeviceAttachmentImpl.h | 62 - src/VBox/Main/include/Performance.h | 178 +- src/VBox/Main/include/PerformanceImpl.h | 2 +- src/VBox/Main/include/ProgressCombinedImpl.h | 192 - src/VBox/Main/include/ProgressImpl.h | 111 +- src/VBox/Main/include/ProgressProxyImpl.h | 2 +- src/VBox/Main/include/RemoteUSBBackend.h | 2 +- src/VBox/Main/include/RemoteUSBDeviceImpl.h | 2 +- src/VBox/Main/include/SessionImpl.h | 47 +- src/VBox/Main/include/SharedFolderImpl.h | 7 +- src/VBox/Main/include/SnapshotImpl.h | 2 + src/VBox/Main/include/StorageControllerImpl.h | 2 +- src/VBox/Main/include/SystemPropertiesImpl.h | 11 +- src/VBox/Main/include/TokenImpl.h | 107 + src/VBox/Main/include/USBControllerImpl.h | 36 +- src/VBox/Main/include/USBDeviceFilterImpl.h | 18 +- src/VBox/Main/include/USBDeviceFiltersImpl.h | 99 + src/VBox/Main/include/USBDeviceImpl.h | 2 +- src/VBox/Main/include/USBGetDevices.h | 2 +- src/VBox/Main/include/UsbWebcamInterface.h | 66 + src/VBox/Main/include/VFSExplorerImpl.h | 4 +- src/VBox/Main/include/VMMDev.h | 12 +- src/VBox/Main/include/VRDEServerImpl.h | 38 +- src/VBox/Main/include/VirtualBoxBase.h | 50 +- src/VBox/Main/include/VirtualBoxClientImpl.h | 3 +- src/VBox/Main/include/VirtualBoxErrorInfoImpl.h | 14 +- src/VBox/Main/include/VirtualBoxImpl.h | 51 +- src/VBox/Main/include/Wrapper.h | 491 ++ src/VBox/Main/include/netif.h | 25 +- src/VBox/Main/include/objectslist.h | 2 +- src/VBox/Main/include/ovfreader.h | 284 +- src/VBox/Main/include/vbox-libhal.h | 2 +- src/VBox/Main/include/win/resource.h | 2 +- src/VBox/Main/src-all/DisplayPNGUtil.cpp | 2 +- src/VBox/Main/src-all/DisplayResampleImage.cpp | 2 +- src/VBox/Main/src-all/DisplayUtils.cpp | 2 +- src/VBox/Main/src-all/EventImpl.cpp | 434 +- src/VBox/Main/src-all/ExtPackManagerImpl.cpp | 109 +- src/VBox/Main/src-all/ExtPackUtil.cpp | 2 +- src/VBox/Main/src-all/Global.cpp | 164 +- src/VBox/Main/src-all/Logging.cpp | 2 +- src/VBox/Main/src-all/ProgressImpl.cpp | 889 +- src/VBox/Main/src-all/SharedFolderImpl.cpp | 46 +- src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp | 27 +- src/VBox/Main/src-all/win/VirtualBox_rgs.xsl | 2 +- src/VBox/Main/src-all/win/comregister.cmd | 26 +- src/VBox/Main/src-client/AudioSnifferInterface.cpp | 6 +- src/VBox/Main/src-client/BusAssignmentManager.cpp | 7 +- src/VBox/Main/src-client/ClientTokenHolder.cpp | 334 + src/VBox/Main/src-client/ConsoleImpl.cpp | 2836 +++--- src/VBox/Main/src-client/ConsoleImpl2.cpp | 1403 ++- src/VBox/Main/src-client/ConsoleImplTeleporter.cpp | 31 +- src/VBox/Main/src-client/ConsoleVRDPServer.cpp | 872 +- src/VBox/Main/src-client/DisplayImpl.cpp | 1665 +++- src/VBox/Main/src-client/EbmlWriter.cpp | 504 ++ src/VBox/Main/src-client/EbmlWriter.h | 291 + src/VBox/Main/src-client/EmulatedUSBImpl.cpp | 692 ++ src/VBox/Main/src-client/GuestCtrlImpl.cpp | 324 +- src/VBox/Main/src-client/GuestCtrlPrivate.cpp | 979 ++- src/VBox/Main/src-client/GuestDirectoryImpl.cpp | 236 +- src/VBox/Main/src-client/GuestDnDImpl.cpp | 2 +- src/VBox/Main/src-client/GuestFileImpl.cpp | 1287 ++- src/VBox/Main/src-client/GuestFsObjInfoImpl.cpp | 3 +- src/VBox/Main/src-client/GuestImpl.cpp | 324 +- src/VBox/Main/src-client/GuestProcessImpl.cpp | 2167 +++-- src/VBox/Main/src-client/GuestSessionImpl.cpp | 2460 +++++- src/VBox/Main/src-client/GuestSessionImplTasks.cpp | 245 +- src/VBox/Main/src-client/HGCM.cpp | 37 +- src/VBox/Main/src-client/HGCMThread.cpp | 6 +- src/VBox/Main/src-client/KeyboardImpl.cpp | 81 +- src/VBox/Main/src-client/MachineDebuggerImpl.cpp | 366 +- src/VBox/Main/src-client/MouseImpl.cpp | 467 +- src/VBox/Main/src-client/Nvram.cpp | 378 +- src/VBox/Main/src-client/PCIRawDevImpl.cpp | 38 +- src/VBox/Main/src-client/RemoteUSBBackend.cpp | 10 +- src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp | 2 +- src/VBox/Main/src-client/SessionImpl.cpp | 599 +- src/VBox/Main/src-client/USBDeviceImpl.cpp | 6 +- src/VBox/Main/src-client/UsbCardReader.cpp | 381 +- src/VBox/Main/src-client/UsbWebcamInterface.cpp | 472 + src/VBox/Main/src-client/VBoxDriversRegister.cpp | 8 +- src/VBox/Main/src-client/VMMDevInterface.cpp | 120 +- src/VBox/Main/src-client/VideoRec.cpp | 885 ++ src/VBox/Main/src-client/VideoRec.h | 39 + src/VBox/Main/src-client/VirtualBoxClientImpl.cpp | 36 +- src/VBox/Main/src-client/win/VBoxC.def | 2 +- src/VBox/Main/src-client/win/VBoxClient-x86.def | 26 + src/VBox/Main/src-client/win/VBoxClient-x86.rc | 67 + src/VBox/Main/src-client/win/dllmain.cpp | 327 +- src/VBox/Main/src-client/xpcom/module.cpp | 27 +- .../Main/src-helper-apps/VBoxExtPackHelperApp.cpp | 6 +- src/VBox/Main/src-helper-apps/VBoxVolInfo.cpp | 96 + src/VBox/Main/src-server/ApplianceImpl.cpp | 263 +- src/VBox/Main/src-server/ApplianceImplExport.cpp | 781 +- src/VBox/Main/src-server/ApplianceImplIO.cpp | 191 +- src/VBox/Main/src-server/ApplianceImplImport.cpp | 1877 +++- src/VBox/Main/src-server/AudioAdapterImpl.cpp | 2 +- src/VBox/Main/src-server/BIOSSettingsImpl.cpp | 19 +- src/VBox/Main/src-server/BandwidthControlImpl.cpp | 26 +- src/VBox/Main/src-server/BandwidthGroupImpl.cpp | 9 +- src/VBox/Main/src-server/ClientToken.cpp | 262 + src/VBox/Main/src-server/ClientWatcher.cpp | 849 ++ src/VBox/Main/src-server/DHCPServerImpl.cpp | 372 +- src/VBox/Main/src-server/DHCPServerRunner.cpp | 151 - src/VBox/Main/src-server/HostDnsService.cpp | 363 + src/VBox/Main/src-server/HostDnsService.h | 236 + .../Main/src-server/HostDnsServiceResolvConf.cpp | 91 + src/VBox/Main/src-server/HostImpl.cpp | 503 +- .../Main/src-server/HostNetworkInterfaceImpl.cpp | 57 +- src/VBox/Main/src-server/HostPower.cpp | 144 +- .../Main/src-server/HostVideoInputDeviceImpl.cpp | 235 + src/VBox/Main/src-server/MachineImpl.cpp | 2724 ++++-- src/VBox/Main/src-server/MachineImplCloneVM.cpp | 50 +- src/VBox/Main/src-server/Matching.cpp | 2 +- src/VBox/Main/src-server/MediumAttachmentImpl.cpp | 42 +- src/VBox/Main/src-server/MediumFormatImpl.cpp | 146 +- src/VBox/Main/src-server/MediumImpl.cpp | 820 +- src/VBox/Main/src-server/MediumLock.cpp | 38 +- src/VBox/Main/src-server/NATEngineImpl.cpp | 4 +- src/VBox/Main/src-server/NATNetworkImpl.cpp | 1115 +++ .../Main/src-server/NATNetworkServiceRunner.cpp | 149 + src/VBox/Main/src-server/NetworkAdapterImpl.cpp | 111 +- src/VBox/Main/src-server/NetworkServiceRunner.cpp | 138 + src/VBox/Main/src-server/ParallelPortImpl.cpp | 2 +- src/VBox/Main/src-server/Performance.cpp | 257 +- src/VBox/Main/src-server/PerformanceImpl.cpp | 2 +- src/VBox/Main/src-server/ProgressProxyImpl.cpp | 2 +- src/VBox/Main/src-server/SerialPortImpl.cpp | 2 +- src/VBox/Main/src-server/SnapshotImpl.cpp | 499 +- src/VBox/Main/src-server/StorageControllerImpl.cpp | 2 +- src/VBox/Main/src-server/SystemPropertiesImpl.cpp | 203 +- src/VBox/Main/src-server/TokenImpl.cpp | 217 + src/VBox/Main/src-server/USBControllerImpl.cpp | 1010 +-- src/VBox/Main/src-server/USBDeviceFilterImpl.cpp | 12 +- src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp | 1089 +++ src/VBox/Main/src-server/VFSExplorerImpl.cpp | 6 +- src/VBox/Main/src-server/VRDEServerImpl.cpp | 107 +- src/VBox/Main/src-server/VirtualBoxImpl.cpp | 1235 ++- .../src-server/darwin/HostDnsServiceDarwin.cpp | 256 + .../Main/src-server/darwin/HostPowerDarwin.cpp | 118 +- src/VBox/Main/src-server/darwin/NetIf-darwin.cpp | 23 +- .../Main/src-server/darwin/PerformanceDarwin.cpp | 67 +- src/VBox/Main/src-server/darwin/iokit.cpp | 6 +- src/VBox/Main/src-server/darwin/iokit.h | 2 +- .../src-server/freebsd/HostHardwareFreeBSD.cpp | 13 +- src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp | 22 +- .../Main/src-server/freebsd/PerformanceFreeBSD.cpp | 13 +- .../src-server/freebsd/USBProxyServiceFreeBSD.cpp | 2 +- .../src-server/generic/AutostartDb-generic.cpp | 4 +- src/VBox/Main/src-server/generic/NetIf-generic.cpp | 51 +- .../Main/src-server/linux/HostDnsServiceLinux.cpp | 233 + .../Main/src-server/linux/HostHardwareLinux.cpp | 5 +- src/VBox/Main/src-server/linux/NetIf-linux.cpp | 133 +- .../Main/src-server/linux/PerformanceLinux.cpp | 336 +- src/VBox/Main/src-server/linux/USBGetDevices.cpp | 16 +- .../Main/src-server/linux/USBProxyServiceLinux.cpp | 2 +- src/VBox/Main/src-server/linux/vbox-libhal.cpp | 2 +- src/VBox/Main/src-server/os2/NetIf-os2.cpp | 11 +- src/VBox/Main/src-server/os2/PerformanceOs2.cpp | 15 +- .../Main/src-server/solaris/DynLoadLibSolaris.cpp | 2 +- .../Main/src-server/solaris/DynLoadLibSolaris.h | 2 +- src/VBox/Main/src-server/solaris/NetIf-solaris.cpp | 133 +- .../Main/src-server/solaris/PerformanceSolaris.cpp | 530 +- .../src-server/solaris/USBProxyServiceSolaris.cpp | 6 +- src/VBox/Main/src-server/win/HostDnsServiceWin.cpp | 233 + src/VBox/Main/src-server/win/HostPowerWin.cpp | 38 +- src/VBox/Main/src-server/win/NetIf-win.cpp | 37 +- src/VBox/Main/src-server/win/PerformanceWin.cpp | 84 +- src/VBox/Main/src-server/win/svchlp.cpp | 2 +- src/VBox/Main/src-server/win/svchlp.h | 2 +- src/VBox/Main/src-server/win/svcmain.cpp | 17 +- src/VBox/Main/src-server/xpcom/server.cpp | 45 +- src/VBox/Main/src-server/xpcom/server.h | 2 +- src/VBox/Main/src-server/xpcom/server_module.cpp | 92 +- src/VBox/Main/testcase/Makefile.kmk | 110 +- src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp | 2 +- src/VBox/Main/testcase/makefile.tstVBoxAPILinux | 48 - src/VBox/Main/testcase/makefile.tstVBoxAPIWin | 88 + src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM | 48 + src/VBox/Main/testcase/tstAPI.cpp | 41 +- src/VBox/Main/testcase/tstCollector.cpp | 539 +- src/VBox/Main/testcase/tstGuestCtrlContextID.cpp | 27 +- src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp | 2 +- src/VBox/Main/testcase/tstMediumLock.cpp | 299 + src/VBox/Main/testcase/tstMouseImpl.cpp | 459 + src/VBox/Main/testcase/tstOVF.cpp | 15 +- src/VBox/Main/testcase/tstUSBLinux.h | 2 +- src/VBox/Main/testcase/tstVBoxAPILinux.cpp | 629 -- src/VBox/Main/testcase/tstVBoxAPIWin.cpp | 2 +- src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp | 655 ++ src/VBox/Main/webservice/MANIFEST.MF.in | 2 +- src/VBox/Main/webservice/Makefile.kmk | 103 +- src/VBox/Main/webservice/platform-xidl.xsl | 2 +- .../Main/webservice/samples/java/jax-ws/Makefile | 2 +- .../webservice/samples/java/jax-ws/Makefile.glue | 2 +- .../Main/webservice/samples/php/clienttest.php | 2 +- src/VBox/Main/webservice/samples/python/Makefile | 2 +- .../Main/webservice/samples/python/Makefile.glue | 2 +- .../Main/webservice/samples/python/clienttest.py | 30 +- src/VBox/Main/webservice/split-soapC.cpp | 2 +- src/VBox/Main/webservice/vboxweb.cpp | 123 +- src/VBox/Main/webservice/vboxweb.h | 19 +- src/VBox/Main/webservice/websrv-cpp.xsl | 78 +- src/VBox/Main/webservice/websrv-nsmap.xsl | 4 +- src/VBox/Main/webservice/websrv-php.xsl | 339 +- src/VBox/Main/webservice/websrv-python.xsl | 9 +- src/VBox/Main/webservice/websrv-shared.inc.xsl | 359 - src/VBox/Main/webservice/websrv-typemap.xsl | 4 +- src/VBox/Main/webservice/websrv-wsdl-service.xsl | 4 +- src/VBox/Main/webservice/websrv-wsdl.xsl | 161 +- src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl | 6 +- src/VBox/Main/webservice/webtest.cpp | 67 +- src/VBox/Main/xml/SchemaDefs.xsl | 4 +- src/VBox/Main/xml/Settings.cpp | 933 +- src/VBox/Main/xml/SettingsConverter.xsl | 1043 --- src/VBox/Main/xml/VirtualBox-settings-common.xsd | 963 --- src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd | 69 - src/VBox/Main/xml/VirtualBox-settings-linux.xsd | 70 - src/VBox/Main/xml/VirtualBox-settings-macosx.xsd | 68 - src/VBox/Main/xml/VirtualBox-settings-os2.xsd | 69 - src/VBox/Main/xml/VirtualBox-settings-solaris.xsd | 69 - src/VBox/Main/xml/VirtualBox-settings-windows.xsd | 69 - src/VBox/Main/xml/VirtualBox-settings.xsd | 1309 +++ src/VBox/Main/xml/ovfreader.cpp | 519 +- 320 files changed, 62954 insertions(+), 24503 deletions(-) create mode 100644 src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c create mode 100644 src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.h create mode 100644 src/VBox/Main/cbinding/VBoxCAPI.cpp create mode 100644 src/VBox/Main/cbinding/VBoxCAPIGlue.c create mode 100644 src/VBox/Main/cbinding/VBoxCAPIGlue.h.in create mode 100644 src/VBox/Main/cbinding/VBoxCAPI_v4_2.h delete mode 100644 src/VBox/Main/cbinding/VBoxXPCOMC.cpp delete mode 100644 src/VBox/Main/cbinding/VBoxXPCOMCGlue.c delete mode 100644 src/VBox/Main/cbinding/VBoxXPCOMCGlue.h.in create mode 100644 src/VBox/Main/cbinding/capiidl.xsl create mode 100644 src/VBox/Main/cbinding/makefile.tstCAPIGlue delete mode 100644 src/VBox/Main/cbinding/makefile.tstXPCOMCGlue create mode 100644 src/VBox/Main/cbinding/tstCAPIGlue.c delete mode 100644 src/VBox/Main/cbinding/tstXPCOMCCall.c delete mode 100644 src/VBox/Main/cbinding/tstXPCOMCGlue.c delete mode 100644 src/VBox/Main/cbinding/xpcidl.xsl create mode 100644 src/VBox/Main/glue/NativeEventQueue.cpp create mode 100644 src/VBox/Main/glue/tests/TestVBoxNATEngine.java mode change 100755 => 100644 src/VBox/Main/glue/vboxapi.py create mode 100644 src/VBox/Main/idl/apiwrap-server.xsl create mode 100644 src/VBox/Main/idl/typemap-shared.inc.xsl create mode 100644 src/VBox/Main/idl/xpidl_iid.xsl create mode 100644 src/VBox/Main/include/ClientToken.h create mode 100644 src/VBox/Main/include/ClientTokenHolder.h create mode 100644 src/VBox/Main/include/ClientWatcher.h delete mode 100644 src/VBox/Main/include/DHCPServerRunner.h create mode 100644 src/VBox/Main/include/EmulatedUSBImpl.h create mode 100644 src/VBox/Main/include/HostVideoInputDeviceImpl.h create mode 100644 src/VBox/Main/include/NATNetworkImpl.h create mode 100644 src/VBox/Main/include/NATNetworkServiceRunner.h create mode 100644 src/VBox/Main/include/NetworkServiceRunner.h delete mode 100644 src/VBox/Main/include/ProgressCombinedImpl.h create mode 100644 src/VBox/Main/include/TokenImpl.h create mode 100644 src/VBox/Main/include/USBDeviceFiltersImpl.h create mode 100644 src/VBox/Main/include/UsbWebcamInterface.h create mode 100644 src/VBox/Main/include/Wrapper.h create mode 100644 src/VBox/Main/src-client/ClientTokenHolder.cpp create mode 100644 src/VBox/Main/src-client/EbmlWriter.cpp create mode 100644 src/VBox/Main/src-client/EbmlWriter.h create mode 100644 src/VBox/Main/src-client/EmulatedUSBImpl.cpp create mode 100644 src/VBox/Main/src-client/UsbWebcamInterface.cpp create mode 100644 src/VBox/Main/src-client/VideoRec.cpp create mode 100644 src/VBox/Main/src-client/VideoRec.h create mode 100644 src/VBox/Main/src-client/win/VBoxClient-x86.def create mode 100644 src/VBox/Main/src-client/win/VBoxClient-x86.rc create mode 100644 src/VBox/Main/src-helper-apps/VBoxVolInfo.cpp create mode 100644 src/VBox/Main/src-server/ClientToken.cpp create mode 100644 src/VBox/Main/src-server/ClientWatcher.cpp delete mode 100644 src/VBox/Main/src-server/DHCPServerRunner.cpp create mode 100644 src/VBox/Main/src-server/HostDnsService.cpp create mode 100644 src/VBox/Main/src-server/HostDnsService.h create mode 100644 src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp create mode 100644 src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp create mode 100644 src/VBox/Main/src-server/NATNetworkImpl.cpp create mode 100644 src/VBox/Main/src-server/NATNetworkServiceRunner.cpp create mode 100644 src/VBox/Main/src-server/NetworkServiceRunner.cpp create mode 100644 src/VBox/Main/src-server/TokenImpl.cpp create mode 100644 src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp create mode 100644 src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp create mode 100644 src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp create mode 100644 src/VBox/Main/src-server/win/HostDnsServiceWin.cpp delete mode 100644 src/VBox/Main/testcase/makefile.tstVBoxAPILinux create mode 100644 src/VBox/Main/testcase/makefile.tstVBoxAPIWin create mode 100644 src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM create mode 100644 src/VBox/Main/testcase/tstMediumLock.cpp create mode 100644 src/VBox/Main/testcase/tstMouseImpl.cpp delete mode 100644 src/VBox/Main/testcase/tstVBoxAPILinux.cpp create mode 100644 src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp delete mode 100644 src/VBox/Main/webservice/websrv-shared.inc.xsl delete mode 100644 src/VBox/Main/xml/SettingsConverter.xsl delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-common.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-linux.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-macosx.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-os2.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-solaris.xsd delete mode 100644 src/VBox/Main/xml/VirtualBox-settings-windows.xsd create mode 100644 src/VBox/Main/xml/VirtualBox-settings.xsd (limited to 'src/VBox/Main') diff --git a/src/VBox/Main/Docs-Intro.cpp b/src/VBox/Main/Docs-Intro.cpp index df647cb8..aca3f65b 100644 --- a/src/VBox/Main/Docs-Intro.cpp +++ b/src/VBox/Main/Docs-Intro.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk index d2b32b0f..302f6815 100644 --- a/src/VBox/Main/Makefile.kmk +++ b/src/VBox/Main/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2004-2012 Oracle Corporation +# Copyright (C) 2004-2014 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -49,21 +49,22 @@ ifneq ($(KBUILD_TARGET),win) ifndef VBOX_WITH_XPCOM $(error "VBox: VBOX_WITH_XPCOM isn't defined") endif - ifneq ($(KBUILD_TARGET),os2) - VBOX_MAIN_DEFS += VBOX_WITH_SYS_V_IPC_SESSION_WATCHER - endif + VBOX_MAIN_DEFS += VBOX_WITH_GENERIC_SESSION_WATCHER endif VBOX_MAIN_DEFS += \ $(if $(VBOX_WITH_RAW_MODE),VBOX_WITH_RAW_MODE,) \ + $(if $(VBOX_WITH_RAW_RING1),VBOX_WITH_RAW_RING1,) \ + $(if $(VBOX_WITH_VMSVGA),VBOX_WITH_VMSVGA,) \ + $(if $(VBOX_WITH_VMSVGA3D),VBOX_WITH_VMSVGA3D,) \ $(if $(VBOX_WITH_NETFLT),VBOX_WITH_NETFLT,) \ $(if $(VBOX_WITH_COPYTOGUEST),VBOX_WITH_COPYTOGUEST,) \ $(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \ $(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \ $(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL,) \ + $(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI,) \ $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \ $(if $(VBOX_WITH_GUEST_PROPS_RDONLY_GUEST),VBOX_WITH_GUEST_PROPS_RDONLY_GUEST,) \ $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,) \ - $(if $(VBOX_WITH_USB_VIDEO),VBOX_WITH_USB_VIDEO,) \ $(if $(VBOX_WITH_USB_CARDREADER),VBOX_WITH_USB_CARDREADER,) \ $(if $(VBOX_WITH_USB_CARDREADER_TEST),VBOX_WITH_USB_CARDREADER_TEST,) \ $(if $(VBOX_WITH_HOSTNETIF_API),VBOX_WITH_HOSTNETIF_API,) \ @@ -100,13 +101,20 @@ if defined(VBOX_ONLY_SDK) || "$(KBUILD_TARGET)" == "win" endif # The XPCOM specific stuff. -if defined(VBOX_ONLY_SDK) || "$(KBUILD_TARGET)" != "win" +# if defined(VBOX_ONLY_SDK) || "$(KBUILD_TARGET)" != "win" -- does not build on Windows +if "$(KBUILD_TARGET)" != "win" OTHERS += $(VBOX_IDL_FILE.XPCOM) $(VBOX_IDL_TYPELIB.XPCOM) $(VBOX_IDL_HEADER.XPCOM) OTHER_CLEAN += \ $(VBOX_IDL_FILE.XPCOM) \ $(VBOX_IDL_HEADER.XPCOM) \ $(VBOX_IDL_TYPELIB.XPCOM) + INSTALLS += VBox-xpcom-bindings-lib + VBox-xpcom-bindings-lib_INST = $(INST_SDK)bindings/xpcom/lib/ + VBox-xpcom-bindings-lib_MODE = a+r,u+w + VBox-xpcom-bindings-lib_SOURCES = $(VBoxCOM_0_OUTDIR)/VirtualBox_XPCOM_i.c=>VirtualBox_i.c + VBox-xpcom-bindings-lib_CLEAN = $(VBoxCOM_0_OUTDIR)/VirtualBox_XPCOM_i.c + VBOX_MAIN_PREREQS += $(VBOX_IDL_TYPELIB.XPCOM) $(VBOX_IDL_HEADER.XPCOM) BLDDIRS += \ $(VBOX_PATH_SDK)/bindings/xpcom/idl \ @@ -161,6 +169,38 @@ docs: $(PATH_TARGET)/docs.Main endif +ifndef VBOX_ONLY_SDK +# +# Generate library with API class wrappers from the XIDL file. +# +LIBRARIES += VBoxAPIWrap +VBoxAPIWrap_TEMPLATE = VBoxMainLib +VBoxAPIWrap_SOURCES = $(VBoxAPIWrap_GENERATEDCPP) +VBoxAPIWrap_GENERATEDCPP = $(filter %.cpp,$(VBoxAPIWrap_GENERATEDSOURCES)) +VBoxAPIWrap_GENERATEDSOURCES = $(addprefix $(VBoxAPIWrap_0_OUTDIR)/,$(VBoxAPIWrap_VBOX_APIWRAPPERFILES)) +VBoxAPIWrap_RAWSRC = \ + $(VBoxAPIWrap_0_OUTDIR)/apiwrappers +VBoxAPIWrap_XSLT = \ + $(VBOX_PATH_MAIN_SRC)/idl/apiwrap-server.xsl +VBoxAPIWrap_DEFS.win.x86 += _WIN32_WINNT=0x0500 +VBoxAPIWrap_DEFS.win.amd64 += _WIN32_WINNT=0x0510 +VBoxAPIWrap_INCS += \ + include +VBoxAPIWrap_CLEAN = \ + $(wildcard $(VBoxAPIWrap_0_OUTDIR)/*.cpp) \ + $(wildcard $(VBoxAPIWrap_0_OUTDIR)/*.h) \ + $(VBoxAPIWrap_RAWSRC) +VBoxAPIWrap_KMK = $(PATH_OUT)/vboxapiwrap.kmk +include $(VBoxAPIWrap_KMK) + +ifdef VBOX_WITH_32_ON_64_MAIN_API +LIBRARIES += VBoxAPIWrap-x86 +VBoxAPIWrap-x86_TEMPLATE = VBoxMainLib-x86 +VBoxAPIWrap-x86_EXTENDS = VBoxAPIWrap +endif + +endif # !VBOX_ONLY_SDK + # # Some SDK bit. # @@ -236,7 +276,10 @@ VBoxSVC_DEFS = \ $(if $(VBOX_WITH_EXTPACK),VBOX_WITH_EXTPACK,) \ $(if $(VBOX_WITH_VUSB),VBOX_WITH_VUSB,) \ $(if $(VBOX_WITH_S3),VBOX_WITH_S3,) \ - $(if $(VBOX_WITH_PCI_PASSTHROUGH),VBOX_WITH_PCI_PASSTHROUGH,) + $(if $(VBOX_WITH_PCI_PASSTHROUGH),VBOX_WITH_PCI_PASSTHROUGH,) \ + $(if $(VBOX_WITH_NAT_SERVICE),VBOX_WITH_NAT_SERVICE,) \ + $(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL,) \ + $(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI,) ifdef VBOX_WITH_USB VBoxSVC_DEFS += \ VBOX_WITH_USB \ @@ -252,10 +295,13 @@ VBoxSVC_DEFS.freebsd += VBOX_USE_LIBHAL VBoxSVC_CXXFLAGS = $(filter-out -Wno-unused,$(TEMPLATE_VBOXMAINEXE_CXXFLAGS)) +VBoxSVC_DEPS = $(filter %.h,$(VBoxAPIWrap_GENERATEDSOURCES)) + VBoxSVC_INCS = \ include \ $(VBoxSVC_0_OUTDIR) \ $(dir $(VBOX_XML_SCHEMADEFS_H)) \ + $(VBoxAPIWrap_0_OUTDIR) \ . VBoxSVC_INCS.win = \ $(VBoxCOM_0_OUTDIR) @@ -265,6 +311,7 @@ ifdef VBOX_WITH_USB endif VBoxSVC_LIBS += \ + $(PATH_STAGE_LIB)/VBoxAPIWrap$(VBOX_SUFF_LIB) \ $(PATH_STAGE_LIB)/SSMStandalone$(VBOX_SUFF_LIB) \ $(LIB_DDU) VBoxSVC_SDKS = VBOX_LIBPNG VBOX_ZLIB @@ -302,12 +349,17 @@ VBoxSVC_SOURCES = \ src-server/BandwidthControlImpl.cpp \ src-server/BandwidthGroupImpl.cpp \ src-server/BIOSSettingsImpl.cpp \ + src-server/ClientWatcher.cpp \ + src-server/ClientToken.cpp \ src-server/DHCPServerImpl.cpp \ - src-server/DHCPServerRunner.cpp \ + src-server/NetworkServiceRunner.cpp \ + src-server/NATNetworkImpl.cpp \ src-server/GuestOSTypeImpl.cpp \ + src-server/HostDnsService.cpp \ src-server/HostImpl.cpp \ src-server/HostNetworkInterfaceImpl.cpp \ src-server/HostPower.cpp \ + src-server/HostVideoInputDeviceImpl.cpp \ src-server/MachineImpl.cpp \ src-server/MachineImplCloneVM.cpp \ src-server/Matching.cpp \ @@ -315,7 +367,6 @@ VBoxSVC_SOURCES = \ src-server/MediumFormatImpl.cpp \ src-server/MediumImpl.cpp \ src-server/MediumLock.cpp \ - $(if $(VBOX_WITH_NAT_SERVICE),src-server/NATServerImpl.cpp,) \ src-server/NATEngineImpl.cpp \ src-server/NetworkAdapterImpl.cpp \ src-server/ParallelPortImpl.cpp \ @@ -324,7 +375,9 @@ VBoxSVC_SOURCES = \ src-server/SnapshotImpl.cpp \ src-server/StorageControllerImpl.cpp \ src-server/SystemPropertiesImpl.cpp \ + src-server/TokenImpl.cpp \ src-server/USBControllerImpl.cpp \ + src-server/USBDeviceFiltersImpl.cpp \ src-server/VFSExplorerImpl.cpp \ src-server/VirtualBoxImpl.cpp \ src-server/VRDEServerImpl.cpp \ @@ -335,23 +388,35 @@ VBoxSVC_SOURCES = \ $(VBOX_AUTOGEN_EVENT_CPP) \ $(if $(VBOX_WITH_XPCOM),src-server/xpcom/server.cpp,) +ifn1of ($(KBUILD_TARGET), win darwin) + VBoxSVC_SOURCES += $(PATH_ROOT)/src/VBox/Devices/Network/slirp/resolv_conf_parser.c +endif + VBoxSVC_SOURCES.darwin = \ src-server/darwin/iokit.cpp \ - src-server/darwin/HostPowerDarwin.cpp + src-server/darwin/HostPowerDarwin.cpp \ + src-server/darwin/HostDnsServiceDarwin.cpp VBoxSVC_SOURCES.win = \ src-server/win/svcmain.cpp \ src-server/win/svchlp.cpp \ src-server/win/HostPowerWin.cpp \ src-server/win/VBoxSVC.rc \ - src-server/win/VBoxComEvents.cpp + src-server/win/VBoxComEvents.cpp \ + src-server/win/HostDnsServiceWin.cpp VBoxSVC_SOURCES.linux = \ - src-server/linux/HostHardwareLinux.cpp + src-server/linux/HostHardwareLinux.cpp \ + src-server/linux/HostDnsServiceLinux.cpp \ + src-server/HostDnsServiceResolvConf.cpp VBoxSVC_SOURCES.solaris = \ src-server/linux/vbox-libhal.cpp \ - src-server/solaris/DynLoadLibSolaris.cpp + src-server/solaris/DynLoadLibSolaris.cpp \ + src-server/HostDnsServiceResolvConf.cpp + +VBoxSVC_SOURCES.os2 = \ + src-server/HostDnsServiceResolvConf.cpp VBoxSVC_SOURCES.freebsd = \ src-server/freebsd/HostHardwareFreeBSD.cpp @@ -404,7 +469,7 @@ ifdef VBOX_WITH_RESOURCE_USAGE_API VBoxSVC_SOURCES.solaris += src-server/solaris/PerformanceSolaris.cpp VBoxSVC_SOURCES.win += src-server/win/PerformanceWin.cpp VBoxSVC_LDFLAGS.darwin += -lproc - VBoxSVC_LDFLAGS.solaris += -lkstat + VBoxSVC_LDFLAGS.solaris += -lkstat -lnvpair VBoxSVC_LDFLAGS.win += psapi.lib powrprof.lib endif @@ -431,39 +496,37 @@ $$(VBoxSVC_0_OUTDIR)/VBoxSVC-icon.rc: $(MAKEFILE_CURRENT) $(VBOX_WINDOWS_ICON_FI $$(VBoxSVC_0_OUTDIR)/VBoxSVC.rgs: $(VBOX_PATH_MAIN_SRC)/src-all/win/VirtualBox_rgs.xsl $(VBOX_XIDL_FILE) | $$(dir $$(@D)) $(VBOX_XSLTPROC) --stringparam Module VBoxSVC -o $@ $< $(VBOX_XIDL_FILE) - +## @todo r=klaus unfortunately we don't have xmllint everywhere, would be +# good to check the validity for every VirtualBox.xidl change. +#$(VBOX_XIDL_FILE).validated.ts: $(VBOX_XIDL_FILE_SRC) +# xmllint --dtdvalid $(VBOX_PATH_MAIN_SRC)/idl/VirtualBox.dtd --noout $< +# $(QUIET)$(CP) --changed -fv $< $(VBOX_XIDL_FILE).validated.ts # -# Embed XML Schema files to VBoxSVC -# -VBOX_XML_SCHEMA_COMMON = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-common.xsd -VBOX_XML_SCHEMA.darwin = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-macosx.xsd -VBOX_XML_SCHEMA.linux = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-linux.xsd -VBOX_XML_SCHEMA.freebsd = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-freebsd.xsd -VBOX_XML_SCHEMA.win = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-windows.xsd -VBOX_XML_SCHEMA.os2 = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-os2.xsd -VBOX_XML_SCHEMA.solaris = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings-solaris.xsd - -VBOX_XML_CONVERTER_TEMPLATE = $(VBOX_PATH_MAIN_SRC)/xml/SettingsConverter.xsl +#OTHERS += $(VBOX_XIDL_FILE).validated.ts +#OTHER_CLEAN += $(VBOX_XIDL_FILE).validated.ts -$$(VBoxSVC_0_OUTDIR)/xml_VirtualBox_settings_xsd.h: $(VBOX_XML_SCHEMA.$(KBUILD_TARGET)) $(VBOX_BIN2C) - $(call MSG_TOOL,bin2c,VBoxSVC,$<,$@) - $(QUIET)$(VBOX_BIN2C) _xml_VirtualBox_settings_xsd $< $@ +testvalidxidl: $(VBOX_XIDL_FILE_SRC) + xmllint --dtdvalid $(VBOX_PATH_MAIN_SRC)/idl/VirtualBox.dtd --noout $< -$$(VBoxSVC_0_OUTDIR)/xml_VirtualBox_settings_common_xsd.h: $(VBOX_XML_SCHEMA_COMMON) $(VBOX_BIN2C) - $(call MSG_TOOL,bin2c,VBoxSVC,$<,$@) - $(QUIET)$(VBOX_BIN2C) _xml_VirtualBox_settings_common_xsd $< $@ -$$(VBoxSVC_0_OUTDIR)/xml_SettingsConverter_xsl.h: $(VBOX_XML_CONVERTER_TEMPLATE) $(VBOX_BIN2C) - $(call MSG_TOOL,bin2c,VBoxSVC,$<,$@) - $(QUIET)$(VBOX_BIN2C) _xml_SettingsConverter_xsl $< $@ +# +# Embed some constraints from XML Schema file into VBoxSVC +# +VBOX_XML_SCHEMA = $(VBOX_PATH_MAIN_SRC)/xml/VirtualBox-settings.xsd -$(VBOX_XML_SCHEMADEFS_H): $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA.$(KBUILD_TARGET)) $(VBOX_XML_SCHEMA_COMMON) | $$(dir $$@) +$(VBOX_XML_SCHEMADEFS_H): $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA) | $$(dir $$@) $(call MSG_GENERATE,SchemaDefs,$@,$<) - $(QUIET)$(VBOX_XSLTPROC) --stringparam mode declare -o $@ $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA.$(KBUILD_TARGET)) + $(QUIET)$(VBOX_XSLTPROC) --stringparam mode declare -o $@ $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA) -$(VBOX_XML_SCHEMADEFS_CPP): $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA.$(KBUILD_TARGET)) $(VBOX_XML_SCHEMA_COMMON) | $$(dir $$@) +$(VBOX_XML_SCHEMADEFS_CPP): $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA) | $$(dir $$@) $(call MSG_GENERATE,SchemaDefs,$@,$<) - $(QUIET)$(VBOX_XSLTPROC) --stringparam mode define -o $@ $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA.$(KBUILD_TARGET)) + $(QUIET)$(VBOX_XSLTPROC) --stringparam mode define -o $@ $(VBOX_XML_SCHEMADEFS_XSL) $(VBOX_XML_SCHEMA) + +testvalidsettings: $(VBOX_XML_SCHEMA) + xmllint --schema $< --noout $(HOME)/.VirtualBox/VirtualBox.xml + xmllint --schema $< --noout $(HOME)/.VirtualBox/Machines/*/*.xml + xmllint --schema $< --noout $(HOME)/.VirtualBox/Machines/*/*.vbox + xmllint --schema $< --noout $(HOME)/VirtualBox\ VMs/*/*.vbox OTHER_CLEAN += $(VBOX_XML_SCHEMADEFS_H) $(VBOX_XML_SCHEMADEFS_CPP) @@ -509,6 +572,14 @@ $$(VBoxSVCM_0_OUTDIR)/VBoxSVCM.def: $(APPEND) $@ _NSGetModule endif VBoxSVCM_INTERMEDIATES += $(VBOX_IDL_HEADER.XPCOM) + + # 32-bit version of the module. + ifdef VBOX_WITH_32_ON_64_MAIN_API +DLLS += VBoxSVCM-x86 +VBoxSVCM-x86_TEMPLATE = VBoxMainComp-x86 +VBoxSVCM-x86_EXTENDS = VBoxSVCM + endif + endif # VBOX_WITH_XPCOM @@ -521,7 +592,6 @@ VBoxC_DEFS = \ IN_RING3 \ $(VBOX_MAIN_DEFS) \ VBOX_COM_INPROC \ - $(if $(VBOX_WITH_VRDP_VIDEO_CHANNEL),VBOX_WITH_VRDP_VIDEO_CHANNEL,) \ $(if $(VBOX_WITH_HGCM),VBOX_WITH_HGCM,) \ $(if $(VBOX_WITH_ALSA),VBOX_WITH_ALSA,) \ $(if $(VBOX_WITH_PULSE),VBOX_WITH_PULSE,) \ @@ -542,20 +612,27 @@ VBoxC_DEFS = \ $(if $(VBOX_WITH_EXTPACK),VBOX_WITH_EXTPACK,) \ $(if $(VBOX_WITH_PCI_PASSTHROUGH),VBOX_WITH_PCI_PASSTHROUGH,) \ $(if $(VBOX_WITH_VPX),VBOX_WITH_VPX,) - +ifdef VBOX_WITH_CRHGSMI + VBoxC_DEFS += VBOX_WITH_CRHGSMI +endif +ifdef VBOX_WITH_NETSHAPER + VBoxC_DEFS += VBOX_WITH_NETSHAPER +endif VBoxC_DEFS.darwin.x86 = VBOX_WITH_2X_4GB_ADDR_SPACE VBoxC_DEFS.win.x86 += _WIN32_WINNT=0x0500 VBoxC_DEFS.win.amd64 += _WIN32_WINNT=0x0510 +VBoxC_SDKS = VBOX_LIBPNG VBOX_ZLIB ifdef VBOX_WITH_VPX - VBoxC_SDKS = VBOX_LIBPNG VBOX_ZLIB VBOX_VPX -else - VBoxC_SDKS = VBOX_LIBPNG VBOX_ZLIB + VBoxC_SDKS += VBOX_VPX endif +VBoxC_DEPS = $(filter %.h,$(VBoxAPIWrap_GENERATEDSOURCES)) + VBoxC_INCS = \ include \ $(VBoxC_0_OUTDIR) \ + $(VBoxAPIWrap_0_OUTDIR) \ $(dir $(VBOX_XML_SCHEMADEFS_H)) VBoxC_INCS.win = \ $(VBoxCOM_0_OUTDIR) \ @@ -565,12 +642,12 @@ VBoxC_LDFLAGS.darwin = \ -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/components/VBoxC.dylib \ -exported_symbols_list $(VBoxC_0_OUTDIR)/VBoxC.def \ -framework IOKit -VBoxC_LDFLAGS.win += /DELAYLOAD:VBoxVMM.dll /MANIFEST +VBoxC_LDFLAGS.win += /MANIFEST VBoxC_LIBS += \ - $(LIB_VMM) \ - $(LIB_REM) - + $(PATH_STAGE_LIB)/VBoxAPIWrap$(VBOX_SUFF_LIB) \ + $(if-expr "$(LIB_VMM)" == "$(VBOX_LIB_VMM_LAZY)",$(LIB_REM),) \ + $(VBOX_LIB_VMM_LAZY) ifdef VBOX_WITH_NETFLT VBoxC_LIBS.win += \ $(PATH_STAGE_LIB)/VBoxDrvCfg$(VBOX_SUFF_LIB) \ @@ -586,9 +663,8 @@ ifdef VBOX_WITH_CROGL VBoxC_LDFLAGS.darwin += -framework OpenGL endif - -VBoxC_INTERMEDIATES = \ - $(VBOX_MAIN_PREREQS) \ +VBoxC_INTERMEDIATES = \ + $(VBOX_MAIN_PREREQS) \ $(VBOX_XML_SCHEMADEFS_H) \ $(VBOX_AUTOGEN_EVENT_H) @@ -606,18 +682,20 @@ VBoxC_SOURCES = \ src-all/VirtualBoxBase.cpp \ src-all/VirtualBoxErrorInfoImpl.cpp \ $(if $(VBOX_WITH_EXTPACK),src-all/ExtPackManagerImpl.cpp src-all/ExtPackUtil.cpp,) \ - $(if $(VBOX_WITH_USB_VIDEO),src-client/UsbWebcamInterface.cpp,) \ + src-client/UsbWebcamInterface.cpp \ $(if $(VBOX_WITH_USB_CARDREADER),src-client/UsbCardReader.cpp,) \ src-client/Nvram.cpp \ src-client/AdditionsFacilityImpl.cpp \ src-client/AudioSnifferInterface.cpp \ src-client/BusAssignmentManager.cpp \ $(if $(VBOX_WITH_PCI_PASSTHROUGH),src-client/PCIRawDevImpl.cpp,) \ + src-client/ClientTokenHolder.cpp \ src-client/ConsoleImpl.cpp \ src-client/ConsoleImpl2.cpp \ src-client/ConsoleImplTeleporter.cpp \ src-client/ConsoleVRDPServer.cpp \ src-client/DisplayImpl.cpp \ + src-client/EmulatedUSBImpl.cpp \ src-client/GuestImpl.cpp \ src-client/GuestDirectoryImpl.cpp \ src-client/GuestFileImpl.cpp \ @@ -640,49 +718,35 @@ VBoxC_SOURCES.win = \ src-client/win/dllmain.cpp \ src-client/win/VBoxC.def \ src-client/win/VBoxC.rc - ifdef VBOX_WITH_GUEST_CONTROL -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/GuestSessionImplTasks.cpp \ src-client/GuestCtrlPrivate.cpp endif - ifdef VBOX_WITH_DRAG_AND_DROP -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/GuestDnDImpl.cpp endif - ifdef VBOX_WITH_XPCOM -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/xpcom/module.cpp endif - ifdef VBOX_WITH_HGCM -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/HGCMObjects.cpp \ src-client/HGCMThread.cpp \ src-client/HGCM.cpp endif - -ifdef VBOX_WITH_CRHGSMI -VBoxC_DEFS += VBOX_WITH_CRHGSMI -endif - ifdef VBOX_WITH_USB -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/RemoteUSBBackend.cpp endif - ifdef VBOX_WITH_VPX -VBoxC_SOURCES += \ + VBoxC_SOURCES += \ src-client/EbmlWriter.cpp \ src-client/VideoRec.cpp endif -ifdef VBOX_WITH_NETSHAPER -VBoxC_DEFS += VBOX_WITH_NETSHAPER -endif - ifeq ($(KBUILD_TARGET),darwin) VBoxC_ORDERDEPS += $(VBoxC_0_OUTDIR)/VBoxC.def VBoxC_CLEAN += $(VBoxC_0_OUTDIR)/VBoxC.def @@ -702,12 +766,64 @@ VBoxC_CLEAN.win += $(VBoxC_0_OUTDIR)/VBoxC.rgs $$(VBoxC_0_OUTDIR)/VBoxC.rgs: $(VBOX_PATH_MAIN_SRC)/src-all/win/VirtualBox_rgs.xsl $(VBOX_XIDL_FILE) | $$(dir $$@) $(VBOX_XSLTPROC) --stringparam Module VBoxC -o $@ $< $(VBOX_XIDL_FILE) +ifdef VBOX_WITH_32_ON_64_MAIN_API + # + # 32-bit VBox API Client In-Process module. + # + # This is currently just a 32-bit version of VBoxC. It might be desirable to + # split up VBoxC into a simple client and a VM client part later, in which + # case this module will be a simple client. + # + # Note! One important thing is that the typelib for this DLL must be build + # with the /env win32 switch and the VBoxC typelib with /env amd64, if + # not they will overwrite each others typelib module entry. + # + DLLS += VBoxClient-x86 + VBoxClient-x86_TEMPLATE = VBoxMainComp-x86 + VBoxClient-x86_EXTENDS = VBoxC + VBoxClient-x86_DEFS = VBOX_COM_INPROC_API_CLIENT $(VBoxC_DEFS) + VBoxClient-x86_INCS.win = \ + $(VBoxClient-x86_0_OUTDIR) \ + $(VBoxCOM-x86_0_OUTDIR) \ + $(VBoxC_INCS.win) + VBoxClient-x86_SOURCES = \ + src-all/EventImpl.cpp \ + src-all/Global.cpp \ + src-all/VirtualBoxBase.cpp \ + src-all/VirtualBoxErrorInfoImpl.cpp \ + src-client/ClientTokenHolder.cpp \ + src-client/SessionImpl.cpp \ + src-client/VirtualBoxClientImpl.cpp \ + $(VBOX_AUTOGEN_EVENT_CPP) \ + $(VBOX_XML_SCHEMADEFS_CPP) + VBoxClient-x86_SOURCES.win = \ + src-client/win/dllmain.cpp \ + src-client/win/VBoxClient-x86.def \ + src-client/win/VBoxClient-x86.rc + ifdef VBOX_WITH_XPCOM + VBoxClient-x86_SOURCES += \ + src-client/xpcom/module.cpp + endif + VBoxClient-x86_LIBS = $(NO_SUCH_VARIABLE) + VBoxClient-x86_LIBS.win = $(NO_SUCH_VARIABLE) + VBoxClient-x86_CLEAN.win += $$(VBoxClient-x86_0_OUTDIR)/VBoxClient-x86.rgs + src-client/win/VBoxClient-x86.rc_DEPS = \ + $(VBoxClient-x86_0_OUTDIR)/VBoxClient-x86.rgs \ + $(VBoxCOM-x86_0_OUTDIR)/VirtualBox-x86.tlb + + $$(VBoxClient-x86_0_OUTDIR)/VBoxClient-x86.rgs: \ + $(VBOX_PATH_MAIN_SRC)/src-all/win/VirtualBox_rgs.xsl \ + $(VBOX_XIDL_FILE) | $$(dir $$@) + $(VBOX_XSLTPROC) --stringparam Module VBoxC -o $@ $< $(VBOX_XIDL_FILE) + +endif + # # VBoxCOM - COM Abstraction Layer library # LIBRARIES += VBoxCOM -VBoxCOM_TEMPLATE = VBOXMAINLIB +VBoxCOM_TEMPLATE = VBoxMainLib VBoxCOM_INTERMEDIATES = $(VBOX_MAIN_PREREQS) VBoxCOM_SOURCES = \ glue/com.cpp \ @@ -715,22 +831,33 @@ VBoxCOM_SOURCES = \ glue/string.cpp \ glue/AutoLock.cpp \ glue/EventQueue.cpp \ + glue/NativeEventQueue.cpp \ glue/ErrorInfo.cpp \ glue/errorprint.cpp VBoxCOM_INCS += \ include ifeq ($(KBUILD_TARGET),win) - VBoxCOM_DEFS.x86 += _WIN32_WINNT=0x0500 - VBoxCOM_DEFS.amd64 += _WIN32_WINNT=0x0510 + VBoxCOM_DEFS.x86 = _WIN32_WINNT=0x0500 + VBoxCOM_DEFS.amd64 = _WIN32_WINNT=0x0510 VBoxCOM_SOURCES += \ $(VBoxCOM_0_OUTDIR)/VirtualBox_i.c else # !win VBoxCOM_SOURCES += \ + $(VBoxCOM_0_OUTDIR)/VirtualBox_XPCOM_i.c \ glue/xpcom/helpers.cpp endif # !win glue/com.cpp_DEFS = \ - $(if $(VBOX_BLEEDING_EDGE),VBOX_BLEEDING_EDGE=\"$(VBOX_BLEEDING_EDGE)\",) + $(if $(VBOX_BLEEDING_EDGE),VBOX_BLEEDING_EDGE=\"$(VBOX_BLEEDING_EDGE)\",) \ + KBUILD_TYPE=\"$(KBUILD_TYPE)\" + +# 32-bit version of VBoxCOM. +ifdef VBOX_WITH_32_ON_64_MAIN_API + LIBRARIES += VBoxCOM-x86 + VBoxCOM-x86_TEMPLATE = VBoxMainLib-x86 + VBoxCOM-x86_EXTENDS = VBoxCOM +endif + # @@ -748,6 +875,15 @@ ifdef VBOX_WITH_EXTPACK $(LIB_RUNTIME) endif # VBOX_WITH_EXTPACK +# +# VolInfo +# +ifdef VBOX_WITH_DEVMAPPER + PROGRAMS.linux += VBoxVolInfo + VBoxVolInfo_TEMPLATE = VBoxR3SetUidToRoot + VBoxVolInfo_SOURCES = src-helper-apps/VBoxVolInfo.cpp + VBoxVolInfo_LIBS = devmapper +endif endif # !VBOX_ONLY_SDK (the ifndef is far above) @@ -808,23 +944,40 @@ $(VBOX_IDL_FILE.MSCOM): $(VBOX_PATH_MAIN_SRC)/idl/midl.xsl $(VBOX_XIDL_FILE) | $ # Aliases for testing purposes. ifdef VBOX_WITH_XPCOM -testidl: $(VBOX_IDL_FILE.XPCOM) $(VBOX_IDL_TYPELIB.XPCOM) +testidl: $(VBOX_IDL_FILE.XPCOM) $(VBOX_IDL_TYPELIB.XPCOM) $(VBoxCOM_0_OUTDIR)/VirtualBox_XPCOM_i.c testidlhdr: $(VBOX_IDL_HEADER.XPCOM) else -testidl: $(VBOX_IDL_FILE.MSCOM) $(VBoxCOM_0_OUTDIR)/VirtualBox_i.c +testidl: $(VBOX_IDL_FILE.MSCOM) $(VBoxCOM_0_OUTDIR)/VirtualBox_i.c \ + $(if $(VBOX_WITH_32_ON_64_MAIN_API),$(VBoxCOM-x86_0_OUTDIR)/VirtualBox_i.c,) endif +$(VBoxCOM_0_OUTDIR)/VirtualBox_XPCOM_i.c: $(VBOX_PATH_MAIN_SRC)/idl/xpidl_iid.xsl $(VBOX_XIDL_FILE) | $$(dir $$@) + $(call MSG_TOOL,xsltproc,VBoxSVC,$<,$@) + $(QUIET)$(VBOX_XSLTPROC) -o $@ $< $(VBOX_XIDL_FILE) + $(VBoxCOM_0_OUTDIR)/VirtualBox_i.c \ + $(VBoxCOM_0_OUTDIR)/VirtualBox.h \ + $(VBoxCOM_0_OUTDIR)/VirtualBox.tlb: $(VBOX_IDL_FILE.MSCOM) | $$(dir $$@) $(VBOX_WIN_MIDL) /nologo \ + $(if-expr "$(KBUILD_TARGET_ARCH)" == "amd64" && "$(KBUILD_HOST)" == "win",/env amd64,/env win32) /target NT51 \ /out $(call VBOX_FN_MAKE_WIN_PATH,$(VBoxCOM_0_OUTDIR)) \ /cpp_cmd $(subst $(EXEC_X86_WIN32),,$(call VBOX_FN_MAKE_WIN_PATH,$(TOOL_$(VBOX_VCC_TOOL)_CC))) \ /I $(call VBOX_FN_MAKE_WIN_PATH,$(PATH_SDK_$(VBOX_WINPSDK)_INC)) \ /I idl \ $(call VBOX_FN_MAKE_WIN_PATH,$<) +$(VBoxCOM-x86_0_OUTDIR)/VirtualBox_i.c \ ++ $(VBoxCOM-x86_0_OUTDIR)/VirtualBox.h \ ++ $(VBoxCOM-x86_0_OUTDIR)/VirtualBox-x86.tlb: $(VBOX_IDL_FILE.MSCOM) | $$(dir $$@) + $(VBOX_WIN_MIDL) /nologo /env win32 /target NT51 \ + /out $(call VBOX_FN_MAKE_WIN_PATH,$(VBoxCOM-x86_0_OUTDIR)) \ + /tlb $(call VBOX_FN_MAKE_WIN_PATH,$(VBoxCOM-x86_0_OUTDIR)/VirtualBox-x86.tlb) \ + /cpp_cmd $(subst $(EXEC_X86_WIN32),,$(call VBOX_FN_MAKE_WIN_PATH,$(TOOL_$(VBOX_VCC_TOOL_STEM)X86_CC))) \ + /I $(call VBOX_FN_MAKE_WIN_PATH,$(PATH_SDK_$(VBOX_WINPSDK)_INC)) \ + /I idl \ + $(call VBOX_FN_MAKE_WIN_PATH,$<) + # # Translation stuff # @@ -890,7 +1043,7 @@ $$(VBOX_JMSCOM_JAR): $(VBOX_JMSCOM_GEN)/jmscomglue.list | $$(dir $$@) $(call MSG_TOOL,javac,$(notdir $@),...,) $(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) \ @$(VBOX_JMSCOM_GEN)/jmscomglue.list \ - -d $(VBOX_JMSCOM_JDEST) -classpath $(VBOX_JMSCOM_JDEST)$(VBOX_SEP)$(VBOX_JACOB_DIR)/jacob.jar + -d $(VBOX_JMSCOM_JDEST) -classpath "$(VBOX_JMSCOM_JDEST)$(VBOX_SEP)$(VBOX_JACOB_DIR)/jacob.jar" $(call MSG_LINK,$(notdir $@),$@) $(VBOX_JAR) cf $@ -C $(VBOX_JMSCOM_JDEST) . @@ -908,6 +1061,25 @@ javagluesample_SOURCES = \ $(VBOX_PATH_MAIN_SRC)/glue/tests/TestVBox.java=>TestVBox.java \ $(VBOX_PATH_MAIN_SRC)/glue/tests/Makefile=>Makefile +# moved those rules to the end so that VBoxAPIWrap_0_OUTDIR can be expanded without $$ trickery +$(VBoxAPIWrap_RAWSRC) \ ++| $(VBoxAPIWrap_GENERATEDSOURCES): \ + $(VBOX_XIDL_FILE) \ + $(VBoxAPIWrap_XSLT) \ + $(VBOX_FILESPLIT) \ + | $$(dir $$@) + $(call MSG_L1,Generating C++ Server API wrapper files from XIDL) + $(QUIET)$(RM) -f $(filter-out $(VBoxAPIWrap_GENERATEDSOURCES),$(wildcard $(VBoxAPIWrap_0_OUTDIR)/*.cpp) $(wildcard $(VBoxAPIWrap_0_OUTDIR)/*.h)) + $(QUIET)$(VBOX_XSLTPROC) --stringparam filelistonly "" -o $@ $(VBoxAPIWrap_XSLT) $< + $(QUIET)$(VBOX_FILESPLIT) $@ $(VBoxAPIWrap_0_OUTDIR) + +$(VBoxAPIWrap_KMK).ts +| $(VBoxAPIWrap_KMK): $(VBOX_XIDL_FILE) $(VBoxAPIWrap_XSLT) + $(call MSG_GENERATE,,$(VBoxAPIWrap_KMK)) + $(QUIET)$(RM) -f $@ + $(QUIET)$(MKDIR) -p $(@D) + $(QUIET)$(VBOX_XSLTPROC) --stringparam filelistonly VBoxAPIWrap_VBOX_APIWRAPPERFILES -o $@ $(VBoxAPIWrap_XSLT) $< + $(QUIET)$(CP) --changed -fv $@ $(VBoxAPIWrap_KMK) + updatenls:: $(VBOX_LUPDATE) $(VBoxSVC_SOURCES) $(VBoxSVC_VBOX_HEADERS) -ts $(VBoxSVC_VBOX_TRANSLATIONS) $(VBOX_LUPDATE) $(VBoxC_SOURCES) $(VBoxC_VBOX_HEADERS) -ts $(VBoxC_VBOX_TRANSLATIONS) diff --git a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c new file mode 100644 index 00000000..3a5e698d --- /dev/null +++ b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c @@ -0,0 +1,330 @@ +/* $Revision: 91907 $ */ +/** @file VBoxXPCOMCGlue.c + * Glue code for dynamically linking to VBoxCAPI, LEGACY VARIANT. + */ + +/* + * Copyright (C) 2008-2014 Oracle Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "VBoxXPCOMCGlue.h" + +#include +#include +#include +#include +#include +#ifndef WIN32 +# include +# include +#else /* WIN32 */ +# include +#endif /* WIN32 */ + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__) +# define DYNLIB_NAME "VBoxXPCOMC.so" +#elif defined(__APPLE__) +# define DYNLIB_NAME "VBoxXPCOMC.dylib" +#elif defined(__OS2__) +# define DYNLIB_NAME "VBoxXPCOMC.dll" +#elif defined(WIN32) +# define DYNLIB_NAME "VBoxCAPI.dll" +#else +# error "Port me" +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +void *g_hVBoxCAPI = NULL; +#else /* WIN32 */ +HMODULE g_hVBoxCAPI = NULL; +#endif /* WIN32 */ +/** The last load error. */ +char g_szVBoxErrMsg[256] = ""; +/** Pointer to the VBOXCAPI function table. */ +PCVBOXCAPI g_pVBoxFuncs = NULL; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions = NULL; + +typedef void FNDUMMY(void); +typedef FNDUMMY *PFNDUMMY; +/** Just a dummy global structure containing a bunch of + * function pointers to code which is wanted in the link. */ +PFNDUMMY g_apfnVBoxCAPIGlue[] = +{ +#ifndef WIN32 + /* The following link dependency is for helping gdb as it gets hideously + * confused if the application doesn't drag in pthreads, but uses it. */ + (PFNDUMMY)pthread_create, +#endif /* !WIN32 */ + NULL +}; + + +/** + * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub. + * + * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty. + * @param pszFormat The format string. + * @param ... The arguments. + */ +static void setErrMsg(int fAlways, const char *pszFormat, ...) +{ + if ( fAlways + || !g_szVBoxErrMsg[0]) + { + va_list va; + va_start(va, pszFormat); + vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va); + va_end(va); + } +} + + +/** + * Try load C API .so/dylib/dll from the specified location and resolve all + * the symbols we need. Tries both the new style and legacy name. + * + * @returns 0 on success, -1 on failure. + * @param pszHome The directory where to try load VBoxCAPI/VBoxXPCOMC + * from. Can be NULL. + * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not + * (boolean). + */ +static int tryLoadLibrary(const char *pszHome, int fSetAppHome) +{ + size_t cchHome = pszHome ? strlen(pszHome) : 0; + size_t cbBufNeeded; + char szName[4096]; + + /* + * Construct the full name. + */ + cbBufNeeded = cchHome + sizeof("/" DYNLIB_NAME); + if (cbBufNeeded > sizeof(szName)) + { + setErrMsg(1, "path buffer too small: %u bytes needed", + (unsigned)cbBufNeeded); + return -1; + } + if (cchHome) + { + memcpy(szName, pszHome, cchHome); + szName[cchHome] = '/'; + cchHome++; + } + memcpy(&szName[cchHome], DYNLIB_NAME, sizeof(DYNLIB_NAME)); + + /* + * Try load it by that name, setting the VBOX_APP_HOME first (for now). + * Then resolve and call the function table getter. + */ + if (fSetAppHome) + { +#ifndef WIN32 + if (pszHome) + setenv("VBOX_APP_HOME", pszHome, 1 /* always override */); + else + unsetenv("VBOX_APP_HOME"); +#endif /* !WIN32 */ + } + +#ifndef WIN32 + g_hVBoxCAPI = dlopen(szName, RTLD_NOW | RTLD_LOCAL); + if (g_hVBoxCAPI) + { + PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions; + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); +#ifdef VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME + if (!pfnGetFunctions) + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME); +#endif /* VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME */ + if (pfnGetFunctions) + { + g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION); + if (g_pVBoxFuncs) + { + g_pfnGetFunctions = pfnGetFunctions; + return 0; + } + + /* bail out */ + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", + szName, VBOX_CAPI_VERSION); + } + else + setErrMsg(1, "dlsym(%.80s/%.32s): %.128s", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, dlerror()); + dlclose(g_hVBoxCAPI); + g_hVBoxCAPI = NULL; + } + else + setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror()); +#else /* !WIN32 */ + g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */, 0 /* dwFlags */); + if (g_hVBoxCAPI) + { + PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions; + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS) + GetProcAddress(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); + if (pfnGetFunctions) + { + g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION); + if (g_pVBoxFuncs) + { + g_pfnGetFunctions = pfnGetFunctions; + return 0; + } + + /* bail out */ + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", + szName, VBOX_CAPI_VERSION); + } + else + setErrMsg(1, "GetProcAddress(%.80s/%.32s): %d", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, GetLastError()); + FreeLibrary(g_hVBoxCAPI); + g_hVBoxCAPI = NULL; + } + else + setErrMsg(0, "LoadLibraryEx(%.80s): %d", szName, GetLastError()); +#endif /* !WIN32 */ + + return -1; +} + + +/** + * Tries to locate and load VBoxCAPI.so/dylib/dll, resolving all the related + * function pointers. + * + * @returns 0 on success, -1 on failure. + * + * @remark This should be considered moved into a separate glue library since + * its its going to be pretty much the same for any user of VBoxCAPI + * and it will just cause trouble to have duplicate versions of this + * source code all around the place. + */ +int VBoxCGlueInit(void) +{ + const char *pszHome; + + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); + + /* + * If the user specifies the location, try only that. + */ + pszHome = getenv("VBOX_APP_HOME"); + if (pszHome) + return tryLoadLibrary(pszHome, 0); + + /* + * Try the known standard locations. + */ +#if defined(__gnu__linux__) || defined(__linux__) + if (tryLoadLibrary("/opt/VirtualBox", 1) == 0) + return 0; + if (tryLoadLibrary("/usr/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__sun__) + if (tryLoadLibrary("/opt/VirtualBox/amd64", 1) == 0) + return 0; + if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0) + return 0; +#elif defined(__APPLE__) + if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0) + return 0; +#elif defined(__FreeBSD__) + if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__OS2__) + if (tryLoadLibrary("C:/Apps/VirtualBox", 1) == 0) + return 0; +#elif defined(WIN32) + pszHome = getenv("ProgramFiles"); + if (pszHome) + { + char szPath[4096]; + size_t cb = sizeof(szPath); + char *tmp = szPath; + strncpy(tmp, pszHome, cb); + tmp[cb - 1] = '\0'; + cb -= strlen(tmp); + tmp += strlen(tmp); + strncpy(tmp, "/Oracle/VirtualBox", cb); + tmp[cb - 1] = '\0'; + if (tryLoadLibrary(szPath, 1) == 0) + return 0; + } + if (tryLoadLibrary("C:/Program Files/Oracle/VirtualBox", 1) == 0) + return 0; +#else +# error "port me" +#endif + + /* + * Finally try the dynamic linker search path. + */ + if (tryLoadLibrary(NULL, 1) == 0) + return 0; + + /* No luck, return failure. */ + return -1; +} + + +/** + * Terminate the C glue library. + */ +void VBoxCGlueTerm(void) +{ + if (g_hVBoxCAPI) + { +#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */ +#ifndef WIN32 + dlclose(g_hVBoxCAPI); +#else + FreeLibrary(g_hVBoxCAPI); +#endif +#endif + g_hVBoxCAPI = NULL; + } + g_pVBoxFuncs = NULL; + g_pfnGetFunctions = NULL; + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); +} + diff --git a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.h b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.h new file mode 100644 index 00000000..a6670fa0 --- /dev/null +++ b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.h @@ -0,0 +1,64 @@ +/* $Revision: 91907 $ */ +/** @file VBoxXPCOMCGlue.h + * Glue for dynamically linking with VBoxCAPI, LEGACY VARIANT. + */ + +/* + * Copyright (C) 2008-2014 Oracle Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___VBoxXPCOMCGlue_h +#define ___VBoxXPCOMCGlue_h + +#undef VBOX_WITH_GLUE +#include "VBoxCAPI_v4_3.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +extern void *g_hVBoxCAPI; +#else +extern HMODULE g_hVBoxCAPI; +#endif +/** The last load error. */ +extern char g_szVBoxErrMsg[256]; +/** Pointer to the VBOXCAPI function table. */ +extern PCVBOXCAPI g_pVBoxFuncs; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +extern PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions; + + +int VBoxCGlueInit(void); +void VBoxCGlueTerm(void); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/VBox/Main/cbinding/Makefile.kmk b/src/VBox/Main/cbinding/Makefile.kmk index 7e64c372..e84dfcb3 100644 --- a/src/VBox/Main/cbinding/Makefile.kmk +++ b/src/VBox/Main/cbinding/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2009-2012 Oracle Corporation +# Copyright (C) 2009-2014 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -19,41 +19,40 @@ SUB_DEPTH = ../../../.. include $(KBUILD_PATH)/subheader.kmk -if defined(VBOX_WITH_XPCOM) || defined(VBOX_ONLY_SDK) # # The samples # -INSTALLS += XpComCSamples -XpComCSamples_MODE = a+r,u+rw -XpComCSamples_INST = \ - $(INST_SDK)bindings/xpcom/cbinding/samples/ -XpComCSamples_SOURCES = \ - tstXPCOMCGlue.c \ - tstXPCOMCCall.c \ - makefile.tstXPCOMCGlue=>Makefile - -INSTALLS += XpComCGlue -XpComCGlue_MODE = a+r,u+rw -XpComCGlue_INST = \ - $(INST_SDK)bindings/xpcom/cbinding/ -XpComCGlue_SOURCES = \ - VBoxXPCOMCGlue.c \ - $(XpComCHeaders_0_OUTDIR)/VBoxXPCOMCGlue.h - -INSTALLS += XpComCHeaders -XpComCHeaders_MODE = a+r,u+rw -XpComCHeaders_INST = $(INST_SDK)bindings/xpcom/include/ -XpComCHeaders_SOURCES = \ +INSTALLS += CAPISamples +CAPISamples_MODE = a+r,u+rw +CAPISamples_INST = \ + $(INST_SDK)bindings/c/samples/ +CAPISamples_SOURCES = \ + tstCAPIGlue.c \ + makefile.tstCAPIGlue=>Makefile + +INSTALLS += CAPIGlue +CAPIGlue_MODE = a+r,u+rw +CAPIGlue_INST = \ + $(INST_SDK)bindings/c/glue/ +CAPIGlue_SOURCES = \ + VBoxCAPIGlue.c \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPIGlue.h + +INSTALLS += CAPIHeaders +CAPIHeaders_MODE = a+r,u+rw +CAPIHeaders_INST = $(INST_SDK)bindings/c/include/ +CAPIHeaders_SOURCES = \ VBoxCAPI_v2_2.h \ VBoxCAPI_v3_0.h \ VBoxCAPI_v3_1.h \ VBoxCAPI_v3_2.h \ VBoxCAPI_v4_0.h \ VBoxCAPI_v4_1.h \ - $(XpComCHeaders_0_OUTDIR)/VBoxCAPI.h=>VBoxCAPI_v$(VBOX_API_VERSION).h + VBoxCAPI_v4_2.h \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h=>VBoxCAPI_v$(VBOX_API_VERSION).h -$$(XpComCHeaders_0_OUTDIR)/VBoxXPCOMCGlue.h: \ - $(PATH_SUB_CURRENT)/VBoxXPCOMCGlue.h.in \ +$$(CAPIHeaders_0_OUTDIR)/VBoxCAPIGlue.h: \ + $(PATH_SUB_CURRENT)/VBoxCAPIGlue.h.in \ $(MAKEFILE_CURRENT) \ | $$(dir $$@) $(call MSG_GENERATE,,$@) @@ -61,78 +60,103 @@ $$(XpComCHeaders_0_OUTDIR)/VBoxXPCOMCGlue.h: \ -e 's/@VBOX_API_VERSION@/$(VBOX_API_VERSION)/' \ < $< > $@ -$$(XpComCHeaders_0_OUTDIR)/VBoxCAPI.h: \ - $(PATH_SUB_CURRENT)/xpcidl.xsl \ +$$(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h: \ + $(PATH_SUB_CURRENT)/capiidl.xsl \ $(VBOX_XIDL_FILE) \ | $$(dir $$@) - $(call MSG_TOOL,xsltproc,XpComCHeaders,$<,$@) + $(call MSG_TOOL,xsltproc,CAPIHeaders,$<,$@) $(QUIET)$(VBOX_XSLTPROC) -o $@ $^ -endif # VBOX_WITH_XPCOM || SDK -if !defined(VBOX_ONLY_SDK) && defined(VBOX_WITH_XPCOM) +# Additional legacy install, to keep compatibility with older 4.3 SDK packages, +# to avoid breaking 3rd party code in the middle of the 4.3 release. +INSTALLS += LegacyXPCOMCGlue +LegacyXPCOMCGlue_MODE = a+r,u+rw +LegacyXPCOMCGlue_INST = \ + $(INST_SDK)bindings/xpcom/cbinding/ +LegacyXPCOMCGlue_SOURCES = \ + LegacyVBoxXPCOMCGlue.c=>VBoxXPCOMCGlue.c \ + LegacyVBoxXPCOMCGlue.h=>VBoxXPCOMCGlue.h + +# Additional legacy install, to keep compatibility with older 4.3 SDK packages, +# to avoid breaking 3rd party code in the middle of the 4.3 release. +INSTALLS += LegacyXPCOMCHeaders +LegacyXPCOMCHeaders_MODE = a+r,u+rw +LegacyXPCOMCHeaders_INST = $(INST_SDK)bindings/xpcom/include/ +LegacyXPCOMCHeaders_SOURCES = \ + VBoxCAPI_v2_2.h \ + VBoxCAPI_v3_0.h \ + VBoxCAPI_v3_1.h \ + VBoxCAPI_v3_2.h \ + VBoxCAPI_v4_0.h \ + VBoxCAPI_v4_1.h \ + VBoxCAPI_v4_2.h \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h=>VBoxCAPI_v$(VBOX_API_VERSION).h + +if !defined(VBOX_ONLY_SDK) # - # The C utility DLL + # The C API binding utility DLL # + DLLS += VBoxCAPI + VBoxCAPI_TEMPLATE = VBOXMAINCLIENTDLL ifdef VBOX_WITH_XPCOM - DLLS += VBoxXPCOMC - VBoxXPCOMC_TEMPLATE = VBOXMAINDLL - VBoxXPCOMC_DEFS = IN_VBOXXPCOMC - VBoxXPCOMC_SOURCES = \ - VBoxXPCOMC.cpp - VBoxXPCOMC_INCS = \ - $(XpComCHeaders_0_OUTDIR) - VBoxXPCOMC_INTERMEDIATES = \ - $(XpComCHeaders_0_OUTDIR)/VBoxCAPI.h + # Keep old name on XPCOM so that legacy code is happy. + VBoxCAPI_INST = $(INST_BIN)VBoxXPCOMC$(VBOX_SUFF_DLL) endif + VBoxCAPI_DEFS = IN_VBOXCAPI + VBoxCAPI_SOURCES = \ + VBoxCAPI.cpp + VBoxCAPI_INCS = \ + $(CAPIHeaders_0_OUTDIR) + VBoxCAPI_INTERMEDIATES = \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h # # The C glue library. # - LIBRARIES += VBoxXPCOMCGlue - VBoxXPCOMCGlue_TEMPLATE = VBOXMAINEXE - VBoxXPCOMCGlue_DEFS = IN_VBOXXPCOMC - VBoxXPCOMCGlue_SOURCES = \ - VBoxXPCOMCGlue.c - VBoxXPCOMCGlue_INCS = \ - $(VBOX_PATH_SDK)/bindings/xpcom/cbinding - VBoxXPCOMCGlue_INTERMEDIATES = \ - $(VBOX_PATH_SDK)/bindings/xpcom/cbinding/VBoxXPCOMCGlue.h \ - $(VBOX_PATH_SDK)/bindings/xpcom/include/VBoxCAPI_v$(VBOX_API_VERSION).h + LIBRARIES += VBoxCAPIGlue + VBoxCAPIGlue_TEMPLATE = VBOXMAINEXE + VBoxCAPIGlue_DEFS = IN_VBOXCAPI + VBoxCAPIGlue_SOURCES = \ + VBoxCAPIGlue.c + ifdef VBOX_WITH_XPCOM + VBoxCAPIGlue_SOURCES += \ + $(VBOX_PATH_SDK)/bindings/xpcom/lib/VirtualBox_i.c + else + VBoxCAPIGlue_SOURCES += \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c + endif + VBoxCAPIGlue_INCS = \ + $(VBOX_PATH_SDK)/bindings/c/include \ + $(VBOX_PATH_SDK)/bindings/c/glue + VBoxCAPIGlue_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/c/glue/VBoxCAPIGlue.h \ + $(VBOX_PATH_SDK)/bindings/c/include/VBoxCAPI_v$(VBOX_API_VERSION).h if defined(VBOX_WITH_TESTCASES) && "$(KBUILD_TARGET)" != "darwin" # # The testcase (also in samples). # C testcase using the dynamic glue. # - PROGRAMS += tstXPCOMCGlue - tstXPCOMCGlue_TEMPLATE = VBOXR3EXE - tstXPCOMCGlue_INCS = \ - $(VBOX_PATH_SDK)/bindings/xpcom/include \ - $(VBOX_PATH_SDK)/bindings/xpcom/cbinding - tstXPCOMCGlue_INTERMEDIATES = \ - $(VBOX_PATH_SDK)/bindings/xpcom/cbinding/VBoxXPCOMCGlue.h \ - $(VBOX_PATH_SDK)/bindings/xpcom/include/VBoxCAPI_v$(VBOX_API_VERSION).h - tstXPCOMCGlue_SOURCES = \ - tstXPCOMCGlue.c - tstXPCOMCGlue_LIBS = \ - $(VBoxXPCOMCGlue_1_TARGET) - - ifeq (disabled,1) - # - # The callback testcase. - # - PROGRAMS += tstXPCOMCCall - tstXPCOMCCall_TEMPLATE = VBOXR3EXE - tstXPCOMCCall_INCS = \ + PROGRAMS += tstCAPIGlue + tstCAPIGlue_TEMPLATE = VBOXR3TSTEXE + tstCAPIGlue_INCS = \ + $(VBOX_PATH_SDK)/bindings/c/include \ + $(VBOX_PATH_SDK)/bindings/c/glue + ifdef VBOX_WITH_XPCOM + tstCAPIGlue_INCS += \ $(VBOX_PATH_SDK)/bindings/xpcom/include - tstXPCOMCCall_INTERMEDIATES = \ - $(VBOX_PATH_SDK)/bindings/xpcom/include/VBoxCAPI_v$(VBOX_API_VERSION).h - tstXPCOMCCall_SOURCES = \ - tstXPCOMCCall.c - tstXPCOMCCall_LIBS = \ - $(VBoxXPCOMCGlue_1_TARGET) + else + tstCAPIGlue_INCS += \ + $(VBOX_PATH_SDK)/bindings/mscom/include endif + tstCAPIGlue_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/c/glue/VBoxCAPIGlue.h \ + $(VBOX_PATH_SDK)/bindings/c/include/VBoxCAPI_v$(VBOX_API_VERSION).h + tstCAPIGlue_SOURCES = \ + tstCAPIGlue.c + tstCAPIGlue_LIBS = \ + $(VBoxCAPIGlue_1_TARGET) endif endif # ! VBOX_ONLY_SDK diff --git a/src/VBox/Main/cbinding/VBoxCAPI.cpp b/src/VBox/Main/cbinding/VBoxCAPI.cpp new file mode 100644 index 00000000..094d4e4a --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPI.cpp @@ -0,0 +1,924 @@ +/* $Id: VBoxCAPI.cpp $ */ +/** @file VBoxCAPI.cpp + * Utility functions to use with the C API binding. + */ + +/* + * Copyright (C) 2009-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#define LOG_GROUP LOG_GROUP_MAIN + +#include "VBoxCAPI.h" + +#ifdef VBOX_WITH_XPCOM +# include +# include +# include +# include +# include +#endif /* VBOX_WITH_XPCOM */ + +#include +#include +#include +#include +#include +#include +#include + +#include "VBox/com/com.h" +#include "VBox/com/NativeEventQueue.h" + +using namespace std; + +/* The following 2 object references should be eliminated once the legacy + * way to initialize the COM/XPCOM C bindings is removed. */ +static ISession *g_Session = NULL; +static IVirtualBox *g_VirtualBox = NULL; + +#ifdef VBOX_WITH_XPCOM +/* This object reference should be eliminated once the legacy way of handling + * the event queue (XPCOM specific) is removed. */ +static nsIEventQueue *g_EventQueue = NULL; +#endif /* VBOX_WITH_XPCOM */ + +static void VBoxComUninitialize(void); +static void VBoxClientUninitialize(void); + +static int +VBoxUtf16ToUtf8(CBSTR pwszString, char **ppszString) +{ + if (!pwszString) + { + *ppszString = NULL; + return VINF_SUCCESS; + } + return RTUtf16ToUtf8(pwszString, ppszString); +} + +static int +VBoxUtf8ToUtf16(const char *pszString, BSTR *ppwszString) +{ + if (!pszString) + { + *ppwszString = NULL; + return VINF_SUCCESS; + } +#ifdef VBOX_WITH_XPCOM + return RTStrToUtf16(pszString, ppwszString); +#else /* !VBOX_WITH_XPCOM */ + PRTUTF16 pwsz; + int vrc = RTStrToUtf16(pszString, &pwsz); + *ppwszString = ::SysAllocString(pwsz); + RTUtf16Free(pwsz); + return vrc; +#endif /* !VBOX_WITH_XPCOM */ +} + +static void +VBoxUtf16Free(BSTR pwszString) +{ +#ifdef VBOX_WITH_XPCOM + RTUtf16Free(pwszString); +#else /* !VBOX_WITH_XPCOM */ + ::SysFreeString(pwszString); +#endif /* !VBOX_WITH_XPCOM */ +} + +static void +VBoxUtf8Free(char *pszString) +{ + RTStrFree(pszString); +} + +static void +VBoxComUnallocString(BSTR pwsz) +{ + if (pwsz) + { +#ifdef VBOX_WITH_XPCOM + nsMemory::Free(pwsz); +#else /* !VBOX_WITH_XPCOM */ + ::SysFreeString(pwsz); +#endif /* !VBOX_WITH_XPCOM */ + } +} + +static void +VBoxComUnallocMem(void *pv) +{ + VBoxComUnallocString((BSTR)pv); +} + +static ULONG +VBoxVTElemSize(VARTYPE vt) +{ + switch (vt) + { + case VT_BOOL: + case VT_I1: + case VT_UI1: + return 1; + case VT_I2: + case VT_UI2: + return 2; + case VT_I4: + case VT_UI4: + case VT_HRESULT: + return 4; + case VT_I8: + case VT_UI8: + return 8; + case VT_BSTR: + case VT_DISPATCH: + case VT_UNKNOWN: + return sizeof(void *); + default: + return 0; + } +} + +static SAFEARRAY * +VBoxSafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements) +{ +#ifdef VBOX_WITH_XPCOM + NOREF(lLbound); + ULONG cbElement = VBoxVTElemSize(vt); + if (!cbElement) + return NULL; + SAFEARRAY *psa = (SAFEARRAY *)RTMemAllocZ(sizeof(SAFEARRAY)); + if (!psa) + return psa; + if (cElements) + { + void *pv = nsMemory::Alloc(cElements * cbElement); + if (!pv) + { + RTMemFree(psa); + return NULL; + } + psa->pv = pv; + psa->c = cElements; + } + return psa; +#else /* !VBOX_WITH_XPCOM */ + return SafeArrayCreateVector(vt, lLbound, cElements); +#endif /* !VBOX_WITH_XPCOM */ +} + +static SAFEARRAY * +VBoxSafeArrayOutParamAlloc(void) +{ +#ifdef VBOX_WITH_XPCOM + return (SAFEARRAY *)RTMemAllocZ(sizeof(SAFEARRAY)); +#else /* !VBOX_WITH_XPCOM */ + return NULL; +#endif /* !VBOX_WITH_XPCOM */ +} + +static HRESULT +VBoxSafeArrayDestroy(SAFEARRAY *psa) +{ +#ifdef VBOX_WITH_XPCOM + if (psa) + { + if (psa->pv) + nsMemory::Free(psa->pv); + RTMemFree(psa); + } + return S_OK; +#else /* !VBOX_WITH_XPCOM */ + return SafeArrayDestroy(psa); +#endif /* !VBOX_WITH_XPCOM */ +} + +static HRESULT +VBoxSafeArrayCopyInParamHelper(SAFEARRAY *psa, const void *pv, ULONG cb) +{ + if (!pv || !psa) + return E_POINTER; + if (!cb) + return S_OK; + + void *pData; +#ifdef VBOX_WITH_XPCOM + pData = psa->pv; +#else /* !VBOX_WITH_XPCOM */ + HRESULT rc = SafeArrayAccessData(psa, &pData); + if (FAILED(rc)) + return rc; +#endif /* !VBOX_WITH_XPCOM */ + memcpy(pData, pv, cb); +#ifndef VBOX_WITH_XPCOM + SafeArrayUnaccessData(psa); +#endif /* !VBOX_WITH_XPCOM */ + return S_OK; +} + +static HRESULT +VBoxSafeArrayCopyOutParamHelper(void **ppv, ULONG *pcb, VARTYPE vt, SAFEARRAY *psa) +{ + if (!ppv) + return E_POINTER; + ULONG cbElement = VBoxVTElemSize(vt); + if (!cbElement) + return E_INVALIDARG; +#ifndef VBOX_WITH_XPCOM + if (psa->cDims != 1) + return E_INVALIDARG; + Assert(cbElement = psa->cbElements); +#endif /* !VBOX_WITH_XPCOM */ + void *pData; + ULONG cElements; +#ifdef VBOX_WITH_XPCOM + pData = psa->pv; + cElements = psa->c; +#else /* !VBOX_WITH_XPCOM */ + HRESULT rc = SafeArrayAccessData(psa, &pData); + if (FAILED(rc)) + return rc; + cElements = psa->rgsabound[0].cElements; +#endif /* !VBOX_WITH_XPCOM */ + size_t cbTotal = cbElement * cElements; + void *pv = malloc(cbTotal); + if (pv) + { + memcpy(pv, pData, cbTotal); + *ppv = pv; + if (pcb) + *pcb = (ULONG)cbTotal; + } +#ifndef VBOX_WITH_XPCOM + SafeArrayUnaccessData(psa); +#endif /* !VBOX_WITH_XPCOM */ + return S_OK; +} + +static HRESULT +VBoxSafeArrayCopyOutIfaceParamHelper(IUnknown ***ppaObj, ULONG *pcObj, SAFEARRAY *psa) +{ + ULONG mypcb; + HRESULT rc = VBoxSafeArrayCopyOutParamHelper((void **)ppaObj, &mypcb, VT_UNKNOWN, psa); + if (FAILED(rc)) + return rc; + ULONG cElements = mypcb / sizeof(void *); + if (pcObj) + *pcObj = cElements; +#ifndef VBOX_WITH_XPCOM + /* Do this only for COM, as there the SAFEARRAY destruction will release + * the contained references automatically. XPCOM doesn't do that, which + * means that copying implicitly transfers ownership. */ + IUnknown **paObj = *ppaObj; + for (ULONG i = 0; i < cElements; i++) + { + IUnknown *pObj = paObj[i]; + if (pObj) + pObj->AddRef(); + } +#endif /* VBOX_WITH_XPCOM */ + return S_OK; +} + +static void +VBoxComInitialize(const char *pszVirtualBoxIID, IVirtualBox **ppVirtualBox, + const char *pszSessionIID, ISession **ppSession) +{ + int vrc; + IID virtualBoxIID; + IID sessionIID; + + *ppSession = NULL; + *ppVirtualBox = NULL; + + /* convert the string representation of the UUIDs (if provided) to IID */ + if (pszVirtualBoxIID && *pszVirtualBoxIID) + { + vrc = ::RTUuidFromStr((RTUUID *)&virtualBoxIID, pszVirtualBoxIID); + if (RT_FAILURE(vrc)) + return; + } + else + virtualBoxIID = IID_IVirtualBox; + if (pszSessionIID && *pszSessionIID) + { + vrc = ::RTUuidFromStr((RTUUID *)&sessionIID, pszSessionIID); + if (RT_FAILURE(vrc)) + return; + } + else + sessionIID = IID_ISession; + + HRESULT rc = com::Initialize(); + if (FAILED(rc)) + { + Log(("Cbinding: COM/XPCOM could not be initialized! rc=%Rhrc\n", rc)); + VBoxComUninitialize(); + return; + } + +#ifdef VBOX_WITH_XPCOM + rc = NS_GetMainEventQ(&g_EventQueue); + if (FAILED(rc)) + { + Log(("Cbinding: Could not get XPCOM event queue! rc=%Rhrc\n", rc)); + VBoxComUninitialize(); + return; + } +#endif /* VBOX_WITH_XPCOM */ + +#ifdef VBOX_WITH_XPCOM + nsIComponentManager *pManager; + rc = NS_GetComponentManager(&pManager); + if (FAILED(rc)) + { + Log(("Cbinding: Could not get component manager! rc=%Rhrc\n", rc)); + VBoxComUninitialize(); + return; + } + + rc = pManager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID, + nsnull, + virtualBoxIID, + (void **)&g_VirtualBox); +#else /* !VBOX_WITH_XPCOM */ + rc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, virtualBoxIID, (void **)&g_VirtualBox); +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(rc)) + { + Log(("Cbinding: Could not instantiate VirtualBox object! rc=%Rhrc\n",rc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxComUninitialize(); + return; + } + + Log(("Cbinding: IVirtualBox object created.\n")); + +#ifdef VBOX_WITH_XPCOM + rc = pManager->CreateInstanceByContractID(NS_SESSION_CONTRACTID, + nsnull, + sessionIID, + (void **)&g_Session); +#else /* !VBOX_WITH_XPCOM */ + rc = CoCreateInstance(CLSID_Session, NULL, CLSCTX_INPROC_SERVER, sessionIID, (void **)&g_Session); +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(rc)) + { + Log(("Cbinding: Could not instantiate Session object! rc=%Rhrc\n",rc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxComUninitialize(); + return; + } + + Log(("Cbinding: ISession object created.\n")); + +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + + *ppSession = g_Session; + *ppVirtualBox = g_VirtualBox; +} + +static void +VBoxComInitializeV1(IVirtualBox **ppVirtualBox, ISession **ppSession) +{ + VBoxComInitialize(NULL, ppVirtualBox, NULL, ppSession); +} + +static void +VBoxComUninitialize(void) +{ + if (g_Session) + { + g_Session->Release(); + g_Session = NULL; + } + if (g_VirtualBox) + { + g_VirtualBox->Release(); + g_VirtualBox = NULL; + } +#ifdef VBOX_WITH_XPCOM + if (g_EventQueue) + { + g_EventQueue->Release(); + g_EventQueue = NULL; + } +#endif /* VBOX_WITH_XPCOM */ + com::Shutdown(); + Log(("Cbinding: Cleaned up the created objects.\n")); +} + +#ifdef VBOX_WITH_XPCOM +static void +VBoxGetEventQueue(nsIEventQueue **ppEventQueue) +{ + *ppEventQueue = g_EventQueue; +} +#endif /* VBOX_WITH_XPCOM */ + +static int +VBoxProcessEventQueue(LONG64 iTimeoutMS) +{ + RTMSINTERVAL iTimeout; + if (iTimeoutMS < 0 || iTimeoutMS > UINT32_MAX) + iTimeout = RT_INDEFINITE_WAIT; + else + iTimeout = (RTMSINTERVAL)iTimeoutMS; + int vrc = com::NativeEventQueue::getMainEventQueue()->processEventQueue(iTimeout); + switch (vrc) + { + case VINF_SUCCESS: + return 0; + case VINF_INTERRUPTED: + return 1; + case VERR_INTERRUPTED: + return 2; + case VERR_TIMEOUT: + return 3; + case VERR_INVALID_CONTEXT: + return 4; + default: + return 5; + } +} + +static int +VBoxInterruptEventQueueProcessing(void) +{ + com::NativeEventQueue::getMainEventQueue()->interruptEventQueueProcessing(); + return 0; +} + +static HRESULT +VBoxGetException(IErrorInfo **ppException) +{ + HRESULT rc; + + *ppException = NULL; + +#ifdef VBOX_WITH_XPCOM + nsIServiceManager *mgr = NULL; + rc = NS_GetServiceManager(&mgr); + if (FAILED(rc) || !mgr) + return rc; + + IID esid = NS_IEXCEPTIONSERVICE_IID; + nsIExceptionService *es = NULL; + rc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es); + if (FAILED(rc) || !es) + { + mgr->Release(); + return rc; + } + + nsIExceptionManager *em; + rc = es->GetCurrentExceptionManager(&em); + if (FAILED(rc) || !em) + { + es->Release(); + mgr->Release(); + return rc; + } + + nsIException *ex; + rc = em->GetCurrentException(&ex); + if (FAILED(rc)) + { + em->Release(); + es->Release(); + mgr->Release(); + return rc; + } + + *ppException = ex; + em->Release(); + es->Release(); + mgr->Release(); +#else /* !VBOX_WITH_XPCOM */ + IErrorInfo *ex; + rc = ::GetErrorInfo(0, &ex); + if (FAILED(rc)) + return rc; + + *ppException = ex; +#endif /* !VBOX_WITH_XPCOM */ + + return rc; +} + +static HRESULT +VBoxClearException(void) +{ + HRESULT rc; + +#ifdef VBOX_WITH_XPCOM + nsIServiceManager *mgr = NULL; + rc = NS_GetServiceManager(&mgr); + if (FAILED(rc) || !mgr) + return rc; + + IID esid = NS_IEXCEPTIONSERVICE_IID; + nsIExceptionService *es = NULL; + rc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es); + if (FAILED(rc) || !es) + { + mgr->Release(); + return rc; + } + + nsIExceptionManager *em; + rc = es->GetCurrentExceptionManager(&em); + if (FAILED(rc) || !em) + { + es->Release(); + mgr->Release(); + return rc; + } + + rc = em->SetCurrentException(NULL); + em->Release(); + es->Release(); + mgr->Release(); +#else /* !VBOX_WITH_XPCOM */ + rc = ::SetErrorInfo(0, NULL); +#endif /* !VBOX_WITH_XPCOM */ + + return rc; +} + +static HRESULT +VBoxClientInitialize(const char *pszVirtualBoxClientIID, IVirtualBoxClient **ppVirtualBoxClient) +{ + IID virtualBoxClientIID; + + *ppVirtualBoxClient = NULL; + + /* convert the string representation of UUID to IID type */ + if (pszVirtualBoxClientIID && *pszVirtualBoxClientIID) + { + int vrc = ::RTUuidFromStr((RTUUID *)&virtualBoxClientIID, pszVirtualBoxClientIID); + if (RT_FAILURE(vrc)) + return E_INVALIDARG; + } + else + virtualBoxClientIID = IID_IVirtualBoxClient; + + HRESULT rc = com::Initialize(); + if (FAILED(rc)) + { + Log(("Cbinding: COM/XPCOM could not be initialized! rc=%Rhrc\n", rc)); + VBoxClientUninitialize(); + return rc; + } + +#ifdef VBOX_WITH_XPCOM + rc = NS_GetMainEventQ(&g_EventQueue); + if (NS_FAILED(rc)) + { + Log(("Cbinding: Could not get XPCOM event queue! rc=%Rhrc\n", rc)); + VBoxClientUninitialize(); + return rc; + } +#endif /* VBOX_WITH_XPCOM */ + +#ifdef VBOX_WITH_XPCOM + nsIComponentManager *pManager; + rc = NS_GetComponentManager(&pManager); + if (FAILED(rc)) + { + Log(("Cbinding: Could not get component manager! rc=%Rhrc\n", rc)); + VBoxClientUninitialize(); + return rc; + } + + rc = pManager->CreateInstanceByContractID(NS_VIRTUALBOXCLIENT_CONTRACTID, + nsnull, + virtualBoxClientIID, + (void **)ppVirtualBoxClient); +#else /* !VBOX_WITH_XPCOM */ + rc = CoCreateInstance(CLSID_VirtualBoxClient, NULL, CLSCTX_INPROC_SERVER, virtualBoxClientIID, (void **)ppVirtualBoxClient); +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(rc)) + { + Log(("Cbinding: Could not instantiate VirtualBoxClient object! rc=%Rhrc\n",rc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxClientUninitialize(); + return rc; + } + +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + + Log(("Cbinding: IVirtualBoxClient object created.\n")); + + return S_OK; +} + +static HRESULT +VBoxClientThreadInitialize(void) +{ + return com::Initialize(); +} + +static HRESULT +VBoxClientThreadUninitialize(void) +{ + return com::Shutdown(); +} + +static void +VBoxClientUninitialize(void) +{ +#ifdef VBOX_WITH_XPCOM + if (g_EventQueue) + { + NS_RELEASE(g_EventQueue); + g_EventQueue = NULL; + } +#endif /* VBOX_WITH_XPCOM */ + com::Shutdown(); + Log(("Cbinding: Cleaned up the created objects.\n")); +} + +static unsigned int +VBoxVersion(void) +{ + return VBOX_VERSION_MAJOR * 1000 * 1000 + VBOX_VERSION_MINOR * 1000 + VBOX_VERSION_BUILD; +} + +static unsigned int +VBoxAPIVersion(void) +{ + return VBOX_VERSION_MAJOR * 1000 + VBOX_VERSION_MINOR + (VBOX_VERSION_BUILD > 50 ? 1 : 0); +} + +VBOXCAPI_DECL(PCVBOXCAPI) +VBoxGetCAPIFunctions(unsigned uVersion) +{ + /* This is the first piece of code which knows that IPRT exists, so + * initialize it properly. The limited initialization in VBoxC is not + * sufficient, and causes trouble with com::Initialize() misbehaving. */ + RTR3InitDll(0); + + /* + * The current interface version. + */ + static const VBOXCAPI s_Functions = + { + sizeof(VBOXCAPI), + VBOX_CAPI_VERSION, + + VBoxVersion, + VBoxAPIVersion, + + VBoxClientInitialize, + VBoxClientThreadInitialize, + VBoxClientThreadUninitialize, + VBoxClientUninitialize, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocString, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + VBoxUtf8Free, + VBoxUtf16Free, + + VBoxSafeArrayCreateVector, + VBoxSafeArrayOutParamAlloc, + VBoxSafeArrayCopyInParamHelper, + VBoxSafeArrayCopyOutParamHelper, + VBoxSafeArrayCopyOutIfaceParamHelper, + VBoxSafeArrayDestroy, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + VBoxGetException, + VBoxClearException, + VBoxProcessEventQueue, + VBoxInterruptEventQueueProcessing, + + VBOX_CAPI_VERSION + }; + + if ((uVersion & 0xffff0000U) == (VBOX_CAPI_VERSION & 0xffff0000U)) + return &s_Functions; + + /* + * Legacy interface version 3.0. + */ + static const struct VBOXCAPIV3 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + unsigned int (*pfnGetAPIVersion)(void); + + HRESULT (*pfnClientInitialize)(const char *pszVirtualBoxClientIID, + IVirtualBoxClient **ppVirtualBoxClient); + void (*pfnClientUninitialize)(void); + + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + void (*pfnUtf8Free)(char *pszString); + void (*pfnUtf16Free)(BSTR pwszString); + +#ifdef VBOX_WITH_XPCOM + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* VBOX_WITH_XPCOM */ + HRESULT (*pfnGetException)(IErrorInfo **ppException); + HRESULT (*pfnClearException)(void); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v3_0 = + { + sizeof(s_Functions_v3_0), + 0x00030000U, + + VBoxVersion, + VBoxAPIVersion, + + VBoxClientInitialize, + VBoxClientUninitialize, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocMem, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + VBoxUtf8Free, + VBoxUtf16Free, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + VBoxGetException, + VBoxClearException, + + 0x00030000U + }; + + if ((uVersion & 0xffff0000U) == 0x00030000U) + return (PCVBOXCAPI)&s_Functions_v3_0; + + /* + * Legacy interface version 2.0. + */ + static const struct VBOXCAPIV2 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + void (*pfnUtf16Free)(BSTR pwszString); + void (*pfnUtf8Free)(char *pszString); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + +#ifdef VBOX_WITH_XPCOM + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* VBOX_WITH_XPCOM */ + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v2_0 = + { + sizeof(s_Functions_v2_0), + 0x00020000U, + + VBoxVersion, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocMem, + VBoxUtf16Free, + VBoxUtf8Free, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + + 0x00020000U + }; + + if ((uVersion & 0xffff0000U) == 0x00020000U) + return (PCVBOXCAPI)&s_Functions_v2_0; + + /* + * Legacy interface version 1.0. + */ + static const struct VBOXCAPIV1 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + void (*pfnComInitialize)(IVirtualBox **virtualBox, ISession **session); + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + void (*pfnUtf16Free)(BSTR pwszString); + void (*pfnUtf8Free)(char *pszString); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v1_0 = + { + sizeof(s_Functions_v1_0), + 0x00010000U, + + VBoxVersion, + + VBoxComInitializeV1, + VBoxComUninitialize, + + VBoxComUnallocMem, + VBoxUtf16Free, + VBoxUtf8Free, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + + 0x00010000U + }; + + if ((uVersion & 0xffff0000U) == 0x00010000U) + return (PCVBOXCAPI)&s_Functions_v1_0; + + /* + * Unsupported interface version. + */ + return NULL; +} + +#ifdef VBOX_WITH_XPCOM +VBOXCAPI_DECL(PCVBOXCAPI) +VBoxGetXPCOMCFunctions(unsigned uVersion) +{ + return VBoxGetCAPIFunctions(uVersion); +} +#endif /* VBOX_WITH_XPCOM */ +/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.c b/src/VBox/Main/cbinding/VBoxCAPIGlue.c new file mode 100644 index 00000000..d229a6b7 --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.c @@ -0,0 +1,330 @@ +/* $Revision: 91907 $ */ +/** @file + * Glue code for dynamically linking to VBoxCAPI. + */ + +/* + * Copyright (C) 2008-2014 Oracle Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "VBoxCAPIGlue.h" + +#include +#include +#include +#include +#include +#ifndef WIN32 +# include +# include +#else /* WIN32 */ +# include +#endif /* WIN32 */ + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__) +# define DYNLIB_NAME "VBoxXPCOMC.so" +#elif defined(__APPLE__) +# define DYNLIB_NAME "VBoxXPCOMC.dylib" +#elif defined(__OS2__) +# define DYNLIB_NAME "VBoxXPCOMC.dll" +#elif defined(WIN32) +# define DYNLIB_NAME "VBoxCAPI.dll" +#else +# error "Port me" +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +void *g_hVBoxCAPI = NULL; +#else /* WIN32 */ +HMODULE g_hVBoxCAPI = NULL; +#endif /* WIN32 */ +/** The last load error. */ +char g_szVBoxErrMsg[256] = ""; +/** Pointer to the VBOXCAPI function table. */ +PCVBOXCAPI g_pVBoxFuncs = NULL; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions = NULL; + +typedef void FNDUMMY(void); +typedef FNDUMMY *PFNDUMMY; +/** Just a dummy global structure containing a bunch of + * function pointers to code which is wanted in the link. */ +PFNDUMMY g_apfnVBoxCAPIGlue[] = +{ +#ifndef WIN32 + /* The following link dependency is for helping gdb as it gets hideously + * confused if the application doesn't drag in pthreads, but uses it. */ + (PFNDUMMY)pthread_create, +#endif /* !WIN32 */ + NULL +}; + + +/** + * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub. + * + * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty. + * @param pszFormat The format string. + * @param ... The arguments. + */ +static void setErrMsg(int fAlways, const char *pszFormat, ...) +{ + if ( fAlways + || !g_szVBoxErrMsg[0]) + { + va_list va; + va_start(va, pszFormat); + vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va); + va_end(va); + } +} + + +/** + * Try load C API .so/dylib/dll from the specified location and resolve all + * the symbols we need. Tries both the new style and legacy name. + * + * @returns 0 on success, -1 on failure. + * @param pszHome The directory where to try load VBoxCAPI/VBoxXPCOMC + * from. Can be NULL. + * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not + * (boolean). + */ +static int tryLoadLibrary(const char *pszHome, int fSetAppHome) +{ + size_t cchHome = pszHome ? strlen(pszHome) : 0; + size_t cbBufNeeded; + char szName[4096]; + + /* + * Construct the full name. + */ + cbBufNeeded = cchHome + sizeof("/" DYNLIB_NAME); + if (cbBufNeeded > sizeof(szName)) + { + setErrMsg(1, "path buffer too small: %u bytes needed", + (unsigned)cbBufNeeded); + return -1; + } + if (cchHome) + { + memcpy(szName, pszHome, cchHome); + szName[cchHome] = '/'; + cchHome++; + } + memcpy(&szName[cchHome], DYNLIB_NAME, sizeof(DYNLIB_NAME)); + + /* + * Try load it by that name, setting the VBOX_APP_HOME first (for now). + * Then resolve and call the function table getter. + */ + if (fSetAppHome) + { +#ifndef WIN32 + if (pszHome) + setenv("VBOX_APP_HOME", pszHome, 1 /* always override */); + else + unsetenv("VBOX_APP_HOME"); +#endif /* !WIN32 */ + } + +#ifndef WIN32 + g_hVBoxCAPI = dlopen(szName, RTLD_NOW | RTLD_LOCAL); + if (g_hVBoxCAPI) + { + PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions; + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); +#ifdef VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME + if (!pfnGetFunctions) + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME); +#endif /* VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME */ + if (pfnGetFunctions) + { + g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION); + if (g_pVBoxFuncs) + { + g_pfnGetFunctions = pfnGetFunctions; + return 0; + } + + /* bail out */ + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", + szName, VBOX_CAPI_VERSION); + } + else + setErrMsg(1, "dlsym(%.80s/%.32s): %.128s", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, dlerror()); + dlclose(g_hVBoxCAPI); + g_hVBoxCAPI = NULL; + } + else + setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror()); +#else /* !WIN32 */ + g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */, 0 /* dwFlags */); + if (g_hVBoxCAPI) + { + PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions; + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS) + GetProcAddress(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); + if (pfnGetFunctions) + { + g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION); + if (g_pVBoxFuncs) + { + g_pfnGetFunctions = pfnGetFunctions; + return 0; + } + + /* bail out */ + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", + szName, VBOX_CAPI_VERSION); + } + else + setErrMsg(1, "GetProcAddress(%.80s/%.32s): %d", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, GetLastError()); + FreeLibrary(g_hVBoxCAPI); + g_hVBoxCAPI = NULL; + } + else + setErrMsg(0, "LoadLibraryEx(%.80s): %d", szName, GetLastError()); +#endif /* !WIN32 */ + + return -1; +} + + +/** + * Tries to locate and load VBoxCAPI.so/dylib/dll, resolving all the related + * function pointers. + * + * @returns 0 on success, -1 on failure. + * + * @remark This should be considered moved into a separate glue library since + * its its going to be pretty much the same for any user of VBoxCAPI + * and it will just cause trouble to have duplicate versions of this + * source code all around the place. + */ +int VBoxCGlueInit(void) +{ + const char *pszHome; + + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); + + /* + * If the user specifies the location, try only that. + */ + pszHome = getenv("VBOX_APP_HOME"); + if (pszHome) + return tryLoadLibrary(pszHome, 0); + + /* + * Try the known standard locations. + */ +#if defined(__gnu__linux__) || defined(__linux__) + if (tryLoadLibrary("/opt/VirtualBox", 1) == 0) + return 0; + if (tryLoadLibrary("/usr/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__sun__) + if (tryLoadLibrary("/opt/VirtualBox/amd64", 1) == 0) + return 0; + if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0) + return 0; +#elif defined(__APPLE__) + if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0) + return 0; +#elif defined(__FreeBSD__) + if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__OS2__) + if (tryLoadLibrary("C:/Apps/VirtualBox", 1) == 0) + return 0; +#elif defined(WIN32) + pszHome = getenv("ProgramFiles"); + if (pszHome) + { + char szPath[4096]; + size_t cb = sizeof(szPath); + char *tmp = szPath; + strncpy(tmp, pszHome, cb); + tmp[cb - 1] = '\0'; + cb -= strlen(tmp); + tmp += strlen(tmp); + strncpy(tmp, "/Oracle/VirtualBox", cb); + tmp[cb - 1] = '\0'; + if (tryLoadLibrary(szPath, 1) == 0) + return 0; + } + if (tryLoadLibrary("C:/Program Files/Oracle/VirtualBox", 1) == 0) + return 0; +#else +# error "port me" +#endif + + /* + * Finally try the dynamic linker search path. + */ + if (tryLoadLibrary(NULL, 1) == 0) + return 0; + + /* No luck, return failure. */ + return -1; +} + + +/** + * Terminate the C glue library. + */ +void VBoxCGlueTerm(void) +{ + if (g_hVBoxCAPI) + { +#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */ +#ifndef WIN32 + dlclose(g_hVBoxCAPI); +#else + FreeLibrary(g_hVBoxCAPI); +#endif +#endif + g_hVBoxCAPI = NULL; + } + g_pVBoxFuncs = NULL; + g_pfnGetFunctions = NULL; + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); +} + diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in b/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in new file mode 100644 index 00000000..603b1363 --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in @@ -0,0 +1,65 @@ +/* $Revision: 91907 $ */ +/** @file VBoxCAPIGlue.h + * Glue for dynamically linking with VBoxCAPI. + */ + +/* + * Copyright (C) 2008-2014 Oracle Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___VBoxCAPIGlue_h +#define ___VBoxCAPIGlue_h + +#undef VBOX_WITH_GLUE +#define VBOX_WITH_GLUE +#include "VBoxCAPI_v@VBOX_API_VERSION@.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +extern void *g_hVBoxCAPI; +#else +extern HMODULE g_hVBoxCAPI; +#endif +/** The last load error. */ +extern char g_szVBoxErrMsg[256]; +/** Pointer to the VBOXCAPI function table. */ +extern PCVBOXCAPI g_pVBoxFuncs; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +extern PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions; + + +int VBoxCGlueInit(void); +void VBoxCGlueTerm(void); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/VBox/Main/cbinding/VBoxCAPI_v4_2.h b/src/VBox/Main/cbinding/VBoxCAPI_v4_2.h new file mode 100644 index 00000000..1db8217b --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPI_v4_2.h @@ -0,0 +1,8983 @@ + +/* + * DO NOT EDIT! This is a generated file. + * + * XPCOM IDL (XPIDL) definition for VirtualBox Main API (COM interfaces) + * generated from XIDL (XML interface definition). + * + * Source : src/VBox/Main/idl/VirtualBox.xidl + * Generator : src/VBox/Main/idl/xpcidl.xsl + * + * This file contains portions from the following Mozilla XPCOM files: + * xpcom/include/xpcom/nsID.h + * xpcom/include/nsIException.h + * xpcom/include/nsprpub/prtypes.h + * xpcom/include/xpcom/nsISupportsBase.h + * + * These files were originally triple-licensed (MPL/GPL2/LGPL2.1). Oracle + * elects to distribute this derived work under the LGPL2.1 only. + */ + +/* + * Copyright (C) 2008-2012 Oracle Corporation + * + * This file is part of a free software library; you can redistribute + * it and/or modify it under the terms of the GNU Lesser General + * Public License version 2.1 as published by the Free Software + * Foundation and shipped in the "COPYING" file with this library. + * The library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY of any kind. + * + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if + * any license choice other than GPL or LGPL is available it will + * apply instead, Oracle elects to use only the Lesser General Public + * License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the + * language indicating that LGPLv2 or any later version may be used, + * or where a choice of which version of the LGPL is applied is + * otherwise unspecified. + */ + +#ifndef ___VirtualBox_CXPCOM_h +#define ___VirtualBox_CXPCOM_h + +#ifdef __cplusplus +# include "VirtualBox_XPCOM.h" +#else /* !__cplusplus */ + +#include +#include "wchar.h" + +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define PR_EXPORT(__type) __attribute__((visibility("default"))) extern __type +# define PR_EXPORT_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT(__type) __attribute__((visibility("default"))) __type +# define PR_EXTERN_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT_DATA(__type) __attribute__((visibility("default"))) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# else +# define PR_EXPORT(__type) extern __type +# define PR_EXPORT_DATA(__type) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) extern __type +# define PR_IMPLEMENT(__type) __type +# define PR_EXTERN_DATA(__type) extern __type +# define PR_IMPLEMENT_DATA(__type) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# endif +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +typedef unsigned char PRUint8; +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +#define PR_TRUE 1 +#define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif + +typedef long PRWord; +typedef unsigned long PRUword; + +#define nsnull 0 +typedef PRUint32 nsresult; + +#if defined(__GNUC__) && (__GNUC__ > 2) +#define NS_LIKELY(x) (__builtin_expect((x), 1)) +#define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define NS_LIKELY(x) (x) +#define NS_UNLIKELY(x) (x) +#endif + +#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_IntervalNow VBoxNsprPR_IntervalNow +# define PR_TicksPerSecond VBoxNsprPR_TicksPerSecond +# define PR_SecondsToInterval VBoxNsprPR_SecondsToInterval +# define PR_MillisecondsToInterval VBoxNsprPR_MillisecondsToInterval +# define PR_MicrosecondsToInterval VBoxNsprPR_MicrosecondsToInterval +# define PR_IntervalToSeconds VBoxNsprPR_IntervalToSeconds +# define PR_IntervalToMilliseconds VBoxNsprPR_IntervalToMilliseconds +# define PR_IntervalToMicroseconds VBoxNsprPR_IntervalToMicroseconds +# define PR_EnterMonitor VBoxNsprPR_EnterMonitor +# define PR_ExitMonitor VBoxNsprPR_ExitMonitor +# define PR_Notify VBoxNsprPR_Notify +# define PR_NotifyAll VBoxNsprPR_NotifyAll +# define PR_Wait VBoxNsprPR_Wait +# define PR_NewMonitor VBoxNsprPR_NewMonitor +# define PR_DestroyMonitor VBoxNsprPR_DestroyMonitor +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef PRUint32 PRIntervalTime; + +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +NSPR_API(PRIntervalTime) PR_IntervalNow(void); +NSPR_API(PRUint32) PR_TicksPerSecond(void); +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +typedef struct PRMonitor PRMonitor; + +NSPR_API(PRMonitor*) PR_NewMonitor(void); +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_CreateThread VBoxNsprPR_CreateThread +# define PR_JoinThread VBoxNsprPR_JoinThread +# define PR_Sleep VBoxNsprPR_Sleep +# define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread +# define PR_GetThreadState VBoxNsprPR_GetThreadState +# define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate +# define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate +# define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex +# define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority +# define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority +# define PR_Interrupt VBoxNsprPR_Interrupt +# define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt +# define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt +# define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt +# define PR_GetThreadScope VBoxNsprPR_GetThreadScope +# define PR_GetThreadType VBoxNsprPR_GetThreadType +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); +NSPR_API(void) PR_ClearInterrupt(void); +NSPR_API(void) PR_BlockInterrupt(void); +NSPR_API(void) PR_UnblockInterrupt(void); +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_DestroyLock VBoxNsprPR_DestroyLock +# define PR_Lock VBoxNsprPR_Lock +# define PR_NewLock VBoxNsprPR_NewLock +# define PR_Unlock VBoxNsprPR_Unlock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRLock PRLock; + +NSPR_API(PRLock*) PR_NewLock(void); +NSPR_API(void) PR_DestroyLock(PRLock *lock); +NSPR_API(void) PR_Lock(PRLock *lock); +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_NewCondVar VBoxNsprPR_NewCondVar +# define PR_DestroyCondVar VBoxNsprPR_DestroyCondVar +# define PR_WaitCondVar VBoxNsprPR_WaitCondVar +# define PR_NotifyCondVar VBoxNsprPR_NotifyCondVar +# define PR_NotifyAllCondVar VBoxNsprPR_NotifyAllCondVar +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRCondVar PRCondVar; + +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +typedef struct PRCListStr PRCList; + +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PL_DestroyEvent VBoxNsplPL_DestroyEvent +# define PL_HandleEvent VBoxNsplPL_HandleEvent +# define PL_InitEvent VBoxNsplPL_InitEvent +# define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue +# define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue +# define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue +# define PL_DequeueEvent VBoxNsplPL_DequeueEvent +# define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue +# define PL_EventAvailable VBoxNsplPL_EventAvailable +# define PL_EventLoop VBoxNsplPL_EventLoop +# define PL_GetEvent VBoxNsplPL_GetEvent +# define PL_GetEventOwner VBoxNsplPL_GetEventOwner +# define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor +# define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD +# define PL_MapEvents VBoxNsplPL_MapEvents +# define PL_PostEvent VBoxNsplPL_PostEvent +# define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent +# define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID +# define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents +# define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc +# define PL_RevokeEvents VBoxNsplPL_RevokeEvents +# define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc +# define PL_WaitForEvent VBoxNsplPL_WaitForEvent +# define PL_IsQueueNative VBoxNsplPL_IsQueueNative +# define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread +# define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PLEvent PLEvent; +typedef struct PLEventQueue PLEventQueue; + +PR_EXTERN(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread); +PR_EXTERN(PLEventQueue *) + PL_CreateNativeEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(PLEventQueue *) + PL_CreateMonitoredEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(void) +PL_DestroyEventQueue(PLEventQueue* self); +PR_EXTERN(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self); + +#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ + PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) + +#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ + PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) + +PR_EXTERN(PRStatus) PL_PostEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(void*) PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(PLEvent*) PL_GetEvent(PLEventQueue* self); +PR_EXTERN(PRBool) PL_EventAvailable(PLEventQueue* self); + +typedef void (PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); + +PR_EXTERN(void) PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); +PR_EXTERN(void) PL_RevokeEvents(PLEventQueue* self, void* owner); +PR_EXTERN(void) PL_ProcessPendingEvents(PLEventQueue* self); +PR_EXTERN(PLEvent*) PL_WaitForEvent(PLEventQueue* self); +PR_EXTERN(void) PL_EventLoop(PLEventQueue* self); +PR_EXTERN(PRInt32) PL_GetEventQueueSelectFD(PLEventQueue* self); +PR_EXTERN(PRBool) PL_IsQueueOnCurrentThread( PLEventQueue *queue ); +PR_EXTERN(PRBool) PL_IsQueueNative(PLEventQueue *queue); + +typedef void* (PR_CALLBACK *PLHandleEventProc)(PLEvent* self); +typedef void (PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); +PR_EXTERN(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor); +PR_EXTERN(void*) PL_GetEventOwner(PLEvent* self); +PR_EXTERN(void) PL_HandleEvent(PLEvent* self); +PR_EXTERN(void) PL_DestroyEvent(PLEvent* self); +PR_EXTERN(void) PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); +PR_EXTERN(void) PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); + +struct PLEvent { + PRCList link; + PLHandleEventProc handler; + PLDestroyEventProc destructor; + void* owner; + void* synchronousResult; + PRLock* lock; + PRCondVar* condVar; + PRBool handled; +#ifdef PL_POST_TIMINGS + PRIntervalTime postTime; +#endif +#ifdef XP_UNIX + unsigned long id; +#endif /* XP_UNIX */ + /* other fields follow... */ +}; + +#if defined(XP_WIN) || defined(XP_OS2) + +PR_EXTERN(HWND) + PL_GetNativeEventReceiverWindow( + PLEventQueue *eqp + ); +#endif /* XP_WIN || XP_OS2 */ + +#ifdef XP_UNIX + +PR_EXTERN(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); + +typedef unsigned long (PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); + +PR_EXTERN(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure); +PR_EXTERN(void) PL_UnregisterEventIDFunc(PLEventQueue *aSelf); + +#endif /* XP_UNIX */ + +/* Standard "it worked" return value */ +#define NS_OK 0 + +#define NS_ERROR_BASE ((nsresult) 0xC1F30000) + +/* Returned when an instance is not initialized */ +#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + +/* Returned when an instance is already initialized */ +#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) + +/* Returned by a not implemented function */ +#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) + +/* Returned when a given interface is not supported. */ +#define NS_NOINTERFACE ((nsresult) 0x80004002L) +#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + +#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) +#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER + +/* Returned when a function aborts */ +#define NS_ERROR_ABORT ((nsresult) 0x80004004L) + +/* Returned when a function fails */ +#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) + +/* Returned when an unexpected error occurs */ +#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) + +/* Returned when a memory allocation fails */ +#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) + +/* Returned when an illegal value is passed */ +#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) +#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE + +/* Returned when a class doesn't allow aggregation */ +#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) + +/* Returned when an operation can't complete due to an unavailable resource */ +#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) + +/* Returned when a class is not registered */ +#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) + +/* Returned when a class cannot be registered, but may be tried again later */ +#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) + +/* Returned when a dynamically loaded factory couldn't be found */ +#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) + +/* Returned when a factory doesn't support signatures */ +#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ + (NS_ERROR_BASE + 0x101) + +/* Returned when a factory already is registered */ +#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; + +struct nsISupports; /* forward declaration */ +struct nsIStackFrame; /* forward declaration */ +struct nsIException; /* forward declaration */ +typedef struct nsISupports nsISupports; /* forward declaration */ +typedef struct nsIStackFrame nsIStackFrame; /* forward declaration */ +typedef struct nsIException nsIException; /* forward declaration */ + +/** + * IID for the nsISupports interface + * {00000000-0000-0000-c000-000000000046} + * + * To maintain binary compatibility with COM's IUnknown, we define the IID + * of nsISupports to be the same as that of COM's IUnknown. + */ +#define NS_ISUPPORTS_IID \ + { 0x00000000, 0x0000, 0x0000, \ + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } + +/** + * Reference count values + * + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * The following ifdef exists to maintain binary compatibility with + * IUnknown. + */ + +/** + * Basic component object model interface. Objects which implement + * this interface support runtime interface discovery (QueryInterface) + * and a reference counted memory model (AddRef/Release). This is + * modelled after the win32 IUnknown API. + */ +struct nsISupports_vtbl { + + /** + * @name Methods + */ + + /** + * A run time mechanism for interface discovery. + * @param aIID [in] A requested interface IID + * @param aInstancePtr [out] A pointer to an interface pointer to + * receive the result. + * @return NS_OK if the interface is supported by the associated + * instance, NS_NOINTERFACE if it is not. + * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. + */ + nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + /** + * Increases the reference count for this interface. + * The associated instance will not be deleted unless + * the reference count is returned to zero. + * + * @return The resulting reference count. + */ + nsresult (*AddRef)(nsISupports *pThis); + + /** + * Decreases the reference count for this interface. + * Generally, if the reference count returns to zero, + * the associated instance is deleted. + * + * @return The resulting reference count. + */ + nsresult (*Release)(nsISupports *pThis); + +}; + +struct nsISupports { + struct nsISupports_vtbl *vtbl; +}; + +/* starting interface: nsIException */ +#define NS_IEXCEPTION_IID_STR "f3a8d3b4-c424-4edc-8bf6-8974c983ba78" + +#define NS_IEXCEPTION_IID \ + {0xf3a8d3b4, 0xc424, 0x4edc, \ + { 0x8b, 0xf6, 0x89, 0x74, 0xc9, 0x83, 0xba, 0x78 }} + +struct nsIException_vtbl { + + /* Methods from the Class nsISupports */ + struct nsISupports_vtbl nsisupports; + + /* readonly attribute string message; */ + nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); + + /* readonly attribute nsresult (*result; */ + nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); + + /* readonly attribute string name; */ + nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); + + /* readonly attribute string filename; */ + nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); + + /* readonly attribute PRUint32 lineNumber; */ + nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); + + /* readonly attribute PRUint32 columnNumber; */ + nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); + + /* readonly attribute nsIStackFrame location; */ + nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); + + /* readonly attribute nsIException inner; */ + nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); + + /* readonly attribute nsISupports data; */ + nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); + + /* string toString (); */ + nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); +}; + +struct nsIException { + struct nsIException_vtbl *vtbl; +}; + +/* starting interface: nsIStackFrame */ +#define NS_ISTACKFRAME_IID_STR "91d82105-7c62-4f8b-9779-154277c0ee90" + +#define NS_ISTACKFRAME_IID \ + {0x91d82105, 0x7c62, 0x4f8b, \ + { 0x97, 0x79, 0x15, 0x42, 0x77, 0xc0, 0xee, 0x90 }} + +struct nsIStackFrame_vtbl { + + /* Methods from the Class nsISupports */ + struct nsISupports_vtbl nsisupports; + + /* readonly attribute PRUint32 language; */ + nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); + + /* readonly attribute string languageName; */ + nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); + + /* readonly attribute string filename; */ + nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); + + /* readonly attribute string name; */ + nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); + + /* readonly attribute PRInt32 lineNumber; */ + nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); + + /* readonly attribute string sourceLine; */ + nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); + + /* readonly attribute nsIStackFrame caller; */ + nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); + + /* string toString (); */ + nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); +}; + +struct nsIStackFrame { + struct nsIStackFrame_vtbl *vtbl; +}; + +/* starting interface: nsIEventTarget */ +#define NS_IEVENTTARGET_IID_STR "ea99ad5b-cc67-4efb-97c9-2ef620a59f2a" + +#define NS_IEVENTTARGET_IID \ + {0xea99ad5b, 0xcc67, 0x4efb, \ + { 0x97, 0xc9, 0x2e, 0xf6, 0x20, 0xa5, 0x9f, 0x2a }} + +struct nsIEventTarget; +typedef struct nsIEventTarget nsIEventTarget; + +struct nsIEventTarget_vtbl { + + struct nsISupports_vtbl nsisupports; + + nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); + + nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); + +}; + +struct nsIEventTarget { + struct nsIEventTarget_vtbl *vtbl; +}; + +/* starting interface: nsIEventQueue */ +#define NS_IEVENTQUEUE_IID_STR "176afb41-00a4-11d3-9f2a-00400553eef0" + +#define NS_IEVENTQUEUE_IID \ + {0x176afb41, 0x00a4, 0x11d3, \ + { 0x9f, 0x2a, 0x00, 0x40, 0x05, 0x53, 0xee, 0xf0 }} + +struct nsIEventQueue; +typedef struct nsIEventQueue nsIEventQueue; + +struct nsIEventQueue_vtbl { + + struct nsIEventTarget_vtbl nsieventtarget; + + nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); + + nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); + + nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); + + nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); + + nsresult (*EventLoop)(nsIEventQueue *pThis); + + nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); + + nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + + nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + + nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + + PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); + + nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); + + nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); + + nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); + + nsresult (*EnterMonitor)(nsIEventQueue *pThis); + + nsresult (*ExitMonitor)(nsIEventQueue *pThis); + + nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); + + nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); + + nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); + + nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); + +}; + +struct nsIEventQueue { + struct nsIEventQueue_vtbl *vtbl; +}; + + +#define VBOX_E_OBJECT_NOT_FOUND 0x80BB0001 +#define VBOX_E_INVALID_VM_STATE 0x80BB0002 +#define VBOX_E_VM_ERROR 0x80BB0003 +#define VBOX_E_FILE_ERROR 0x80BB0004 +#define VBOX_E_IPRT_ERROR 0x80BB0005 +#define VBOX_E_PDM_ERROR 0x80BB0006 +#define VBOX_E_INVALID_OBJECT_STATE 0x80BB0007 +#define VBOX_E_HOST_ERROR 0x80BB0008 +#define VBOX_E_NOT_SUPPORTED 0x80BB0009 +#define VBOX_E_XML_ERROR 0x80BB000A +#define VBOX_E_INVALID_SESSION_STATE 0x80BB000B +#define VBOX_E_OBJECT_IN_USE 0x80BB000C + + +struct IVirtualBoxErrorInfo; +struct IDHCPServer; +struct IVirtualBox; +struct IVFSExplorer; +struct IAppliance; +struct IVirtualSystemDescription; +struct IInternalMachineControl; +struct IBIOSSettings; +struct IPCIAddress; +struct IPCIDeviceAttachment; +struct IMachine; +struct IVRDEServerInfo; +struct IConsole; +struct IHostNetworkInterface; +struct IHost; +struct ISystemProperties; +struct IGuestOSType; +struct IAdditionsFacility; +struct IGuestSession; +struct IProcess; +struct IGuestProcess; +struct IDirectory; +struct IGuestDirectory; +struct IFile; +struct IGuestFile; +struct IFsObjInfo; +struct IGuestFsObjInfo; +struct IGuest; +struct IProgress; +struct ISnapshot; +struct IMediumAttachment; +struct IMedium; +struct IMediumFormat; +struct IKeyboard; +struct IMouse; +struct IFramebuffer; +struct IFramebufferOverlay; +struct IDisplay; +struct INetworkAdapter; +struct ISerialPort; +struct IParallelPort; +struct IMachineDebugger; +struct IUSBController; +struct IUSBDevice; +struct IUSBDeviceFilter; +struct IHostUSBDevice; +struct IHostUSBDeviceFilter; +struct IAudioAdapter; +struct IVRDEServer; +struct ISharedFolder; +struct IInternalSessionControl; +struct ISession; +struct IStorageController; +struct IManagedObjectRef; +struct IWebsessionManager; +struct IPerformanceMetric; +struct IPerformanceCollector; +struct INATEngine; +struct IExtPackPlugIn; +struct IExtPackBase; +struct IExtPack; +struct IExtPackFile; +struct IExtPackManager; +struct IBandwidthGroup; +struct IBandwidthControl; +struct IVirtualBoxClient; +struct IEventSource; +struct IEventListener; +struct IEvent; +struct IReusableEvent; +struct IMachineEvent; +struct IMachineStateChangedEvent; +struct IMachineDataChangedEvent; +struct IMediumRegisteredEvent; +struct IMachineRegisteredEvent; +struct ISessionStateChangedEvent; +struct IGuestPropertyChangedEvent; +struct ISnapshotEvent; +struct ISnapshotTakenEvent; +struct ISnapshotDeletedEvent; +struct ISnapshotChangedEvent; +struct IMousePointerShapeChangedEvent; +struct IMouseCapabilityChangedEvent; +struct IKeyboardLedsChangedEvent; +struct IStateChangedEvent; +struct IAdditionsStateChangedEvent; +struct INetworkAdapterChangedEvent; +struct ISerialPortChangedEvent; +struct IParallelPortChangedEvent; +struct IStorageControllerChangedEvent; +struct IMediumChangedEvent; +struct IClipboardModeChangedEvent; +struct IDragAndDropModeChangedEvent; +struct ICPUChangedEvent; +struct ICPUExecutionCapChangedEvent; +struct IGuestKeyboardEvent; +struct IGuestMouseEvent; +struct IVRDEServerChangedEvent; +struct IVRDEServerInfoChangedEvent; +struct IUSBControllerChangedEvent; +struct IUSBDeviceStateChangedEvent; +struct ISharedFolderChangedEvent; +struct IRuntimeErrorEvent; +struct IEventSourceChangedEvent; +struct IExtraDataChangedEvent; +struct IVetoEvent; +struct IExtraDataCanChangeEvent; +struct ICanShowWindowEvent; +struct IShowWindowEvent; +struct INATRedirectEvent; +struct IHostPCIDevicePlugEvent; +struct IVBoxSVCAvailabilityChangedEvent; +struct IBandwidthGroupChangedEvent; +struct IGuestMonitorChangedEvent; +struct IStorageDeviceChangedEvent; + +typedef struct IVirtualBoxErrorInfo IVirtualBoxErrorInfo; +typedef struct IDHCPServer IDHCPServer; +typedef struct IVirtualBox IVirtualBox; +typedef struct IVFSExplorer IVFSExplorer; +typedef struct IAppliance IAppliance; +typedef struct IVirtualSystemDescription IVirtualSystemDescription; +typedef struct IInternalMachineControl IInternalMachineControl; +typedef struct IBIOSSettings IBIOSSettings; +typedef struct IPCIAddress IPCIAddress; +typedef struct IPCIDeviceAttachment IPCIDeviceAttachment; +typedef struct IMachine IMachine; +typedef struct IVRDEServerInfo IVRDEServerInfo; +typedef struct IConsole IConsole; +typedef struct IHostNetworkInterface IHostNetworkInterface; +typedef struct IHost IHost; +typedef struct ISystemProperties ISystemProperties; +typedef struct IGuestOSType IGuestOSType; +typedef struct IAdditionsFacility IAdditionsFacility; +typedef struct IGuestSession IGuestSession; +typedef struct IProcess IProcess; +typedef struct IGuestProcess IGuestProcess; +typedef struct IDirectory IDirectory; +typedef struct IGuestDirectory IGuestDirectory; +typedef struct IFile IFile; +typedef struct IGuestFile IGuestFile; +typedef struct IFsObjInfo IFsObjInfo; +typedef struct IGuestFsObjInfo IGuestFsObjInfo; +typedef struct IGuest IGuest; +typedef struct IProgress IProgress; +typedef struct ISnapshot ISnapshot; +typedef struct IMediumAttachment IMediumAttachment; +typedef struct IMedium IMedium; +typedef struct IMediumFormat IMediumFormat; +typedef struct IKeyboard IKeyboard; +typedef struct IMouse IMouse; +typedef struct IFramebuffer IFramebuffer; +typedef struct IFramebufferOverlay IFramebufferOverlay; +typedef struct IDisplay IDisplay; +typedef struct INetworkAdapter INetworkAdapter; +typedef struct ISerialPort ISerialPort; +typedef struct IParallelPort IParallelPort; +typedef struct IMachineDebugger IMachineDebugger; +typedef struct IUSBController IUSBController; +typedef struct IUSBDevice IUSBDevice; +typedef struct IUSBDeviceFilter IUSBDeviceFilter; +typedef struct IHostUSBDevice IHostUSBDevice; +typedef struct IHostUSBDeviceFilter IHostUSBDeviceFilter; +typedef struct IAudioAdapter IAudioAdapter; +typedef struct IVRDEServer IVRDEServer; +typedef struct ISharedFolder ISharedFolder; +typedef struct IInternalSessionControl IInternalSessionControl; +typedef struct ISession ISession; +typedef struct IStorageController IStorageController; +typedef struct IManagedObjectRef IManagedObjectRef; +typedef struct IWebsessionManager IWebsessionManager; +typedef struct IPerformanceMetric IPerformanceMetric; +typedef struct IPerformanceCollector IPerformanceCollector; +typedef struct INATEngine INATEngine; +typedef struct IExtPackPlugIn IExtPackPlugIn; +typedef struct IExtPackBase IExtPackBase; +typedef struct IExtPack IExtPack; +typedef struct IExtPackFile IExtPackFile; +typedef struct IExtPackManager IExtPackManager; +typedef struct IBandwidthGroup IBandwidthGroup; +typedef struct IBandwidthControl IBandwidthControl; +typedef struct IVirtualBoxClient IVirtualBoxClient; +typedef struct IEventSource IEventSource; +typedef struct IEventListener IEventListener; +typedef struct IEvent IEvent; +typedef struct IReusableEvent IReusableEvent; +typedef struct IMachineEvent IMachineEvent; +typedef struct IMachineStateChangedEvent IMachineStateChangedEvent; +typedef struct IMachineDataChangedEvent IMachineDataChangedEvent; +typedef struct IMediumRegisteredEvent IMediumRegisteredEvent; +typedef struct IMachineRegisteredEvent IMachineRegisteredEvent; +typedef struct ISessionStateChangedEvent ISessionStateChangedEvent; +typedef struct IGuestPropertyChangedEvent IGuestPropertyChangedEvent; +typedef struct ISnapshotEvent ISnapshotEvent; +typedef struct ISnapshotTakenEvent ISnapshotTakenEvent; +typedef struct ISnapshotDeletedEvent ISnapshotDeletedEvent; +typedef struct ISnapshotChangedEvent ISnapshotChangedEvent; +typedef struct IMousePointerShapeChangedEvent IMousePointerShapeChangedEvent; +typedef struct IMouseCapabilityChangedEvent IMouseCapabilityChangedEvent; +typedef struct IKeyboardLedsChangedEvent IKeyboardLedsChangedEvent; +typedef struct IStateChangedEvent IStateChangedEvent; +typedef struct IAdditionsStateChangedEvent IAdditionsStateChangedEvent; +typedef struct INetworkAdapterChangedEvent INetworkAdapterChangedEvent; +typedef struct ISerialPortChangedEvent ISerialPortChangedEvent; +typedef struct IParallelPortChangedEvent IParallelPortChangedEvent; +typedef struct IStorageControllerChangedEvent IStorageControllerChangedEvent; +typedef struct IMediumChangedEvent IMediumChangedEvent; +typedef struct IClipboardModeChangedEvent IClipboardModeChangedEvent; +typedef struct IDragAndDropModeChangedEvent IDragAndDropModeChangedEvent; +typedef struct ICPUChangedEvent ICPUChangedEvent; +typedef struct ICPUExecutionCapChangedEvent ICPUExecutionCapChangedEvent; +typedef struct IGuestKeyboardEvent IGuestKeyboardEvent; +typedef struct IGuestMouseEvent IGuestMouseEvent; +typedef struct IVRDEServerChangedEvent IVRDEServerChangedEvent; +typedef struct IVRDEServerInfoChangedEvent IVRDEServerInfoChangedEvent; +typedef struct IUSBControllerChangedEvent IUSBControllerChangedEvent; +typedef struct IUSBDeviceStateChangedEvent IUSBDeviceStateChangedEvent; +typedef struct ISharedFolderChangedEvent ISharedFolderChangedEvent; +typedef struct IRuntimeErrorEvent IRuntimeErrorEvent; +typedef struct IEventSourceChangedEvent IEventSourceChangedEvent; +typedef struct IExtraDataChangedEvent IExtraDataChangedEvent; +typedef struct IVetoEvent IVetoEvent; +typedef struct IExtraDataCanChangeEvent IExtraDataCanChangeEvent; +typedef struct ICanShowWindowEvent ICanShowWindowEvent; +typedef struct IShowWindowEvent IShowWindowEvent; +typedef struct INATRedirectEvent INATRedirectEvent; +typedef struct IHostPCIDevicePlugEvent IHostPCIDevicePlugEvent; +typedef struct IVBoxSVCAvailabilityChangedEvent IVBoxSVCAvailabilityChangedEvent; +typedef struct IBandwidthGroupChangedEvent IBandwidthGroupChangedEvent; +typedef struct IGuestMonitorChangedEvent IGuestMonitorChangedEvent; +typedef struct IStorageDeviceChangedEvent IStorageDeviceChangedEvent; + +/* Start of enum SettingsVersion Declaration */ +#define SETTINGSVERSION_IID_STR "52bd6f5f-1adb-4493-975d-581a9c4b803f" +#define SETTINGSVERSION_IID { \ + 0x52bd6f5f, 0x1adb, 0x4493, \ + { 0x97, 0x5d, 0x58, 0x1a, 0x9c, 0x4b, 0x80, 0x3f } \ +} +enum SettingsVersion +{ + SettingsVersion_Null = 0, + SettingsVersion_v1_0 = 1, + SettingsVersion_v1_1 = 2, + SettingsVersion_v1_2 = 3, + SettingsVersion_v1_3pre = 4, + SettingsVersion_v1_3 = 5, + SettingsVersion_v1_4 = 6, + SettingsVersion_v1_5 = 7, + SettingsVersion_v1_6 = 8, + SettingsVersion_v1_7 = 9, + SettingsVersion_v1_8 = 10, + SettingsVersion_v1_9 = 11, + SettingsVersion_v1_10 = 12, + SettingsVersion_v1_11 = 13, + SettingsVersion_v1_12 = 14, + SettingsVersion_v1_13 = 15, + SettingsVersion_Future = 99999 +}; +/* End of enum SettingsVersion Declaration */ + + +/* Start of enum AccessMode Declaration */ +#define ACCESSMODE_IID_STR "1da0007c-ddf7-4be8-bcac-d84a1558785f" +#define ACCESSMODE_IID { \ + 0x1da0007c, 0xddf7, 0x4be8, \ + { 0xbc, 0xac, 0xd8, 0x4a, 0x15, 0x58, 0x78, 0x5f } \ +} +enum AccessMode +{ + AccessMode_ReadOnly = 1, + AccessMode_ReadWrite = 2 +}; +/* End of enum AccessMode Declaration */ + + +/* Start of enum MachineState Declaration */ +#define MACHINESTATE_IID_STR "ec6c6a9e-113d-4ff4-b44f-0b69f21c97fe" +#define MACHINESTATE_IID { \ + 0xec6c6a9e, 0x113d, 0x4ff4, \ + { 0xb4, 0x4f, 0x0b, 0x69, 0xf2, 0x1c, 0x97, 0xfe } \ +} +enum MachineState +{ + MachineState_Null = 0, + MachineState_PoweredOff = 1, + MachineState_Saved = 2, + MachineState_Teleported = 3, + MachineState_Aborted = 4, + MachineState_Running = 5, + MachineState_Paused = 6, + MachineState_Stuck = 7, + MachineState_Teleporting = 8, + MachineState_LiveSnapshotting = 9, + MachineState_Starting = 10, + MachineState_Stopping = 11, + MachineState_Saving = 12, + MachineState_Restoring = 13, + MachineState_TeleportingPausedVM = 14, + MachineState_TeleportingIn = 15, + MachineState_FaultTolerantSyncing = 16, + MachineState_DeletingSnapshotOnline = 17, + MachineState_DeletingSnapshotPaused = 18, + MachineState_RestoringSnapshot = 19, + MachineState_DeletingSnapshot = 20, + MachineState_SettingUp = 21, + MachineState_FirstOnline = 5, + MachineState_LastOnline = 18, + MachineState_FirstTransient = 8, + MachineState_LastTransient = 21 +}; +/* End of enum MachineState Declaration */ + + +/* Start of enum SessionState Declaration */ +#define SESSIONSTATE_IID_STR "cf2700c0-ea4b-47ae-9725-7810114b94d8" +#define SESSIONSTATE_IID { \ + 0xcf2700c0, 0xea4b, 0x47ae, \ + { 0x97, 0x25, 0x78, 0x10, 0x11, 0x4b, 0x94, 0xd8 } \ +} +enum SessionState +{ + SessionState_Null = 0, + SessionState_Unlocked = 1, + SessionState_Locked = 2, + SessionState_Spawning = 3, + SessionState_Unlocking = 4 +}; +/* End of enum SessionState Declaration */ + + +/* Start of enum CPUPropertyType Declaration */ +#define CPUPROPERTYTYPE_IID_STR "24d356a6-2f45-4abd-b977-1cbe9c4701f5" +#define CPUPROPERTYTYPE_IID { \ + 0x24d356a6, 0x2f45, 0x4abd, \ + { 0xb9, 0x77, 0x1c, 0xbe, 0x9c, 0x47, 0x01, 0xf5 } \ +} +enum CPUPropertyType +{ + CPUPropertyType_Null = 0, + CPUPropertyType_PAE = 1, + CPUPropertyType_Synthetic = 2 +}; +/* End of enum CPUPropertyType Declaration */ + + +/* Start of enum HWVirtExPropertyType Declaration */ +#define HWVIRTEXPROPERTYTYPE_IID_STR "ce81dfdd-d2b8-4a90-bbea-40ee8b7ffcee" +#define HWVIRTEXPROPERTYTYPE_IID { \ + 0xce81dfdd, 0xd2b8, 0x4a90, \ + { 0xbb, 0xea, 0x40, 0xee, 0x8b, 0x7f, 0xfc, 0xee } \ +} +enum HWVirtExPropertyType +{ + HWVirtExPropertyType_Null = 0, + HWVirtExPropertyType_Enabled = 1, + HWVirtExPropertyType_Exclusive = 2, + HWVirtExPropertyType_VPID = 3, + HWVirtExPropertyType_NestedPaging = 4, + HWVirtExPropertyType_LargePages = 5, + HWVirtExPropertyType_Force = 6 +}; +/* End of enum HWVirtExPropertyType Declaration */ + + +/* Start of enum FaultToleranceState Declaration */ +#define FAULTTOLERANCESTATE_IID_STR "5124f7ec-6b67-493c-9dee-ee45a44114e1" +#define FAULTTOLERANCESTATE_IID { \ + 0x5124f7ec, 0x6b67, 0x493c, \ + { 0x9d, 0xee, 0xee, 0x45, 0xa4, 0x41, 0x14, 0xe1 } \ +} +enum FaultToleranceState +{ + FaultToleranceState_Inactive = 1, + FaultToleranceState_Master = 2, + FaultToleranceState_Standby = 3 +}; +/* End of enum FaultToleranceState Declaration */ + + +/* Start of enum LockType Declaration */ +#define LOCKTYPE_IID_STR "168a6a8e-12fd-4878-a1f9-38a750a56089" +#define LOCKTYPE_IID { \ + 0x168a6a8e, 0x12fd, 0x4878, \ + { 0xa1, 0xf9, 0x38, 0xa7, 0x50, 0xa5, 0x60, 0x89 } \ +} +enum LockType +{ + LockType_Write = 2, + LockType_Shared = 1, + LockType_VM = 3 +}; +/* End of enum LockType Declaration */ + + +/* Start of enum SessionType Declaration */ +#define SESSIONTYPE_IID_STR "A13C02CB-0C2C-421E-8317-AC0E8AAA153A" +#define SESSIONTYPE_IID { \ + 0xA13C02CB, 0x0C2C, 0x421E, \ + { 0x83, 0x17, 0xAC, 0x0E, 0x8A, 0xAA, 0x15, 0x3A } \ +} +enum SessionType +{ + SessionType_Null = 0, + SessionType_WriteLock = 1, + SessionType_Remote = 2, + SessionType_Shared = 3 +}; +/* End of enum SessionType Declaration */ + + +/* Start of enum DeviceType Declaration */ +#define DEVICETYPE_IID_STR "6d9420f7-0b56-4636-99f9-7346f1b01e57" +#define DEVICETYPE_IID { \ + 0x6d9420f7, 0x0b56, 0x4636, \ + { 0x99, 0xf9, 0x73, 0x46, 0xf1, 0xb0, 0x1e, 0x57 } \ +} +enum DeviceType +{ + DeviceType_Null = 0, + DeviceType_Floppy = 1, + DeviceType_DVD = 2, + DeviceType_HardDisk = 3, + DeviceType_Network = 4, + DeviceType_USB = 5, + DeviceType_SharedFolder = 6 +}; +/* End of enum DeviceType Declaration */ + + +/* Start of enum DeviceActivity Declaration */ +#define DEVICEACTIVITY_IID_STR "6FC8AEAA-130A-4eb5-8954-3F921422D707" +#define DEVICEACTIVITY_IID { \ + 0x6FC8AEAA, 0x130A, 0x4eb5, \ + { 0x89, 0x54, 0x3F, 0x92, 0x14, 0x22, 0xD7, 0x07 } \ +} +enum DeviceActivity +{ + DeviceActivity_Null = 0, + DeviceActivity_Idle = 1, + DeviceActivity_Reading = 2, + DeviceActivity_Writing = 3 +}; +/* End of enum DeviceActivity Declaration */ + + +/* Start of enum ClipboardMode Declaration */ +#define CLIPBOARDMODE_IID_STR "33364716-4008-4701-8f14-be0fa3d62950" +#define CLIPBOARDMODE_IID { \ + 0x33364716, 0x4008, 0x4701, \ + { 0x8f, 0x14, 0xbe, 0x0f, 0xa3, 0xd6, 0x29, 0x50 } \ +} +enum ClipboardMode +{ + ClipboardMode_Disabled = 0, + ClipboardMode_HostToGuest = 1, + ClipboardMode_GuestToHost = 2, + ClipboardMode_Bidirectional = 3 +}; +/* End of enum ClipboardMode Declaration */ + + +/* Start of enum DragAndDropMode Declaration */ +#define DRAGANDDROPMODE_IID_STR "b618ea0e-b6fb-4f8d-97f7-5e237e49b547" +#define DRAGANDDROPMODE_IID { \ + 0xb618ea0e, 0xb6fb, 0x4f8d, \ + { 0x97, 0xf7, 0x5e, 0x23, 0x7e, 0x49, 0xb5, 0x47 } \ +} +enum DragAndDropMode +{ + DragAndDropMode_Disabled = 0, + DragAndDropMode_HostToGuest = 1, + DragAndDropMode_GuestToHost = 2, + DragAndDropMode_Bidirectional = 3 +}; +/* End of enum DragAndDropMode Declaration */ + + +/* Start of enum Scope Declaration */ +#define SCOPE_IID_STR "7c91096e-499e-4eca-9f9b-9001438d7855" +#define SCOPE_IID { \ + 0x7c91096e, 0x499e, 0x4eca, \ + { 0x9f, 0x9b, 0x90, 0x01, 0x43, 0x8d, 0x78, 0x55 } \ +} +enum Scope +{ + Scope_Global = 0, + Scope_Machine = 1, + Scope_Session = 2 +}; +/* End of enum Scope Declaration */ + + +/* Start of enum BIOSBootMenuMode Declaration */ +#define BIOSBOOTMENUMODE_IID_STR "ae4fb9f7-29d2-45b4-b2c7-d579603135d5" +#define BIOSBOOTMENUMODE_IID { \ + 0xae4fb9f7, 0x29d2, 0x45b4, \ + { 0xb2, 0xc7, 0xd5, 0x79, 0x60, 0x31, 0x35, 0xd5 } \ +} +enum BIOSBootMenuMode +{ + BIOSBootMenuMode_Disabled = 0, + BIOSBootMenuMode_MenuOnly = 1, + BIOSBootMenuMode_MessageAndMenu = 2 +}; +/* End of enum BIOSBootMenuMode Declaration */ + + +/* Start of enum ProcessorFeature Declaration */ +#define PROCESSORFEATURE_IID_STR "64c38e6b-8bcf-45ad-ac03-9b406287c5bf" +#define PROCESSORFEATURE_IID { \ + 0x64c38e6b, 0x8bcf, 0x45ad, \ + { 0xac, 0x03, 0x9b, 0x40, 0x62, 0x87, 0xc5, 0xbf } \ +} +enum ProcessorFeature +{ + ProcessorFeature_HWVirtEx = 0, + ProcessorFeature_PAE = 1, + ProcessorFeature_LongMode = 2, + ProcessorFeature_NestedPaging = 3 +}; +/* End of enum ProcessorFeature Declaration */ + + +/* Start of enum FirmwareType Declaration */ +#define FIRMWARETYPE_IID_STR "b903f264-c230-483e-ac74-2b37ce60d371" +#define FIRMWARETYPE_IID { \ + 0xb903f264, 0xc230, 0x483e, \ + { 0xac, 0x74, 0x2b, 0x37, 0xce, 0x60, 0xd3, 0x71 } \ +} +enum FirmwareType +{ + FirmwareType_BIOS = 1, + FirmwareType_EFI = 2, + FirmwareType_EFI32 = 3, + FirmwareType_EFI64 = 4, + FirmwareType_EFIDUAL = 5 +}; +/* End of enum FirmwareType Declaration */ + + +/* Start of enum PointingHIDType Declaration */ +#define POINTINGHIDTYPE_IID_STR "e44b2f7b-72ba-44fb-9e53-2186014f0d17" +#define POINTINGHIDTYPE_IID { \ + 0xe44b2f7b, 0x72ba, 0x44fb, \ + { 0x9e, 0x53, 0x21, 0x86, 0x01, 0x4f, 0x0d, 0x17 } \ +} +enum PointingHIDType +{ + PointingHIDType_None = 1, + PointingHIDType_PS2Mouse = 2, + PointingHIDType_USBMouse = 3, + PointingHIDType_USBTablet = 4, + PointingHIDType_ComboMouse = 5 +}; +/* End of enum PointingHIDType Declaration */ + + +/* Start of enum KeyboardHIDType Declaration */ +#define KEYBOARDHIDTYPE_IID_STR "383e43d7-5c7c-4ec8-9cb8-eda1bccd6699" +#define KEYBOARDHIDTYPE_IID { \ + 0x383e43d7, 0x5c7c, 0x4ec8, \ + { 0x9c, 0xb8, 0xed, 0xa1, 0xbc, 0xcd, 0x66, 0x99 } \ +} +enum KeyboardHIDType +{ + KeyboardHIDType_None = 1, + KeyboardHIDType_PS2Keyboard = 2, + KeyboardHIDType_USBKeyboard = 3, + KeyboardHIDType_ComboKeyboard = 4 +}; +/* End of enum KeyboardHIDType Declaration */ + + +/* Start of enum VFSType Declaration */ +#define VFSTYPE_IID_STR "813999ba-b949-48a8-9230-aadc6285e2f2" +#define VFSTYPE_IID { \ + 0x813999ba, 0xb949, 0x48a8, \ + { 0x92, 0x30, 0xaa, 0xdc, 0x62, 0x85, 0xe2, 0xf2 } \ +} +enum VFSType +{ + VFSType_File = 1, + VFSType_Cloud = 2, + VFSType_S3 = 3, + VFSType_WebDav = 4 +}; +/* End of enum VFSType Declaration */ + + +/* Start of enum VFSFileType Declaration */ +#define VFSFILETYPE_IID_STR "714333cd-44e2-415f-a245-d378fa9b1242" +#define VFSFILETYPE_IID { \ + 0x714333cd, 0x44e2, 0x415f, \ + { 0xa2, 0x45, 0xd3, 0x78, 0xfa, 0x9b, 0x12, 0x42 } \ +} +enum VFSFileType +{ + VFSFileType_Unknown = 1, + VFSFileType_Fifo = 2, + VFSFileType_DevChar = 3, + VFSFileType_Directory = 4, + VFSFileType_DevBlock = 5, + VFSFileType_File = 6, + VFSFileType_SymLink = 7, + VFSFileType_Socket = 8, + VFSFileType_WhiteOut = 9 +}; +/* End of enum VFSFileType Declaration */ + + +/* Start of enum ImportOptions Declaration */ +#define IMPORTOPTIONS_IID_STR "0a981523-3b20-4004-8ee3-dfd322202ace" +#define IMPORTOPTIONS_IID { \ + 0x0a981523, 0x3b20, 0x4004, \ + { 0x8e, 0xe3, 0xdf, 0xd3, 0x22, 0x20, 0x2a, 0xce } \ +} +enum ImportOptions +{ + ImportOptions_KeepAllMACs = 1, + ImportOptions_KeepNATMACs = 2 +}; +/* End of enum ImportOptions Declaration */ + + +/* Start of enum VirtualSystemDescriptionType Declaration */ +#define VIRTUALSYSTEMDESCRIPTIONTYPE_IID_STR "303c0900-a746-4612-8c67-79003e91f459" +#define VIRTUALSYSTEMDESCRIPTIONTYPE_IID { \ + 0x303c0900, 0xa746, 0x4612, \ + { 0x8c, 0x67, 0x79, 0x00, 0x3e, 0x91, 0xf4, 0x59 } \ +} +enum VirtualSystemDescriptionType +{ + VirtualSystemDescriptionType_Ignore = 1, + VirtualSystemDescriptionType_OS = 2, + VirtualSystemDescriptionType_Name = 3, + VirtualSystemDescriptionType_Product = 4, + VirtualSystemDescriptionType_Vendor = 5, + VirtualSystemDescriptionType_Version = 6, + VirtualSystemDescriptionType_ProductUrl = 7, + VirtualSystemDescriptionType_VendorUrl = 8, + VirtualSystemDescriptionType_Description = 9, + VirtualSystemDescriptionType_License = 10, + VirtualSystemDescriptionType_Miscellaneous = 11, + VirtualSystemDescriptionType_CPU = 12, + VirtualSystemDescriptionType_Memory = 13, + VirtualSystemDescriptionType_HardDiskControllerIDE = 14, + VirtualSystemDescriptionType_HardDiskControllerSATA = 15, + VirtualSystemDescriptionType_HardDiskControllerSCSI = 16, + VirtualSystemDescriptionType_HardDiskControllerSAS = 17, + VirtualSystemDescriptionType_HardDiskImage = 18, + VirtualSystemDescriptionType_Floppy = 19, + VirtualSystemDescriptionType_CDROM = 20, + VirtualSystemDescriptionType_NetworkAdapter = 21, + VirtualSystemDescriptionType_USBController = 22, + VirtualSystemDescriptionType_SoundCard = 23, + VirtualSystemDescriptionType_SettingsFile = 24 +}; +/* End of enum VirtualSystemDescriptionType Declaration */ + + +/* Start of enum VirtualSystemDescriptionValueType Declaration */ +#define VIRTUALSYSTEMDESCRIPTIONVALUETYPE_IID_STR "56d9403f-3425-4118-9919-36f2a9b8c77c" +#define VIRTUALSYSTEMDESCRIPTIONVALUETYPE_IID { \ + 0x56d9403f, 0x3425, 0x4118, \ + { 0x99, 0x19, 0x36, 0xf2, 0xa9, 0xb8, 0xc7, 0x7c } \ +} +enum VirtualSystemDescriptionValueType +{ + VirtualSystemDescriptionValueType_Reference = 1, + VirtualSystemDescriptionValueType_Original = 2, + VirtualSystemDescriptionValueType_Auto = 3, + VirtualSystemDescriptionValueType_ExtraConfig = 4 +}; +/* End of enum VirtualSystemDescriptionValueType Declaration */ + + +/* Start of enum CleanupMode Declaration */ +#define CLEANUPMODE_IID_STR "67897c50-7cca-47a9-83f6-ce8fd8eb5441" +#define CLEANUPMODE_IID { \ + 0x67897c50, 0x7cca, 0x47a9, \ + { 0x83, 0xf6, 0xce, 0x8f, 0xd8, 0xeb, 0x54, 0x41 } \ +} +enum CleanupMode +{ + CleanupMode_UnregisterOnly = 1, + CleanupMode_DetachAllReturnNone = 2, + CleanupMode_DetachAllReturnHardDisksOnly = 3, + CleanupMode_Full = 4 +}; +/* End of enum CleanupMode Declaration */ + + +/* Start of enum CloneMode Declaration */ +#define CLONEMODE_IID_STR "A7A159FE-5096-4B8D-8C3C-D033CB0B35A8" +#define CLONEMODE_IID { \ + 0xA7A159FE, 0x5096, 0x4B8D, \ + { 0x8C, 0x3C, 0xD0, 0x33, 0xCB, 0x0B, 0x35, 0xA8 } \ +} +enum CloneMode +{ + CloneMode_MachineState = 1, + CloneMode_MachineAndChildStates = 2, + CloneMode_AllStates = 3 +}; +/* End of enum CloneMode Declaration */ + + +/* Start of enum CloneOptions Declaration */ +#define CLONEOPTIONS_IID_STR "22243f8e-96ab-497c-8cf0-f40a566c630b" +#define CLONEOPTIONS_IID { \ + 0x22243f8e, 0x96ab, 0x497c, \ + { 0x8c, 0xf0, 0xf4, 0x0a, 0x56, 0x6c, 0x63, 0x0b } \ +} +enum CloneOptions +{ + CloneOptions_Link = 1, + CloneOptions_KeepAllMACs = 2, + CloneOptions_KeepNATMACs = 3, + CloneOptions_KeepDiskNames = 4 +}; +/* End of enum CloneOptions Declaration */ + + +/* Start of enum AutostopType Declaration */ +#define AUTOSTOPTYPE_IID_STR "6bb96740-cf34-470d-aab2-2cd48ea2e10e" +#define AUTOSTOPTYPE_IID { \ + 0x6bb96740, 0xcf34, 0x470d, \ + { 0xaa, 0xb2, 0x2c, 0xd4, 0x8e, 0xa2, 0xe1, 0x0e } \ +} +enum AutostopType +{ + AutostopType_Disabled = 1, + AutostopType_SaveState = 2, + AutostopType_PowerOff = 3, + AutostopType_AcpiShutdown = 4 +}; +/* End of enum AutostopType Declaration */ + + +/* Start of enum HostNetworkInterfaceMediumType Declaration */ +#define HOSTNETWORKINTERFACEMEDIUMTYPE_IID_STR "1aa54aaf-2497-45a2-bfb1-8eb225e93d5b" +#define HOSTNETWORKINTERFACEMEDIUMTYPE_IID { \ + 0x1aa54aaf, 0x2497, 0x45a2, \ + { 0xbf, 0xb1, 0x8e, 0xb2, 0x25, 0xe9, 0x3d, 0x5b } \ +} +enum HostNetworkInterfaceMediumType +{ + HostNetworkInterfaceMediumType_Unknown = 0, + HostNetworkInterfaceMediumType_Ethernet = 1, + HostNetworkInterfaceMediumType_PPP = 2, + HostNetworkInterfaceMediumType_SLIP = 3 +}; +/* End of enum HostNetworkInterfaceMediumType Declaration */ + + +/* Start of enum HostNetworkInterfaceStatus Declaration */ +#define HOSTNETWORKINTERFACESTATUS_IID_STR "CC474A69-2710-434B-8D99-C38E5D5A6F41" +#define HOSTNETWORKINTERFACESTATUS_IID { \ + 0xCC474A69, 0x2710, 0x434B, \ + { 0x8D, 0x99, 0xC3, 0x8E, 0x5D, 0x5A, 0x6F, 0x41 } \ +} +enum HostNetworkInterfaceStatus +{ + HostNetworkInterfaceStatus_Unknown = 0, + HostNetworkInterfaceStatus_Up = 1, + HostNetworkInterfaceStatus_Down = 2 +}; +/* End of enum HostNetworkInterfaceStatus Declaration */ + + +/* Start of enum HostNetworkInterfaceType Declaration */ +#define HOSTNETWORKINTERFACETYPE_IID_STR "67431b00-9946-48a2-bc02-b25c5919f4f3" +#define HOSTNETWORKINTERFACETYPE_IID { \ + 0x67431b00, 0x9946, 0x48a2, \ + { 0xbc, 0x02, 0xb2, 0x5c, 0x59, 0x19, 0xf4, 0xf3 } \ +} +enum HostNetworkInterfaceType +{ + HostNetworkInterfaceType_Bridged = 1, + HostNetworkInterfaceType_HostOnly = 2 +}; +/* End of enum HostNetworkInterfaceType Declaration */ + + +/* Start of enum AdditionsFacilityType Declaration */ +#define ADDITIONSFACILITYTYPE_IID_STR "98f7f957-89fb-49b6-a3b1-31e3285eb1d8" +#define ADDITIONSFACILITYTYPE_IID { \ + 0x98f7f957, 0x89fb, 0x49b6, \ + { 0xa3, 0xb1, 0x31, 0xe3, 0x28, 0x5e, 0xb1, 0xd8 } \ +} +enum AdditionsFacilityType +{ + AdditionsFacilityType_None = 0, + AdditionsFacilityType_VBoxGuestDriver = 20, + AdditionsFacilityType_AutoLogon = 90, + AdditionsFacilityType_VBoxService = 100, + AdditionsFacilityType_VBoxTrayClient = 101, + AdditionsFacilityType_Seamless = 1000, + AdditionsFacilityType_Graphics = 1100, + AdditionsFacilityType_All = 2147483646 +}; +/* End of enum AdditionsFacilityType Declaration */ + + +/* Start of enum AdditionsFacilityClass Declaration */ +#define ADDITIONSFACILITYCLASS_IID_STR "446451b2-c88d-4e5d-84c9-91bc7f533f5f" +#define ADDITIONSFACILITYCLASS_IID { \ + 0x446451b2, 0xc88d, 0x4e5d, \ + { 0x84, 0xc9, 0x91, 0xbc, 0x7f, 0x53, 0x3f, 0x5f } \ +} +enum AdditionsFacilityClass +{ + AdditionsFacilityClass_None = 0, + AdditionsFacilityClass_Driver = 10, + AdditionsFacilityClass_Service = 30, + AdditionsFacilityClass_Program = 50, + AdditionsFacilityClass_Feature = 100, + AdditionsFacilityClass_ThirdParty = 999, + AdditionsFacilityClass_All = 2147483646 +}; +/* End of enum AdditionsFacilityClass Declaration */ + + +/* Start of enum AdditionsFacilityStatus Declaration */ +#define ADDITIONSFACILITYSTATUS_IID_STR "ce06f9e1-394e-4fe9-9368-5a88c567dbde" +#define ADDITIONSFACILITYSTATUS_IID { \ + 0xce06f9e1, 0x394e, 0x4fe9, \ + { 0x93, 0x68, 0x5a, 0x88, 0xc5, 0x67, 0xdb, 0xde } \ +} +enum AdditionsFacilityStatus +{ + AdditionsFacilityStatus_Inactive = 0, + AdditionsFacilityStatus_Paused = 1, + AdditionsFacilityStatus_PreInit = 20, + AdditionsFacilityStatus_Init = 30, + AdditionsFacilityStatus_Active = 50, + AdditionsFacilityStatus_Terminating = 100, + AdditionsFacilityStatus_Terminated = 101, + AdditionsFacilityStatus_Failed = 800, + AdditionsFacilityStatus_Unknown = 999 +}; +/* End of enum AdditionsFacilityStatus Declaration */ + + +/* Start of enum AdditionsRunLevelType Declaration */ +#define ADDITIONSRUNLEVELTYPE_IID_STR "a25417ee-a9dd-4f5b-b0dc-377860087754" +#define ADDITIONSRUNLEVELTYPE_IID { \ + 0xa25417ee, 0xa9dd, 0x4f5b, \ + { 0xb0, 0xdc, 0x37, 0x78, 0x60, 0x08, 0x77, 0x54 } \ +} +enum AdditionsRunLevelType +{ + AdditionsRunLevelType_None = 0, + AdditionsRunLevelType_System = 1, + AdditionsRunLevelType_Userland = 2, + AdditionsRunLevelType_Desktop = 3 +}; +/* End of enum AdditionsRunLevelType Declaration */ + + +/* Start of enum AdditionsUpdateFlag Declaration */ +#define ADDITIONSUPDATEFLAG_IID_STR "726a818d-18d6-4389-94e8-3e9e6826171a" +#define ADDITIONSUPDATEFLAG_IID { \ + 0x726a818d, 0x18d6, 0x4389, \ + { 0x94, 0xe8, 0x3e, 0x9e, 0x68, 0x26, 0x17, 0x1a } \ +} +enum AdditionsUpdateFlag +{ + AdditionsUpdateFlag_None = 0, + AdditionsUpdateFlag_WaitForUpdateStartOnly = 1 +}; +/* End of enum AdditionsUpdateFlag Declaration */ + + +/* Start of enum FileSeekType Declaration */ +#define FILESEEKTYPE_IID_STR "1b73f4f3-3515-4073-a506-76878d9e2541" +#define FILESEEKTYPE_IID { \ + 0x1b73f4f3, 0x3515, 0x4073, \ + { 0xa5, 0x06, 0x76, 0x87, 0x8d, 0x9e, 0x25, 0x41 } \ +} +enum FileSeekType +{ + FileSeekType_Set = 0, + FileSeekType_Current = 1 +}; +/* End of enum FileSeekType Declaration */ + + +/* Start of enum ProcessInputFlag Declaration */ +#define PROCESSINPUTFLAG_IID_STR "5d38c1dd-2604-4ddf-92e5-0c0cdd3bdbd5" +#define PROCESSINPUTFLAG_IID { \ + 0x5d38c1dd, 0x2604, 0x4ddf, \ + { 0x92, 0xe5, 0x0c, 0x0c, 0xdd, 0x3b, 0xdb, 0xd5 } \ +} +enum ProcessInputFlag +{ + ProcessInputFlag_None = 0, + ProcessInputFlag_EndOfFile = 1 +}; +/* End of enum ProcessInputFlag Declaration */ + + +/* Start of enum ProcessOutputFlag Declaration */ +#define PROCESSOUTPUTFLAG_IID_STR "9979e85a-52bb-40b7-870c-57115e27e0f1" +#define PROCESSOUTPUTFLAG_IID { \ + 0x9979e85a, 0x52bb, 0x40b7, \ + { 0x87, 0x0c, 0x57, 0x11, 0x5e, 0x27, 0xe0, 0xf1 } \ +} +enum ProcessOutputFlag +{ + ProcessOutputFlag_None = 0, + ProcessOutputFlag_StdErr = 1 +}; +/* End of enum ProcessOutputFlag Declaration */ + + +/* Start of enum ProcessWaitForFlag Declaration */ +#define PROCESSWAITFORFLAG_IID_STR "23b550c7-78e1-437e-98f0-65fd9757bcd2" +#define PROCESSWAITFORFLAG_IID { \ + 0x23b550c7, 0x78e1, 0x437e, \ + { 0x98, 0xf0, 0x65, 0xfd, 0x97, 0x57, 0xbc, 0xd2 } \ +} +enum ProcessWaitForFlag +{ + ProcessWaitForFlag_None = 0, + ProcessWaitForFlag_Start = 1, + ProcessWaitForFlag_Terminate = 2, + ProcessWaitForFlag_StdIn = 4, + ProcessWaitForFlag_StdOut = 8, + ProcessWaitForFlag_StdErr = 16 +}; +/* End of enum ProcessWaitForFlag Declaration */ + + +/* Start of enum ProcessWaitResult Declaration */ +#define PROCESSWAITRESULT_IID_STR "40719cbe-f192-4fe9-a231-6697b3c8e2b4" +#define PROCESSWAITRESULT_IID { \ + 0x40719cbe, 0xf192, 0x4fe9, \ + { 0xa2, 0x31, 0x66, 0x97, 0xb3, 0xc8, 0xe2, 0xb4 } \ +} +enum ProcessWaitResult +{ + ProcessWaitResult_None = 0, + ProcessWaitResult_Start = 1, + ProcessWaitResult_Terminate = 2, + ProcessWaitResult_Status = 3, + ProcessWaitResult_Error = 4, + ProcessWaitResult_Timeout = 5, + ProcessWaitResult_StdIn = 6, + ProcessWaitResult_StdOut = 7, + ProcessWaitResult_StdErr = 8, + ProcessWaitResult_WaitFlagNotSupported = 9 +}; +/* End of enum ProcessWaitResult Declaration */ + + +/* Start of enum CopyFileFlag Declaration */ +#define COPYFILEFLAG_IID_STR "23f79fdf-738a-493d-b80b-42d607c9b916" +#define COPYFILEFLAG_IID { \ + 0x23f79fdf, 0x738a, 0x493d, \ + { 0xb8, 0x0b, 0x42, 0xd6, 0x07, 0xc9, 0xb9, 0x16 } \ +} +enum CopyFileFlag +{ + CopyFileFlag_None = 0, + CopyFileFlag_Recursive = 1, + CopyFileFlag_Update = 2, + CopyFileFlag_FollowLinks = 4 +}; +/* End of enum CopyFileFlag Declaration */ + + +/* Start of enum DirectoryCreateFlag Declaration */ +#define DIRECTORYCREATEFLAG_IID_STR "bd721b0e-ced5-4f79-b368-249897c32a36" +#define DIRECTORYCREATEFLAG_IID { \ + 0xbd721b0e, 0xced5, 0x4f79, \ + { 0xb3, 0x68, 0x24, 0x98, 0x97, 0xc3, 0x2a, 0x36 } \ +} +enum DirectoryCreateFlag +{ + DirectoryCreateFlag_None = 0, + DirectoryCreateFlag_Parents = 1 +}; +/* End of enum DirectoryCreateFlag Declaration */ + + +/* Start of enum DirectoryRemoveRecFlag Declaration */ +#define DIRECTORYREMOVERECFLAG_IID_STR "455aabf0-7692-48f6-9061-f21579b65769" +#define DIRECTORYREMOVERECFLAG_IID { \ + 0x455aabf0, 0x7692, 0x48f6, \ + { 0x90, 0x61, 0xf2, 0x15, 0x79, 0xb6, 0x57, 0x69 } \ +} +enum DirectoryRemoveRecFlag +{ + DirectoryRemoveRecFlag_None = 0, + DirectoryRemoveRecFlag_ContentAndDir = 1, + DirectoryRemoveRecFlag_ContentOnly = 2 +}; +/* End of enum DirectoryRemoveRecFlag Declaration */ + + +/* Start of enum PathRenameFlag Declaration */ +#define PATHRENAMEFLAG_IID_STR "f3baa09f-c758-453d-b91c-c7787d76351d" +#define PATHRENAMEFLAG_IID { \ + 0xf3baa09f, 0xc758, 0x453d, \ + { 0xb9, 0x1c, 0xc7, 0x78, 0x7d, 0x76, 0x35, 0x1d } \ +} +enum PathRenameFlag +{ + PathRenameFlag_None = 0, + PathRenameFlag_NoReplace = 1, + PathRenameFlag_Replace = 2, + PathRenameFlag_NoSymlinks = 4 +}; +/* End of enum PathRenameFlag Declaration */ + + +/* Start of enum ProcessCreateFlag Declaration */ +#define PROCESSCREATEFLAG_IID_STR "35192799-bfde-405d-9bea-c735ab9998e4" +#define PROCESSCREATEFLAG_IID { \ + 0x35192799, 0xbfde, 0x405d, \ + { 0x9b, 0xea, 0xc7, 0x35, 0xab, 0x99, 0x98, 0xe4 } \ +} +enum ProcessCreateFlag +{ + ProcessCreateFlag_None = 0, + ProcessCreateFlag_WaitForProcessStartOnly = 1, + ProcessCreateFlag_IgnoreOrphanedProcesses = 2, + ProcessCreateFlag_Hidden = 4, + ProcessCreateFlag_NoProfile = 8, + ProcessCreateFlag_WaitForStdOut = 16, + ProcessCreateFlag_WaitForStdErr = 32, + ProcessCreateFlag_ExpandArguments = 64 +}; +/* End of enum ProcessCreateFlag Declaration */ + + +/* Start of enum ProcessPriority Declaration */ +#define PROCESSPRIORITY_IID_STR "ee8cac50-e232-49fe-806b-d1214d9c2e49" +#define PROCESSPRIORITY_IID { \ + 0xee8cac50, 0xe232, 0x49fe, \ + { 0x80, 0x6b, 0xd1, 0x21, 0x4d, 0x9c, 0x2e, 0x49 } \ +} +enum ProcessPriority +{ + ProcessPriority_Invalid = 0, + ProcessPriority_Default = 1 +}; +/* End of enum ProcessPriority Declaration */ + + +/* Start of enum SymlinkType Declaration */ +#define SYMLINKTYPE_IID_STR "37794668-f8f1-4714-98a5-6f8fa2ed0118" +#define SYMLINKTYPE_IID { \ + 0x37794668, 0xf8f1, 0x4714, \ + { 0x98, 0xa5, 0x6f, 0x8f, 0xa2, 0xed, 0x01, 0x18 } \ +} +enum SymlinkType +{ + SymlinkType_Unknown = 0, + SymlinkType_Directory = 1, + SymlinkType_File = 2 +}; +/* End of enum SymlinkType Declaration */ + + +/* Start of enum SymlinkReadFlag Declaration */ +#define SYMLINKREADFLAG_IID_STR "b7fe2b9d-790e-4b25-8adf-1ca33026931f" +#define SYMLINKREADFLAG_IID { \ + 0xb7fe2b9d, 0x790e, 0x4b25, \ + { 0x8a, 0xdf, 0x1c, 0xa3, 0x30, 0x26, 0x93, 0x1f } \ +} +enum SymlinkReadFlag +{ + SymlinkReadFlag_None = 0, + SymlinkReadFlag_NoSymlinks = 1 +}; +/* End of enum SymlinkReadFlag Declaration */ + + +/* Start of enum ProcessStatus Declaration */ +#define PROCESSSTATUS_IID_STR "4d52368f-5b48-4bfe-b486-acf89139b52f" +#define PROCESSSTATUS_IID { \ + 0x4d52368f, 0x5b48, 0x4bfe, \ + { 0xb4, 0x86, 0xac, 0xf8, 0x91, 0x39, 0xb5, 0x2f } \ +} +enum ProcessStatus +{ + ProcessStatus_Undefined = 0, + ProcessStatus_Starting = 10, + ProcessStatus_Started = 100, + ProcessStatus_Paused = 110, + ProcessStatus_Terminating = 480, + ProcessStatus_TerminatedNormally = 500, + ProcessStatus_TerminatedSignal = 510, + ProcessStatus_TerminatedAbnormally = 511, + ProcessStatus_TimedOutKilled = 512, + ProcessStatus_TimedOutAbnormally = 513, + ProcessStatus_Down = 600, + ProcessStatus_Error = 800 +}; +/* End of enum ProcessStatus Declaration */ + + +/* Start of enum FsObjType Declaration */ +#define FSOBJTYPE_IID_STR "a1ed437c-b3c3-4ca2-b19c-4239d658d5e8" +#define FSOBJTYPE_IID { \ + 0xa1ed437c, 0xb3c3, 0x4ca2, \ + { 0xb1, 0x9c, 0x42, 0x39, 0xd6, 0x58, 0xd5, 0xe8 } \ +} +enum FsObjType +{ + FsObjType_Undefined = 0, + FsObjType_FIFO = 1, + FsObjType_DevChar = 10, + FsObjType_DevBlock = 11, + FsObjType_Directory = 50, + FsObjType_File = 80, + FsObjType_Symlink = 100, + FsObjType_Socket = 200, + FsObjType_Whiteout = 400 +}; +/* End of enum FsObjType Declaration */ + + +/* Start of enum DragAndDropAction Declaration */ +#define DRAGANDDROPACTION_IID_STR "47f3b162-c107-4fcd-bfa7-54b8135c441e" +#define DRAGANDDROPACTION_IID { \ + 0x47f3b162, 0xc107, 0x4fcd, \ + { 0xbf, 0xa7, 0x54, 0xb8, 0x13, 0x5c, 0x44, 0x1e } \ +} +enum DragAndDropAction +{ + DragAndDropAction_Ignore = 0, + DragAndDropAction_Copy = 1, + DragAndDropAction_Move = 2, + DragAndDropAction_Link = 3 +}; +/* End of enum DragAndDropAction Declaration */ + + +/* Start of enum DirectoryOpenFlag Declaration */ +#define DIRECTORYOPENFLAG_IID_STR "5138837a-8fd2-4194-a1b0-08f7bc3949d0" +#define DIRECTORYOPENFLAG_IID { \ + 0x5138837a, 0x8fd2, 0x4194, \ + { 0xa1, 0xb0, 0x08, 0xf7, 0xbc, 0x39, 0x49, 0xd0 } \ +} +enum DirectoryOpenFlag +{ + DirectoryOpenFlag_None = 0, + DirectoryOpenFlag_NoSymlinks = 1 +}; +/* End of enum DirectoryOpenFlag Declaration */ + + +/* Start of enum MediumState Declaration */ +#define MEDIUMSTATE_IID_STR "ef41e980-e012-43cd-9dea-479d4ef14d13" +#define MEDIUMSTATE_IID { \ + 0xef41e980, 0xe012, 0x43cd, \ + { 0x9d, 0xea, 0x47, 0x9d, 0x4e, 0xf1, 0x4d, 0x13 } \ +} +enum MediumState +{ + MediumState_NotCreated = 0, + MediumState_Created = 1, + MediumState_LockedRead = 2, + MediumState_LockedWrite = 3, + MediumState_Inaccessible = 4, + MediumState_Creating = 5, + MediumState_Deleting = 6 +}; +/* End of enum MediumState Declaration */ + + +/* Start of enum MediumType Declaration */ +#define MEDIUMTYPE_IID_STR "fe663fb5-c244-4e1b-9d81-c628b417dd04" +#define MEDIUMTYPE_IID { \ + 0xfe663fb5, 0xc244, 0x4e1b, \ + { 0x9d, 0x81, 0xc6, 0x28, 0xb4, 0x17, 0xdd, 0x04 } \ +} +enum MediumType +{ + MediumType_Normal = 0, + MediumType_Immutable = 1, + MediumType_Writethrough = 2, + MediumType_Shareable = 3, + MediumType_Readonly = 4, + MediumType_MultiAttach = 5 +}; +/* End of enum MediumType Declaration */ + + +/* Start of enum MediumVariant Declaration */ +#define MEDIUMVARIANT_IID_STR "80685b6b-e42f-497d-8271-e77bf3c61ada" +#define MEDIUMVARIANT_IID { \ + 0x80685b6b, 0xe42f, 0x497d, \ + { 0x82, 0x71, 0xe7, 0x7b, 0xf3, 0xc6, 0x1a, 0xda } \ +} +enum MediumVariant +{ + MediumVariant_Standard = 0, + MediumVariant_VmdkSplit2G = 0x01, + MediumVariant_VmdkRawDisk = 0x02, + MediumVariant_VmdkStreamOptimized = 0x04, + MediumVariant_VmdkESX = 0x08, + MediumVariant_Fixed = 0x10000, + MediumVariant_Diff = 0x20000, + MediumVariant_NoCreateDir = 0x40000000 +}; +/* End of enum MediumVariant Declaration */ + + +/* Start of enum DataType Declaration */ +#define DATATYPE_IID_STR "d90ea51e-a3f1-4a01-beb1-c1723c0d3ba7" +#define DATATYPE_IID { \ + 0xd90ea51e, 0xa3f1, 0x4a01, \ + { 0xbe, 0xb1, 0xc1, 0x72, 0x3c, 0x0d, 0x3b, 0xa7 } \ +} +enum DataType +{ + DataType_Int32 = 0, + DataType_Int8 = 1, + DataType_String = 2 +}; +/* End of enum DataType Declaration */ + + +/* Start of enum DataFlags Declaration */ +#define DATAFLAGS_IID_STR "86884dcf-1d6b-4f1b-b4bf-f5aa44959d60" +#define DATAFLAGS_IID { \ + 0x86884dcf, 0x1d6b, 0x4f1b, \ + { 0xb4, 0xbf, 0xf5, 0xaa, 0x44, 0x95, 0x9d, 0x60 } \ +} +enum DataFlags +{ + DataFlags_None = 0x00, + DataFlags_Mandatory = 0x01, + DataFlags_Expert = 0x02, + DataFlags_Array = 0x04, + DataFlags_FlagMask = 0x07 +}; +/* End of enum DataFlags Declaration */ + + +/* Start of enum MediumFormatCapabilities Declaration */ +#define MEDIUMFORMATCAPABILITIES_IID_STR "7342ba79-7ce0-4d94-8f86-5ed5a185d9bd" +#define MEDIUMFORMATCAPABILITIES_IID { \ + 0x7342ba79, 0x7ce0, 0x4d94, \ + { 0x8f, 0x86, 0x5e, 0xd5, 0xa1, 0x85, 0xd9, 0xbd } \ +} +enum MediumFormatCapabilities +{ + MediumFormatCapabilities_Uuid = 0x01, + MediumFormatCapabilities_CreateFixed = 0x02, + MediumFormatCapabilities_CreateDynamic = 0x04, + MediumFormatCapabilities_CreateSplit2G = 0x08, + MediumFormatCapabilities_Differencing = 0x10, + MediumFormatCapabilities_Asynchronous = 0x20, + MediumFormatCapabilities_File = 0x40, + MediumFormatCapabilities_Properties = 0x80, + MediumFormatCapabilities_TcpNetworking = 0x100, + MediumFormatCapabilities_VFS = 0x200, + MediumFormatCapabilities_CapabilityMask = 0x3FF +}; +/* End of enum MediumFormatCapabilities Declaration */ + + +/* Start of enum MouseButtonState Declaration */ +#define MOUSEBUTTONSTATE_IID_STR "9ee094b8-b28a-4d56-a166-973cb588d7f8" +#define MOUSEBUTTONSTATE_IID { \ + 0x9ee094b8, 0xb28a, 0x4d56, \ + { 0xa1, 0x66, 0x97, 0x3c, 0xb5, 0x88, 0xd7, 0xf8 } \ +} +enum MouseButtonState +{ + MouseButtonState_LeftButton = 0x01, + MouseButtonState_RightButton = 0x02, + MouseButtonState_MiddleButton = 0x04, + MouseButtonState_WheelUp = 0x08, + MouseButtonState_WheelDown = 0x10, + MouseButtonState_XButton1 = 0x20, + MouseButtonState_XButton2 = 0x40, + MouseButtonState_MouseStateMask = 0x7F +}; +/* End of enum MouseButtonState Declaration */ + + +/* Start of enum FramebufferPixelFormat Declaration */ +#define FRAMEBUFFERPIXELFORMAT_IID_STR "7acfd5ed-29e3-45e3-8136-73c9224f3d2d" +#define FRAMEBUFFERPIXELFORMAT_IID { \ + 0x7acfd5ed, 0x29e3, 0x45e3, \ + { 0x81, 0x36, 0x73, 0xc9, 0x22, 0x4f, 0x3d, 0x2d } \ +} +enum FramebufferPixelFormat +{ + FramebufferPixelFormat_Opaque = 0, + FramebufferPixelFormat_FOURCC_RGB = 0x32424752 +}; +/* End of enum FramebufferPixelFormat Declaration */ + + +/* Start of enum NetworkAttachmentType Declaration */ +#define NETWORKATTACHMENTTYPE_IID_STR "2ac4bc71-6b82-417a-acd1-f7426d2570d6" +#define NETWORKATTACHMENTTYPE_IID { \ + 0x2ac4bc71, 0x6b82, 0x417a, \ + { 0xac, 0xd1, 0xf7, 0x42, 0x6d, 0x25, 0x70, 0xd6 } \ +} +enum NetworkAttachmentType +{ + NetworkAttachmentType_Null = 0, + NetworkAttachmentType_NAT = 1, + NetworkAttachmentType_Bridged = 2, + NetworkAttachmentType_Internal = 3, + NetworkAttachmentType_HostOnly = 4, + NetworkAttachmentType_Generic = 5 +}; +/* End of enum NetworkAttachmentType Declaration */ + + +/* Start of enum NetworkAdapterType Declaration */ +#define NETWORKADAPTERTYPE_IID_STR "3c2281e4-d952-4e87-8c7d-24379cb6a81c" +#define NETWORKADAPTERTYPE_IID { \ + 0x3c2281e4, 0xd952, 0x4e87, \ + { 0x8c, 0x7d, 0x24, 0x37, 0x9c, 0xb6, 0xa8, 0x1c } \ +} +enum NetworkAdapterType +{ + NetworkAdapterType_Null = 0, + NetworkAdapterType_Am79C970A = 1, + NetworkAdapterType_Am79C973 = 2, + NetworkAdapterType_I82540EM = 3, + NetworkAdapterType_I82543GC = 4, + NetworkAdapterType_I82545EM = 5, + NetworkAdapterType_Virtio = 6 +}; +/* End of enum NetworkAdapterType Declaration */ + + +/* Start of enum NetworkAdapterPromiscModePolicy Declaration */ +#define NETWORKADAPTERPROMISCMODEPOLICY_IID_STR "c963768a-376f-4c85-8d84-d8ced4b7269e" +#define NETWORKADAPTERPROMISCMODEPOLICY_IID { \ + 0xc963768a, 0x376f, 0x4c85, \ + { 0x8d, 0x84, 0xd8, 0xce, 0xd4, 0xb7, 0x26, 0x9e } \ +} +enum NetworkAdapterPromiscModePolicy +{ + NetworkAdapterPromiscModePolicy_Deny = 1, + NetworkAdapterPromiscModePolicy_AllowNetwork = 2, + NetworkAdapterPromiscModePolicy_AllowAll = 3 +}; +/* End of enum NetworkAdapterPromiscModePolicy Declaration */ + + +/* Start of enum PortMode Declaration */ +#define PORTMODE_IID_STR "533b5fe3-0185-4197-86a7-17e37dd39d76" +#define PORTMODE_IID { \ + 0x533b5fe3, 0x0185, 0x4197, \ + { 0x86, 0xa7, 0x17, 0xe3, 0x7d, 0xd3, 0x9d, 0x76 } \ +} +enum PortMode +{ + PortMode_Disconnected = 0, + PortMode_HostPipe = 1, + PortMode_HostDevice = 2, + PortMode_RawFile = 3 +}; +/* End of enum PortMode Declaration */ + + +/* Start of enum USBDeviceState Declaration */ +#define USBDEVICESTATE_IID_STR "b99a2e65-67fb-4882-82fd-f3e5e8193ab4" +#define USBDEVICESTATE_IID { \ + 0xb99a2e65, 0x67fb, 0x4882, \ + { 0x82, 0xfd, 0xf3, 0xe5, 0xe8, 0x19, 0x3a, 0xb4 } \ +} +enum USBDeviceState +{ + USBDeviceState_NotSupported = 0, + USBDeviceState_Unavailable = 1, + USBDeviceState_Busy = 2, + USBDeviceState_Available = 3, + USBDeviceState_Held = 4, + USBDeviceState_Captured = 5 +}; +/* End of enum USBDeviceState Declaration */ + + +/* Start of enum USBDeviceFilterAction Declaration */ +#define USBDEVICEFILTERACTION_IID_STR "cbc30a49-2f4e-43b5-9da6-121320475933" +#define USBDEVICEFILTERACTION_IID { \ + 0xcbc30a49, 0x2f4e, 0x43b5, \ + { 0x9d, 0xa6, 0x12, 0x13, 0x20, 0x47, 0x59, 0x33 } \ +} +enum USBDeviceFilterAction +{ + USBDeviceFilterAction_Null = 0, + USBDeviceFilterAction_Ignore = 1, + USBDeviceFilterAction_Hold = 2 +}; +/* End of enum USBDeviceFilterAction Declaration */ + + +/* Start of enum AudioDriverType Declaration */ +#define AUDIODRIVERTYPE_IID_STR "4bcc3d73-c2fe-40db-b72f-0c2ca9d68496" +#define AUDIODRIVERTYPE_IID { \ + 0x4bcc3d73, 0xc2fe, 0x40db, \ + { 0xb7, 0x2f, 0x0c, 0x2c, 0xa9, 0xd6, 0x84, 0x96 } \ +} +enum AudioDriverType +{ + AudioDriverType_Null = 0, + AudioDriverType_WinMM = 1, + AudioDriverType_OSS = 2, + AudioDriverType_ALSA = 3, + AudioDriverType_DirectSound = 4, + AudioDriverType_CoreAudio = 5, + AudioDriverType_MMPM = 6, + AudioDriverType_Pulse = 7, + AudioDriverType_SolAudio = 8 +}; +/* End of enum AudioDriverType Declaration */ + + +/* Start of enum AudioControllerType Declaration */ +#define AUDIOCONTROLLERTYPE_IID_STR "7afd395c-42c3-444e-8788-3ce80292f36c" +#define AUDIOCONTROLLERTYPE_IID { \ + 0x7afd395c, 0x42c3, 0x444e, \ + { 0x87, 0x88, 0x3c, 0xe8, 0x02, 0x92, 0xf3, 0x6c } \ +} +enum AudioControllerType +{ + AudioControllerType_AC97 = 0, + AudioControllerType_SB16 = 1, + AudioControllerType_HDA = 2 +}; +/* End of enum AudioControllerType Declaration */ + + +/* Start of enum AuthType Declaration */ +#define AUTHTYPE_IID_STR "7eef6ef6-98c2-4dc2-ab35-10d2b292028d" +#define AUTHTYPE_IID { \ + 0x7eef6ef6, 0x98c2, 0x4dc2, \ + { 0xab, 0x35, 0x10, 0xd2, 0xb2, 0x92, 0x02, 0x8d } \ +} +enum AuthType +{ + AuthType_Null = 0, + AuthType_External = 1, + AuthType_Guest = 2 +}; +/* End of enum AuthType Declaration */ + + +/* Start of enum Reason Declaration */ +#define REASON_IID_STR "e7e8e097-299d-4e98-8bbc-c31c2d47d0cc" +#define REASON_IID { \ + 0xe7e8e097, 0x299d, 0x4e98, \ + { 0x8b, 0xbc, 0xc3, 0x1c, 0x2d, 0x47, 0xd0, 0xcc } \ +} +enum Reason +{ + Reason_Unspecified = 0, + Reason_HostSuspend = 1, + Reason_HostResume = 2, + Reason_HostBatteryLow = 3 +}; +/* End of enum Reason Declaration */ + + +/* Start of enum StorageBus Declaration */ +#define STORAGEBUS_IID_STR "eee67ab3-668d-4ef5-91e0-7025fe4a0d7a" +#define STORAGEBUS_IID { \ + 0xeee67ab3, 0x668d, 0x4ef5, \ + { 0x91, 0xe0, 0x70, 0x25, 0xfe, 0x4a, 0x0d, 0x7a } \ +} +enum StorageBus +{ + StorageBus_Null = 0, + StorageBus_IDE = 1, + StorageBus_SATA = 2, + StorageBus_SCSI = 3, + StorageBus_Floppy = 4, + StorageBus_SAS = 5 +}; +/* End of enum StorageBus Declaration */ + + +/* Start of enum StorageControllerType Declaration */ +#define STORAGECONTROLLERTYPE_IID_STR "8a412b8a-f43e-4456-bd37-b474f0879a58" +#define STORAGECONTROLLERTYPE_IID { \ + 0x8a412b8a, 0xf43e, 0x4456, \ + { 0xbd, 0x37, 0xb4, 0x74, 0xf0, 0x87, 0x9a, 0x58 } \ +} +enum StorageControllerType +{ + StorageControllerType_Null = 0, + StorageControllerType_LsiLogic = 1, + StorageControllerType_BusLogic = 2, + StorageControllerType_IntelAhci = 3, + StorageControllerType_PIIX3 = 4, + StorageControllerType_PIIX4 = 5, + StorageControllerType_ICH6 = 6, + StorageControllerType_I82078 = 7, + StorageControllerType_LsiLogicSas = 8 +}; +/* End of enum StorageControllerType Declaration */ + + +/* Start of enum ChipsetType Declaration */ +#define CHIPSETTYPE_IID_STR "8b4096a8-a7c3-4d3b-bbb1-05a0a51ec394" +#define CHIPSETTYPE_IID { \ + 0x8b4096a8, 0xa7c3, 0x4d3b, \ + { 0xbb, 0xb1, 0x05, 0xa0, 0xa5, 0x1e, 0xc3, 0x94 } \ +} +enum ChipsetType +{ + ChipsetType_Null = 0, + ChipsetType_PIIX3 = 1, + ChipsetType_ICH9 = 2 +}; +/* End of enum ChipsetType Declaration */ + + +/* Start of enum NATAliasMode Declaration */ +#define NATALIASMODE_IID_STR "67772168-50d9-11df-9669-7fb714ee4fa1" +#define NATALIASMODE_IID { \ + 0x67772168, 0x50d9, 0x11df, \ + { 0x96, 0x69, 0x7f, 0xb7, 0x14, 0xee, 0x4f, 0xa1 } \ +} +enum NATAliasMode +{ + NATAliasMode_AliasLog = 0x1, + NATAliasMode_AliasProxyOnly = 0x02, + NATAliasMode_AliasUseSamePorts = 0x04 +}; +/* End of enum NATAliasMode Declaration */ + + +/* Start of enum NATProtocol Declaration */ +#define NATPROTOCOL_IID_STR "e90164be-eb03-11de-94af-fff9b1c1b19f" +#define NATPROTOCOL_IID { \ + 0xe90164be, 0xeb03, 0x11de, \ + { 0x94, 0xaf, 0xff, 0xf9, 0xb1, 0xc1, 0xb1, 0x9f } \ +} +enum NATProtocol +{ + NATProtocol_UDP = 0, + NATProtocol_TCP = 1 +}; +/* End of enum NATProtocol Declaration */ + + +/* Start of enum BandwidthGroupType Declaration */ +#define BANDWIDTHGROUPTYPE_IID_STR "1d92b67d-dc69-4be9-ad4c-93a01e1e0c8e" +#define BANDWIDTHGROUPTYPE_IID { \ + 0x1d92b67d, 0xdc69, 0x4be9, \ + { 0xad, 0x4c, 0x93, 0xa0, 0x1e, 0x1e, 0x0c, 0x8e } \ +} +enum BandwidthGroupType +{ + BandwidthGroupType_Null = 0, + BandwidthGroupType_Disk = 1, + BandwidthGroupType_Network = 2 +}; +/* End of enum BandwidthGroupType Declaration */ + + +/* Start of enum VBoxEventType Declaration */ +#define VBOXEVENTTYPE_IID_STR "0d67e79e-b7b1-4919-aab3-b36866075515" +#define VBOXEVENTTYPE_IID { \ + 0x0d67e79e, 0xb7b1, 0x4919, \ + { 0xaa, 0xb3, 0xb3, 0x68, 0x66, 0x07, 0x55, 0x15 } \ +} +enum VBoxEventType +{ + VBoxEventType_Invalid = 0, + VBoxEventType_Any = 1, + VBoxEventType_Vetoable = 2, + VBoxEventType_MachineEvent = 3, + VBoxEventType_SnapshotEvent = 4, + VBoxEventType_InputEvent = 5, + VBoxEventType_LastWildcard = 31, + VBoxEventType_OnMachineStateChanged = 32, + VBoxEventType_OnMachineDataChanged = 33, + VBoxEventType_OnExtraDataChanged = 34, + VBoxEventType_OnExtraDataCanChange = 35, + VBoxEventType_OnMediumRegistered = 36, + VBoxEventType_OnMachineRegistered = 37, + VBoxEventType_OnSessionStateChanged = 38, + VBoxEventType_OnSnapshotTaken = 39, + VBoxEventType_OnSnapshotDeleted = 40, + VBoxEventType_OnSnapshotChanged = 41, + VBoxEventType_OnGuestPropertyChanged = 42, + VBoxEventType_OnMousePointerShapeChanged = 43, + VBoxEventType_OnMouseCapabilityChanged = 44, + VBoxEventType_OnKeyboardLedsChanged = 45, + VBoxEventType_OnStateChanged = 46, + VBoxEventType_OnAdditionsStateChanged = 47, + VBoxEventType_OnNetworkAdapterChanged = 48, + VBoxEventType_OnSerialPortChanged = 49, + VBoxEventType_OnParallelPortChanged = 50, + VBoxEventType_OnStorageControllerChanged = 51, + VBoxEventType_OnMediumChanged = 52, + VBoxEventType_OnVRDEServerChanged = 53, + VBoxEventType_OnUSBControllerChanged = 54, + VBoxEventType_OnUSBDeviceStateChanged = 55, + VBoxEventType_OnSharedFolderChanged = 56, + VBoxEventType_OnRuntimeError = 57, + VBoxEventType_OnCanShowWindow = 58, + VBoxEventType_OnShowWindow = 59, + VBoxEventType_OnCPUChanged = 60, + VBoxEventType_OnVRDEServerInfoChanged = 61, + VBoxEventType_OnEventSourceChanged = 62, + VBoxEventType_OnCPUExecutionCapChanged = 63, + VBoxEventType_OnGuestKeyboard = 64, + VBoxEventType_OnGuestMouse = 65, + VBoxEventType_OnNATRedirect = 66, + VBoxEventType_OnHostPCIDevicePlug = 67, + VBoxEventType_OnVBoxSVCAvailabilityChanged = 68, + VBoxEventType_OnBandwidthGroupChanged = 69, + VBoxEventType_OnGuestMonitorChanged = 70, + VBoxEventType_OnStorageDeviceChanged = 71, + VBoxEventType_OnClipboardModeChanged = 72, + VBoxEventType_OnDragAndDropModeChanged = 73, + VBoxEventType_Last = 74 +}; +/* End of enum VBoxEventType Declaration */ + + +/* Start of enum GuestMonitorChangedEventType Declaration */ +#define GUESTMONITORCHANGEDEVENTTYPE_IID_STR "ef172985-7e36-4297-95be-e46396968d66" +#define GUESTMONITORCHANGEDEVENTTYPE_IID { \ + 0xef172985, 0x7e36, 0x4297, \ + { 0x95, 0xbe, 0xe4, 0x63, 0x96, 0x96, 0x8d, 0x66 } \ +} +enum GuestMonitorChangedEventType +{ + GuestMonitorChangedEventType_Enabled = 0, + GuestMonitorChangedEventType_Disabled = 1, + GuestMonitorChangedEventType_NewOrigin = 2 +}; +/* End of enum GuestMonitorChangedEventType Declaration */ + + +/* Start of struct IVirtualBoxErrorInfo Declaration */ +#define IVIRTUALBOXERRORINFO_IID_STR "f91e6e91-49e1-4fd2-b21e-269003350d06" +#define IVIRTUALBOXERRORINFO_IID { \ + 0xf91e6e91, 0x49e1, 0x4fd2, \ + { 0xb2, 0x1e, 0x26, 0x90, 0x03, 0x35, 0x0d, 0x06 } \ +} +struct IVirtualBoxErrorInfo_vtbl +{ + struct nsIException_vtbl nsiexception; + + nsresult (*GetResultCode)(IVirtualBoxErrorInfo *pThis, PRInt32 *resultCode); + + nsresult (*GetInterfaceID)(IVirtualBoxErrorInfo *pThis, PRUnichar * *interfaceID); + + nsresult (*GetComponent)(IVirtualBoxErrorInfo *pThis, PRUnichar * *component); + + nsresult (*GetText)(IVirtualBoxErrorInfo *pThis, PRUnichar * *text); + + nsresult (*GetNext)(IVirtualBoxErrorInfo *pThis, IVirtualBoxErrorInfo * *next); + +}; + +struct IVirtualBoxErrorInfo +{ + struct IVirtualBoxErrorInfo_vtbl *vtbl; +}; +/* End of struct IVirtualBoxErrorInfo Declaration */ + + +/* Start of struct IDHCPServer Declaration */ +#define IDHCPSERVER_IID_STR "6cfe387c-74fb-4ca7-bff6-973bec8af7a3" +#define IDHCPSERVER_IID { \ + 0x6cfe387c, 0x74fb, 0x4ca7, \ + { 0xbf, 0xf6, 0x97, 0x3b, 0xec, 0x8a, 0xf7, 0xa3 } \ +} +struct IDHCPServer_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetEnabled)(IDHCPServer *pThis, PRBool *enabled); + nsresult (*SetEnabled)(IDHCPServer *pThis, PRBool enabled); + + nsresult (*GetIPAddress)(IDHCPServer *pThis, PRUnichar * *IPAddress); + + nsresult (*GetNetworkMask)(IDHCPServer *pThis, PRUnichar * *networkMask); + + nsresult (*GetNetworkName)(IDHCPServer *pThis, PRUnichar * *networkName); + + nsresult (*GetLowerIP)(IDHCPServer *pThis, PRUnichar * *lowerIP); + + nsresult (*GetUpperIP)(IDHCPServer *pThis, PRUnichar * *upperIP); + + nsresult (*SetConfiguration)( + IDHCPServer *pThis, + PRUnichar * IPAddress, + PRUnichar * networkMask, + PRUnichar * FromIPAddress, + PRUnichar * ToIPAddress + ); + + nsresult (*Start)( + IDHCPServer *pThis, + PRUnichar * networkName, + PRUnichar * trunkName, + PRUnichar * trunkType + ); + + nsresult (*Stop)(IDHCPServer *pThis ); + +}; + +struct IDHCPServer +{ + struct IDHCPServer_vtbl *vtbl; +}; +/* End of struct IDHCPServer Declaration */ + + +/* Start of struct IVirtualBox Declaration */ +#define IVIRTUALBOX_IID_STR "3b2f08eb-b810-4715-bee0-bb06b9880ad2" +#define IVIRTUALBOX_IID { \ + 0x3b2f08eb, 0xb810, 0x4715, \ + { 0xbe, 0xe0, 0xbb, 0x06, 0xb9, 0x88, 0x0a, 0xd2 } \ +} +struct IVirtualBox_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetVersion)(IVirtualBox *pThis, PRUnichar * *version); + + nsresult (*GetVersionNormalized)(IVirtualBox *pThis, PRUnichar * *versionNormalized); + + nsresult (*GetRevision)(IVirtualBox *pThis, PRUint32 *revision); + + nsresult (*GetPackageType)(IVirtualBox *pThis, PRUnichar * *packageType); + + nsresult (*GetAPIVersion)(IVirtualBox *pThis, PRUnichar * *APIVersion); + + nsresult (*GetHomeFolder)(IVirtualBox *pThis, PRUnichar * *homeFolder); + + nsresult (*GetSettingsFilePath)(IVirtualBox *pThis, PRUnichar * *settingsFilePath); + + nsresult (*GetHost)(IVirtualBox *pThis, IHost * *host); + + nsresult (*GetSystemProperties)(IVirtualBox *pThis, ISystemProperties * *systemProperties); + + nsresult (*GetMachines)(IVirtualBox *pThis, PRUint32 *machinesSize, IMachine * **machines); + + nsresult (*GetMachineGroups)(IVirtualBox *pThis, PRUint32 *machineGroupsSize, PRUnichar * **machineGroups); + + nsresult (*GetHardDisks)(IVirtualBox *pThis, PRUint32 *hardDisksSize, IMedium * **hardDisks); + + nsresult (*GetDVDImages)(IVirtualBox *pThis, PRUint32 *DVDImagesSize, IMedium * **DVDImages); + + nsresult (*GetFloppyImages)(IVirtualBox *pThis, PRUint32 *floppyImagesSize, IMedium * **floppyImages); + + nsresult (*GetProgressOperations)(IVirtualBox *pThis, PRUint32 *progressOperationsSize, IProgress * **progressOperations); + + nsresult (*GetGuestOSTypes)(IVirtualBox *pThis, PRUint32 *guestOSTypesSize, IGuestOSType * **guestOSTypes); + + nsresult (*GetSharedFolders)(IVirtualBox *pThis, PRUint32 *sharedFoldersSize, ISharedFolder * **sharedFolders); + + nsresult (*GetPerformanceCollector)(IVirtualBox *pThis, IPerformanceCollector * *performanceCollector); + + nsresult (*GetDHCPServers)(IVirtualBox *pThis, PRUint32 *DHCPServersSize, IDHCPServer * **DHCPServers); + + nsresult (*GetEventSource)(IVirtualBox *pThis, IEventSource * *eventSource); + + nsresult (*GetExtensionPackManager)(IVirtualBox *pThis, IExtPackManager * *extensionPackManager); + + nsresult (*GetInternalNetworks)(IVirtualBox *pThis, PRUint32 *internalNetworksSize, PRUnichar * **internalNetworks); + + nsresult (*GetGenericNetworkDrivers)(IVirtualBox *pThis, PRUint32 *genericNetworkDriversSize, PRUnichar * **genericNetworkDrivers); + + nsresult (*ComposeMachineFilename)( + IVirtualBox *pThis, + PRUnichar * name, + PRUnichar * group, + PRUnichar * createFlags, + PRUnichar * baseFolder, + PRUnichar * * file + ); + + nsresult (*CreateMachine)( + IVirtualBox *pThis, + PRUnichar * settingsFile, + PRUnichar * name, + PRUint32 groupsSize, + PRUnichar ** groups, + PRUnichar * osTypeId, + PRUnichar * flags, + IMachine * * machine + ); + + nsresult (*OpenMachine)( + IVirtualBox *pThis, + PRUnichar * settingsFile, + IMachine * * machine + ); + + nsresult (*RegisterMachine)( + IVirtualBox *pThis, + IMachine * machine + ); + + nsresult (*FindMachine)( + IVirtualBox *pThis, + PRUnichar * nameOrId, + IMachine * * machine + ); + + nsresult (*GetMachinesByGroups)( + IVirtualBox *pThis, + PRUint32 groupsSize, + PRUnichar ** groups, + PRUint32 *machinesSize, + IMachine *** machines + ); + + nsresult (*GetMachineStates)( + IVirtualBox *pThis, + PRUint32 machinesSize, + IMachine ** machines, + PRUint32 *statesSize, + PRUint32** states + ); + + nsresult (*CreateAppliance)( + IVirtualBox *pThis, + IAppliance * * appliance + ); + + nsresult (*CreateHardDisk)( + IVirtualBox *pThis, + PRUnichar * format, + PRUnichar * location, + IMedium * * medium + ); + + nsresult (*OpenMedium)( + IVirtualBox *pThis, + PRUnichar * location, + PRUint32 deviceType, + PRUint32 accessMode, + PRBool forceNewUuid, + IMedium * * medium + ); + + nsresult (*GetGuestOSType)( + IVirtualBox *pThis, + PRUnichar * id, + IGuestOSType * * type + ); + + nsresult (*CreateSharedFolder)( + IVirtualBox *pThis, + PRUnichar * name, + PRUnichar * hostPath, + PRBool writable, + PRBool automount + ); + + nsresult (*RemoveSharedFolder)( + IVirtualBox *pThis, + PRUnichar * name + ); + + nsresult (*GetExtraDataKeys)( + IVirtualBox *pThis, + PRUint32 *valueSize, + PRUnichar *** value + ); + + nsresult (*GetExtraData)( + IVirtualBox *pThis, + PRUnichar * key, + PRUnichar * * value + ); + + nsresult (*SetExtraData)( + IVirtualBox *pThis, + PRUnichar * key, + PRUnichar * value + ); + + nsresult (*SetSettingsSecret)( + IVirtualBox *pThis, + PRUnichar * password + ); + + nsresult (*CreateDHCPServer)( + IVirtualBox *pThis, + PRUnichar * name, + IDHCPServer * * server + ); + + nsresult (*FindDHCPServerByNetworkName)( + IVirtualBox *pThis, + PRUnichar * name, + IDHCPServer * * server + ); + + nsresult (*RemoveDHCPServer)( + IVirtualBox *pThis, + IDHCPServer * server + ); + + nsresult (*CheckFirmwarePresent)( + IVirtualBox *pThis, + PRUint32 firmwareType, + PRUnichar * version, + PRUnichar * * url, + PRUnichar * * file, + PRBool * result + ); + +}; + +struct IVirtualBox +{ + struct IVirtualBox_vtbl *vtbl; +}; +/* End of struct IVirtualBox Declaration */ + + +/* Start of struct IVFSExplorer Declaration */ +#define IVFSEXPLORER_IID_STR "003d7f92-d38e-487f-b790-8c5e8631cb2f" +#define IVFSEXPLORER_IID { \ + 0x003d7f92, 0xd38e, 0x487f, \ + { 0xb7, 0x90, 0x8c, 0x5e, 0x86, 0x31, 0xcb, 0x2f } \ +} +struct IVFSExplorer_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetPath)(IVFSExplorer *pThis, PRUnichar * *path); + + nsresult (*GetType)(IVFSExplorer *pThis, PRUint32 *type); + + nsresult (*Update)( + IVFSExplorer *pThis, + IProgress * * aProgress + ); + + nsresult (*Cd)( + IVFSExplorer *pThis, + PRUnichar * aDir, + IProgress * * aProgress + ); + + nsresult (*CdUp)( + IVFSExplorer *pThis, + IProgress * * aProgress + ); + + nsresult (*EntryList)( + IVFSExplorer *pThis, + PRUint32 *aNamesSize, + PRUnichar *** aNames, + PRUint32 *aTypesSize, + PRUint32** aTypes, + PRUint32 *aSizesSize, + PRUint32** aSizes, + PRUint32 *aModesSize, + PRUint32** aModes + ); + + nsresult (*Exists)( + IVFSExplorer *pThis, + PRUint32 aNamesSize, + PRUnichar ** aNames, + PRUint32 *aExistsSize, + PRUnichar *** aExists + ); + + nsresult (*Remove)( + IVFSExplorer *pThis, + PRUint32 aNamesSize, + PRUnichar ** aNames, + IProgress * * aProgress + ); + +}; + +struct IVFSExplorer +{ + struct IVFSExplorer_vtbl *vtbl; +}; +/* End of struct IVFSExplorer Declaration */ + + +/* Start of struct IAppliance Declaration */ +#define IAPPLIANCE_IID_STR "3059cf9e-25c7-4f0b-9fa5-3c42e441670b" +#define IAPPLIANCE_IID { \ + 0x3059cf9e, 0x25c7, 0x4f0b, \ + { 0x9f, 0xa5, 0x3c, 0x42, 0xe4, 0x41, 0x67, 0x0b } \ +} +struct IAppliance_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetPath)(IAppliance *pThis, PRUnichar * *path); + + nsresult (*GetDisks)(IAppliance *pThis, PRUint32 *disksSize, PRUnichar * **disks); + + nsresult (*GetVirtualSystemDescriptions)(IAppliance *pThis, PRUint32 *virtualSystemDescriptionsSize, IVirtualSystemDescription * **virtualSystemDescriptions); + + nsresult (*GetMachines)(IAppliance *pThis, PRUint32 *machinesSize, PRUnichar * **machines); + + nsresult (*Read)( + IAppliance *pThis, + PRUnichar * file, + IProgress * * aProgress + ); + + nsresult (*Interpret)(IAppliance *pThis ); + + nsresult (*ImportMachines)( + IAppliance *pThis, + PRUint32 optionsSize, + PRUint32* options, + IProgress * * aProgress + ); + + nsresult (*CreateVFSExplorer)( + IAppliance *pThis, + PRUnichar * aUri, + IVFSExplorer * * aExplorer + ); + + nsresult (*Write)( + IAppliance *pThis, + PRUnichar * format, + PRBool manifest, + PRUnichar * path, + IProgress * * progress + ); + + nsresult (*GetWarnings)( + IAppliance *pThis, + PRUint32 *aWarningsSize, + PRUnichar *** aWarnings + ); + +}; + +struct IAppliance +{ + struct IAppliance_vtbl *vtbl; +}; +/* End of struct IAppliance Declaration */ + + +/* Start of struct IVirtualSystemDescription Declaration */ +#define IVIRTUALSYSTEMDESCRIPTION_IID_STR "d7525e6c-531a-4c51-8e04-41235083a3d8" +#define IVIRTUALSYSTEMDESCRIPTION_IID { \ + 0xd7525e6c, 0x531a, 0x4c51, \ + { 0x8e, 0x04, 0x41, 0x23, 0x50, 0x83, 0xa3, 0xd8 } \ +} +struct IVirtualSystemDescription_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetCount)(IVirtualSystemDescription *pThis, PRUint32 *count); + + nsresult (*GetDescription)( + IVirtualSystemDescription *pThis, + PRUint32 *aTypesSize, + PRUint32** aTypes, + PRUint32 *aRefsSize, + PRUnichar *** aRefs, + PRUint32 *aOvfValuesSize, + PRUnichar *** aOvfValues, + PRUint32 *aVBoxValuesSize, + PRUnichar *** aVBoxValues, + PRUint32 *aExtraConfigValuesSize, + PRUnichar *** aExtraConfigValues + ); + + nsresult (*GetDescriptionByType)( + IVirtualSystemDescription *pThis, + PRUint32 aType, + PRUint32 *aTypesSize, + PRUint32** aTypes, + PRUint32 *aRefsSize, + PRUnichar *** aRefs, + PRUint32 *aOvfValuesSize, + PRUnichar *** aOvfValues, + PRUint32 *aVBoxValuesSize, + PRUnichar *** aVBoxValues, + PRUint32 *aExtraConfigValuesSize, + PRUnichar *** aExtraConfigValues + ); + + nsresult (*GetValuesByType)( + IVirtualSystemDescription *pThis, + PRUint32 aType, + PRUint32 aWhich, + PRUint32 *aValuesSize, + PRUnichar *** aValues + ); + + nsresult (*SetFinalValues)( + IVirtualSystemDescription *pThis, + PRUint32 aEnabledSize, + PRBool* aEnabled, + PRUint32 aVBoxValuesSize, + PRUnichar ** aVBoxValues, + PRUint32 aExtraConfigValuesSize, + PRUnichar ** aExtraConfigValues + ); + + nsresult (*AddDescription)( + IVirtualSystemDescription *pThis, + PRUint32 aType, + PRUnichar * aVBoxValue, + PRUnichar * aExtraConfigValue + ); + +}; + +struct IVirtualSystemDescription +{ + struct IVirtualSystemDescription_vtbl *vtbl; +}; +/* End of struct IVirtualSystemDescription Declaration */ + + +/* Start of struct IInternalMachineControl Declaration */ +#define IINTERNALMACHINECONTROL_IID_STR "dca36a92-703c-4649-98a4-f40c1ef0c336" +#define IINTERNALMACHINECONTROL_IID { \ + 0xdca36a92, 0x703c, 0x4649, \ + { 0x98, 0xa4, 0xf4, 0x0c, 0x1e, 0xf0, 0xc3, 0x36 } \ +} +struct IInternalMachineControl_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*SetRemoveSavedStateFile)( + IInternalMachineControl *pThis, + PRBool aRemove + ); + + nsresult (*UpdateState)( + IInternalMachineControl *pThis, + PRUint32 state + ); + + nsresult (*GetIPCId)( + IInternalMachineControl *pThis, + PRUnichar * * id + ); + + nsresult (*BeginPowerUp)( + IInternalMachineControl *pThis, + IProgress * aProgress + ); + + nsresult (*EndPowerUp)( + IInternalMachineControl *pThis, + PRInt32 result + ); + + nsresult (*BeginPoweringDown)( + IInternalMachineControl *pThis, + IProgress * * progress + ); + + nsresult (*EndPoweringDown)( + IInternalMachineControl *pThis, + PRInt32 result, + PRUnichar * errMsg + ); + + nsresult (*RunUSBDeviceFilters)( + IInternalMachineControl *pThis, + IUSBDevice * device, + PRBool * matched, + PRUint32 * maskedInterfaces + ); + + nsresult (*CaptureUSBDevice)( + IInternalMachineControl *pThis, + PRUnichar * id + ); + + nsresult (*DetachUSBDevice)( + IInternalMachineControl *pThis, + PRUnichar * id, + PRBool done + ); + + nsresult (*AutoCaptureUSBDevices)(IInternalMachineControl *pThis ); + + nsresult (*DetachAllUSBDevices)( + IInternalMachineControl *pThis, + PRBool done + ); + + nsresult (*OnSessionEnd)( + IInternalMachineControl *pThis, + ISession * session, + IProgress * * progress + ); + + nsresult (*BeginSavingState)( + IInternalMachineControl *pThis, + IProgress * * progress, + PRUnichar * * stateFilePath + ); + + nsresult (*EndSavingState)( + IInternalMachineControl *pThis, + PRInt32 result, + PRUnichar * errMsg + ); + + nsresult (*AdoptSavedState)( + IInternalMachineControl *pThis, + PRUnichar * savedStateFile + ); + + nsresult (*BeginTakingSnapshot)( + IInternalMachineControl *pThis, + IConsole * initiator, + PRUnichar * name, + PRUnichar * description, + IProgress * consoleProgress, + PRBool fTakingSnapshotOnline, + PRUnichar * * stateFilePath + ); + + nsresult (*EndTakingSnapshot)( + IInternalMachineControl *pThis, + PRBool success + ); + + nsresult (*DeleteSnapshot)( + IInternalMachineControl *pThis, + IConsole * initiator, + PRUnichar * startId, + PRUnichar * endId, + PRBool deleteAllChildren, + PRUint32 * machineState, + IProgress * * progress + ); + + nsresult (*FinishOnlineMergeMedium)( + IInternalMachineControl *pThis, + IMediumAttachment * mediumAttachment, + IMedium * source, + IMedium * target, + PRBool mergeForward, + IMedium * parentForTarget, + PRUint32 childrenToReparentSize, + IMedium ** childrenToReparent + ); + + nsresult (*RestoreSnapshot)( + IInternalMachineControl *pThis, + IConsole * initiator, + ISnapshot * snapshot, + PRUint32 * machineState, + IProgress * * progress + ); + + nsresult (*PullGuestProperties)( + IInternalMachineControl *pThis, + PRUint32 *nameSize, + PRUnichar *** name, + PRUint32 *valueSize, + PRUnichar *** value, + PRUint32 *timestampSize, + PRInt64** timestamp, + PRUint32 *flagsSize, + PRUnichar *** flags + ); + + nsresult (*PushGuestProperty)( + IInternalMachineControl *pThis, + PRUnichar * name, + PRUnichar * value, + PRInt64 timestamp, + PRUnichar * flags + ); + + nsresult (*LockMedia)(IInternalMachineControl *pThis ); + + nsresult (*UnlockMedia)(IInternalMachineControl *pThis ); + + nsresult (*EjectMedium)( + IInternalMachineControl *pThis, + IMediumAttachment * attachment, + IMediumAttachment * * newAttachment + ); + + nsresult (*ReportVmStatistics)( + IInternalMachineControl *pThis, + PRUint32 validStats, + PRUint32 cpuUser, + PRUint32 cpuKernel, + PRUint32 cpuIdle, + PRUint32 memTotal, + PRUint32 memFree, + PRUint32 memBalloon, + PRUint32 memShared, + PRUint32 memCache, + PRUint32 pagedTotal, + PRUint32 memAllocTotal, + PRUint32 memFreeTotal, + PRUint32 memBalloonTotal, + PRUint32 memSharedTotal, + PRUint32 vmNetRx, + PRUint32 vmNetTx + ); + +}; + +struct IInternalMachineControl +{ + struct IInternalMachineControl_vtbl *vtbl; +}; +/* End of struct IInternalMachineControl Declaration */ + + +/* Start of struct IBIOSSettings Declaration */ +#define IBIOSSETTINGS_IID_STR "38b54279-dc35-4f5e-a431-835b867c6b5e" +#define IBIOSSETTINGS_IID { \ + 0x38b54279, 0xdc35, 0x4f5e, \ + { 0xa4, 0x31, 0x83, 0x5b, 0x86, 0x7c, 0x6b, 0x5e } \ +} +struct IBIOSSettings_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetLogoFadeIn)(IBIOSSettings *pThis, PRBool *logoFadeIn); + nsresult (*SetLogoFadeIn)(IBIOSSettings *pThis, PRBool logoFadeIn); + + nsresult (*GetLogoFadeOut)(IBIOSSettings *pThis, PRBool *logoFadeOut); + nsresult (*SetLogoFadeOut)(IBIOSSettings *pThis, PRBool logoFadeOut); + + nsresult (*GetLogoDisplayTime)(IBIOSSettings *pThis, PRUint32 *logoDisplayTime); + nsresult (*SetLogoDisplayTime)(IBIOSSettings *pThis, PRUint32 logoDisplayTime); + + nsresult (*GetLogoImagePath)(IBIOSSettings *pThis, PRUnichar * *logoImagePath); + nsresult (*SetLogoImagePath)(IBIOSSettings *pThis, PRUnichar * logoImagePath); + + nsresult (*GetBootMenuMode)(IBIOSSettings *pThis, PRUint32 *bootMenuMode); + nsresult (*SetBootMenuMode)(IBIOSSettings *pThis, PRUint32 bootMenuMode); + + nsresult (*GetACPIEnabled)(IBIOSSettings *pThis, PRBool *ACPIEnabled); + nsresult (*SetACPIEnabled)(IBIOSSettings *pThis, PRBool ACPIEnabled); + + nsresult (*GetIOAPICEnabled)(IBIOSSettings *pThis, PRBool *IOAPICEnabled); + nsresult (*SetIOAPICEnabled)(IBIOSSettings *pThis, PRBool IOAPICEnabled); + + nsresult (*GetTimeOffset)(IBIOSSettings *pThis, PRInt64 *timeOffset); + nsresult (*SetTimeOffset)(IBIOSSettings *pThis, PRInt64 timeOffset); + + nsresult (*GetPXEDebugEnabled)(IBIOSSettings *pThis, PRBool *PXEDebugEnabled); + nsresult (*SetPXEDebugEnabled)(IBIOSSettings *pThis, PRBool PXEDebugEnabled); + +}; + +struct IBIOSSettings +{ + struct IBIOSSettings_vtbl *vtbl; +}; +/* End of struct IBIOSSettings Declaration */ + + +/* Start of struct IPCIAddress Declaration */ +#define IPCIADDRESS_IID_STR "D88B324F-DB19-4D3B-A1A9-BF5B127199A8" +#define IPCIADDRESS_IID { \ + 0xD88B324F, 0xDB19, 0x4D3B, \ + { 0xA1, 0xA9, 0xBF, 0x5B, 0x12, 0x71, 0x99, 0xA8 } \ +} +struct IPCIAddress_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetBus)(IPCIAddress *pThis, PRInt16 *bus); + nsresult (*SetBus)(IPCIAddress *pThis, PRInt16 bus); + + nsresult (*GetDevice)(IPCIAddress *pThis, PRInt16 *device); + nsresult (*SetDevice)(IPCIAddress *pThis, PRInt16 device); + + nsresult (*GetDevFunction)(IPCIAddress *pThis, PRInt16 *devFunction); + nsresult (*SetDevFunction)(IPCIAddress *pThis, PRInt16 devFunction); + + nsresult (*AsLong)( + IPCIAddress *pThis, + PRInt32 * result + ); + + nsresult (*FromLong)( + IPCIAddress *pThis, + PRInt32 number + ); + +}; + +struct IPCIAddress +{ + struct IPCIAddress_vtbl *vtbl; +}; +/* End of struct IPCIAddress Declaration */ + + +/* Start of struct IPCIDeviceAttachment Declaration */ +#define IPCIDEVICEATTACHMENT_IID_STR "91f33d6f-e621-4f70-a77e-15f0e3c714d5" +#define IPCIDEVICEATTACHMENT_IID { \ + 0x91f33d6f, 0xe621, 0x4f70, \ + { 0xa7, 0x7e, 0x15, 0xf0, 0xe3, 0xc7, 0x14, 0xd5 } \ +} +struct IPCIDeviceAttachment_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IPCIDeviceAttachment *pThis, PRUnichar * *name); + + nsresult (*GetIsPhysicalDevice)(IPCIDeviceAttachment *pThis, PRBool *isPhysicalDevice); + + nsresult (*GetHostAddress)(IPCIDeviceAttachment *pThis, PRInt32 *hostAddress); + + nsresult (*GetGuestAddress)(IPCIDeviceAttachment *pThis, PRInt32 *guestAddress); + +}; + +struct IPCIDeviceAttachment +{ + struct IPCIDeviceAttachment_vtbl *vtbl; +}; +/* End of struct IPCIDeviceAttachment Declaration */ + + +/* Start of struct IMachine Declaration */ +#define IMACHINE_IID_STR "22781af3-1c96-4126-9edf-67a020e0e858" +#define IMACHINE_IID { \ + 0x22781af3, 0x1c96, 0x4126, \ + { 0x9e, 0xdf, 0x67, 0xa0, 0x20, 0xe0, 0xe8, 0x58 } \ +} +struct IMachine_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetParent)(IMachine *pThis, IVirtualBox * *parent); + + nsresult (*GetAccessible)(IMachine *pThis, PRBool *accessible); + + nsresult (*GetAccessError)(IMachine *pThis, IVirtualBoxErrorInfo * *accessError); + + nsresult (*GetName)(IMachine *pThis, PRUnichar * *name); + nsresult (*SetName)(IMachine *pThis, PRUnichar * name); + + nsresult (*GetDescription)(IMachine *pThis, PRUnichar * *description); + nsresult (*SetDescription)(IMachine *pThis, PRUnichar * description); + + nsresult (*GetId)(IMachine *pThis, PRUnichar * *id); + + nsresult (*GetGroups)(IMachine *pThis, PRUint32 *groupsSize, PRUnichar * **groups); + nsresult (*SetGroups)(IMachine *pThis, PRUint32 groupsSize, PRUnichar * *groups); + + nsresult (*GetOSTypeId)(IMachine *pThis, PRUnichar * *OSTypeId); + nsresult (*SetOSTypeId)(IMachine *pThis, PRUnichar * OSTypeId); + + nsresult (*GetHardwareVersion)(IMachine *pThis, PRUnichar * *hardwareVersion); + nsresult (*SetHardwareVersion)(IMachine *pThis, PRUnichar * hardwareVersion); + + nsresult (*GetHardwareUUID)(IMachine *pThis, PRUnichar * *hardwareUUID); + nsresult (*SetHardwareUUID)(IMachine *pThis, PRUnichar * hardwareUUID); + + nsresult (*GetCPUCount)(IMachine *pThis, PRUint32 *CPUCount); + nsresult (*SetCPUCount)(IMachine *pThis, PRUint32 CPUCount); + + nsresult (*GetCPUHotPlugEnabled)(IMachine *pThis, PRBool *CPUHotPlugEnabled); + nsresult (*SetCPUHotPlugEnabled)(IMachine *pThis, PRBool CPUHotPlugEnabled); + + nsresult (*GetCPUExecutionCap)(IMachine *pThis, PRUint32 *CPUExecutionCap); + nsresult (*SetCPUExecutionCap)(IMachine *pThis, PRUint32 CPUExecutionCap); + + nsresult (*GetMemorySize)(IMachine *pThis, PRUint32 *memorySize); + nsresult (*SetMemorySize)(IMachine *pThis, PRUint32 memorySize); + + nsresult (*GetMemoryBalloonSize)(IMachine *pThis, PRUint32 *memoryBalloonSize); + nsresult (*SetMemoryBalloonSize)(IMachine *pThis, PRUint32 memoryBalloonSize); + + nsresult (*GetPageFusionEnabled)(IMachine *pThis, PRBool *pageFusionEnabled); + nsresult (*SetPageFusionEnabled)(IMachine *pThis, PRBool pageFusionEnabled); + + nsresult (*GetVRAMSize)(IMachine *pThis, PRUint32 *VRAMSize); + nsresult (*SetVRAMSize)(IMachine *pThis, PRUint32 VRAMSize); + + nsresult (*GetAccelerate3DEnabled)(IMachine *pThis, PRBool *accelerate3DEnabled); + nsresult (*SetAccelerate3DEnabled)(IMachine *pThis, PRBool accelerate3DEnabled); + + nsresult (*GetAccelerate2DVideoEnabled)(IMachine *pThis, PRBool *accelerate2DVideoEnabled); + nsresult (*SetAccelerate2DVideoEnabled)(IMachine *pThis, PRBool accelerate2DVideoEnabled); + + nsresult (*GetMonitorCount)(IMachine *pThis, PRUint32 *monitorCount); + nsresult (*SetMonitorCount)(IMachine *pThis, PRUint32 monitorCount); + + nsresult (*GetVideoCaptureEnabled)(IMachine *pThis, PRBool *VideoCaptureEnabled); + nsresult (*SetVideoCaptureEnabled)(IMachine *pThis, PRBool VideoCaptureEnabled); + + nsresult (*GetVideoCaptureFile)(IMachine *pThis, PRUnichar * *VideoCaptureFile); + nsresult (*SetVideoCaptureFile)(IMachine *pThis, PRUnichar * VideoCaptureFile); + + nsresult (*GetVideoCaptureWidth)(IMachine *pThis, PRUint32 *VideoCaptureWidth); + nsresult (*SetVideoCaptureWidth)(IMachine *pThis, PRUint32 VideoCaptureWidth); + + nsresult (*GetVideoCaptureHeight)(IMachine *pThis, PRUint32 *VideoCaptureHeight); + nsresult (*SetVideoCaptureHeight)(IMachine *pThis, PRUint32 VideoCaptureHeight); + + nsresult (*GetBIOSSettings)(IMachine *pThis, IBIOSSettings * *BIOSSettings); + + nsresult (*GetFirmwareType)(IMachine *pThis, PRUint32 *firmwareType); + nsresult (*SetFirmwareType)(IMachine *pThis, PRUint32 firmwareType); + + nsresult (*GetPointingHIDType)(IMachine *pThis, PRUint32 *pointingHIDType); + nsresult (*SetPointingHIDType)(IMachine *pThis, PRUint32 pointingHIDType); + + nsresult (*GetKeyboardHIDType)(IMachine *pThis, PRUint32 *keyboardHIDType); + nsresult (*SetKeyboardHIDType)(IMachine *pThis, PRUint32 keyboardHIDType); + + nsresult (*GetHPETEnabled)(IMachine *pThis, PRBool *HPETEnabled); + nsresult (*SetHPETEnabled)(IMachine *pThis, PRBool HPETEnabled); + + nsresult (*GetChipsetType)(IMachine *pThis, PRUint32 *chipsetType); + nsresult (*SetChipsetType)(IMachine *pThis, PRUint32 chipsetType); + + nsresult (*GetSnapshotFolder)(IMachine *pThis, PRUnichar * *snapshotFolder); + nsresult (*SetSnapshotFolder)(IMachine *pThis, PRUnichar * snapshotFolder); + + nsresult (*GetVRDEServer)(IMachine *pThis, IVRDEServer * *VRDEServer); + + nsresult (*GetEmulatedUSBWebcameraEnabled)(IMachine *pThis, PRBool *emulatedUSBWebcameraEnabled); + nsresult (*SetEmulatedUSBWebcameraEnabled)(IMachine *pThis, PRBool emulatedUSBWebcameraEnabled); + + nsresult (*GetEmulatedUSBCardReaderEnabled)(IMachine *pThis, PRBool *emulatedUSBCardReaderEnabled); + nsresult (*SetEmulatedUSBCardReaderEnabled)(IMachine *pThis, PRBool emulatedUSBCardReaderEnabled); + + nsresult (*GetMediumAttachments)(IMachine *pThis, PRUint32 *mediumAttachmentsSize, IMediumAttachment * **mediumAttachments); + + nsresult (*GetUSBController)(IMachine *pThis, IUSBController * *USBController); + + nsresult (*GetAudioAdapter)(IMachine *pThis, IAudioAdapter * *audioAdapter); + + nsresult (*GetStorageControllers)(IMachine *pThis, PRUint32 *storageControllersSize, IStorageController * **storageControllers); + + nsresult (*GetSettingsFilePath)(IMachine *pThis, PRUnichar * *settingsFilePath); + + nsresult (*GetSettingsModified)(IMachine *pThis, PRBool *settingsModified); + + nsresult (*GetSessionState)(IMachine *pThis, PRUint32 *sessionState); + + nsresult (*GetSessionType)(IMachine *pThis, PRUnichar * *sessionType); + + nsresult (*GetSessionPID)(IMachine *pThis, PRUint32 *sessionPID); + + nsresult (*GetState)(IMachine *pThis, PRUint32 *state); + + nsresult (*GetLastStateChange)(IMachine *pThis, PRInt64 *lastStateChange); + + nsresult (*GetStateFilePath)(IMachine *pThis, PRUnichar * *stateFilePath); + + nsresult (*GetLogFolder)(IMachine *pThis, PRUnichar * *logFolder); + + nsresult (*GetCurrentSnapshot)(IMachine *pThis, ISnapshot * *currentSnapshot); + + nsresult (*GetSnapshotCount)(IMachine *pThis, PRUint32 *snapshotCount); + + nsresult (*GetCurrentStateModified)(IMachine *pThis, PRBool *currentStateModified); + + nsresult (*GetSharedFolders)(IMachine *pThis, PRUint32 *sharedFoldersSize, ISharedFolder * **sharedFolders); + + nsresult (*GetClipboardMode)(IMachine *pThis, PRUint32 *clipboardMode); + nsresult (*SetClipboardMode)(IMachine *pThis, PRUint32 clipboardMode); + + nsresult (*GetDragAndDropMode)(IMachine *pThis, PRUint32 *dragAndDropMode); + nsresult (*SetDragAndDropMode)(IMachine *pThis, PRUint32 dragAndDropMode); + + nsresult (*GetGuestPropertyNotificationPatterns)(IMachine *pThis, PRUnichar * *guestPropertyNotificationPatterns); + nsresult (*SetGuestPropertyNotificationPatterns)(IMachine *pThis, PRUnichar * guestPropertyNotificationPatterns); + + nsresult (*GetTeleporterEnabled)(IMachine *pThis, PRBool *teleporterEnabled); + nsresult (*SetTeleporterEnabled)(IMachine *pThis, PRBool teleporterEnabled); + + nsresult (*GetTeleporterPort)(IMachine *pThis, PRUint32 *teleporterPort); + nsresult (*SetTeleporterPort)(IMachine *pThis, PRUint32 teleporterPort); + + nsresult (*GetTeleporterAddress)(IMachine *pThis, PRUnichar * *teleporterAddress); + nsresult (*SetTeleporterAddress)(IMachine *pThis, PRUnichar * teleporterAddress); + + nsresult (*GetTeleporterPassword)(IMachine *pThis, PRUnichar * *teleporterPassword); + nsresult (*SetTeleporterPassword)(IMachine *pThis, PRUnichar * teleporterPassword); + + nsresult (*GetFaultToleranceState)(IMachine *pThis, PRUint32 *faultToleranceState); + nsresult (*SetFaultToleranceState)(IMachine *pThis, PRUint32 faultToleranceState); + + nsresult (*GetFaultTolerancePort)(IMachine *pThis, PRUint32 *faultTolerancePort); + nsresult (*SetFaultTolerancePort)(IMachine *pThis, PRUint32 faultTolerancePort); + + nsresult (*GetFaultToleranceAddress)(IMachine *pThis, PRUnichar * *faultToleranceAddress); + nsresult (*SetFaultToleranceAddress)(IMachine *pThis, PRUnichar * faultToleranceAddress); + + nsresult (*GetFaultTolerancePassword)(IMachine *pThis, PRUnichar * *faultTolerancePassword); + nsresult (*SetFaultTolerancePassword)(IMachine *pThis, PRUnichar * faultTolerancePassword); + + nsresult (*GetFaultToleranceSyncInterval)(IMachine *pThis, PRUint32 *faultToleranceSyncInterval); + nsresult (*SetFaultToleranceSyncInterval)(IMachine *pThis, PRUint32 faultToleranceSyncInterval); + + nsresult (*GetRTCUseUTC)(IMachine *pThis, PRBool *RTCUseUTC); + nsresult (*SetRTCUseUTC)(IMachine *pThis, PRBool RTCUseUTC); + + nsresult (*GetIOCacheEnabled)(IMachine *pThis, PRBool *IOCacheEnabled); + nsresult (*SetIOCacheEnabled)(IMachine *pThis, PRBool IOCacheEnabled); + + nsresult (*GetIOCacheSize)(IMachine *pThis, PRUint32 *IOCacheSize); + nsresult (*SetIOCacheSize)(IMachine *pThis, PRUint32 IOCacheSize); + + nsresult (*GetPCIDeviceAssignments)(IMachine *pThis, PRUint32 *PCIDeviceAssignmentsSize, IPCIDeviceAttachment * **PCIDeviceAssignments); + + nsresult (*GetBandwidthControl)(IMachine *pThis, IBandwidthControl * *bandwidthControl); + + nsresult (*GetTracingEnabled)(IMachine *pThis, PRBool *tracingEnabled); + nsresult (*SetTracingEnabled)(IMachine *pThis, PRBool tracingEnabled); + + nsresult (*GetTracingConfig)(IMachine *pThis, PRUnichar * *tracingConfig); + nsresult (*SetTracingConfig)(IMachine *pThis, PRUnichar * tracingConfig); + + nsresult (*GetAllowTracingToAccessVM)(IMachine *pThis, PRBool *allowTracingToAccessVM); + nsresult (*SetAllowTracingToAccessVM)(IMachine *pThis, PRBool allowTracingToAccessVM); + + nsresult (*GetAutostartEnabled)(IMachine *pThis, PRBool *autostartEnabled); + nsresult (*SetAutostartEnabled)(IMachine *pThis, PRBool autostartEnabled); + + nsresult (*GetAutostartDelay)(IMachine *pThis, PRUint32 *autostartDelay); + nsresult (*SetAutostartDelay)(IMachine *pThis, PRUint32 autostartDelay); + + nsresult (*GetAutostopType)(IMachine *pThis, PRUint32 *autostopType); + nsresult (*SetAutostopType)(IMachine *pThis, PRUint32 autostopType); + + nsresult (*LockMachine)( + IMachine *pThis, + ISession * session, + PRUint32 lockType + ); + + nsresult (*LaunchVMProcess)( + IMachine *pThis, + ISession * session, + PRUnichar * type, + PRUnichar * environment, + IProgress * * progress + ); + + nsresult (*SetBootOrder)( + IMachine *pThis, + PRUint32 position, + PRUint32 device + ); + + nsresult (*GetBootOrder)( + IMachine *pThis, + PRUint32 position, + PRUint32 * device + ); + + nsresult (*AttachDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRUint32 type, + IMedium * medium + ); + + nsresult (*AttachDeviceWithoutMedium)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRUint32 type + ); + + nsresult (*DetachDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device + ); + + nsresult (*PassthroughDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRBool passthrough + ); + + nsresult (*TemporaryEjectDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRBool temporaryEject + ); + + nsresult (*NonRotationalDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRBool nonRotational + ); + + nsresult (*SetAutoDiscardForDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRBool discard + ); + + nsresult (*SetBandwidthGroupForDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + IBandwidthGroup * bandwidthGroup + ); + + nsresult (*SetNoBandwidthGroupForDevice)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device + ); + + nsresult (*UnmountMedium)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + PRBool force + ); + + nsresult (*MountMedium)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + IMedium * medium, + PRBool force + ); + + nsresult (*GetMedium)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + IMedium * * medium + ); + + nsresult (*GetMediumAttachmentsOfController)( + IMachine *pThis, + PRUnichar * name, + PRUint32 *mediumAttachmentsSize, + IMediumAttachment *** mediumAttachments + ); + + nsresult (*GetMediumAttachment)( + IMachine *pThis, + PRUnichar * name, + PRInt32 controllerPort, + PRInt32 device, + IMediumAttachment * * attachment + ); + + nsresult (*AttachHostPCIDevice)( + IMachine *pThis, + PRInt32 hostAddress, + PRInt32 desiredGuestAddress, + PRBool tryToUnbind + ); + + nsresult (*DetachHostPCIDevice)( + IMachine *pThis, + PRInt32 hostAddress + ); + + nsresult (*GetNetworkAdapter)( + IMachine *pThis, + PRUint32 slot, + INetworkAdapter * * adapter + ); + + nsresult (*AddStorageController)( + IMachine *pThis, + PRUnichar * name, + PRUint32 connectionType, + IStorageController * * controller + ); + + nsresult (*GetStorageControllerByName)( + IMachine *pThis, + PRUnichar * name, + IStorageController * * storageController + ); + + nsresult (*GetStorageControllerByInstance)( + IMachine *pThis, + PRUint32 instance, + IStorageController * * storageController + ); + + nsresult (*RemoveStorageController)( + IMachine *pThis, + PRUnichar * name + ); + + nsresult (*SetStorageControllerBootable)( + IMachine *pThis, + PRUnichar * name, + PRBool bootable + ); + + nsresult (*GetSerialPort)( + IMachine *pThis, + PRUint32 slot, + ISerialPort * * port + ); + + nsresult (*GetParallelPort)( + IMachine *pThis, + PRUint32 slot, + IParallelPort * * port + ); + + nsresult (*GetExtraDataKeys)( + IMachine *pThis, + PRUint32 *valueSize, + PRUnichar *** value + ); + + nsresult (*GetExtraData)( + IMachine *pThis, + PRUnichar * key, + PRUnichar * * value + ); + + nsresult (*SetExtraData)( + IMachine *pThis, + PRUnichar * key, + PRUnichar * value + ); + + nsresult (*GetCPUProperty)( + IMachine *pThis, + PRUint32 property, + PRBool * value + ); + + nsresult (*SetCPUProperty)( + IMachine *pThis, + PRUint32 property, + PRBool value + ); + + nsresult (*GetCPUIDLeaf)( + IMachine *pThis, + PRUint32 id, + PRUint32 * valEax, + PRUint32 * valEbx, + PRUint32 * valEcx, + PRUint32 * valEdx + ); + + nsresult (*SetCPUIDLeaf)( + IMachine *pThis, + PRUint32 id, + PRUint32 valEax, + PRUint32 valEbx, + PRUint32 valEcx, + PRUint32 valEdx + ); + + nsresult (*RemoveCPUIDLeaf)( + IMachine *pThis, + PRUint32 id + ); + + nsresult (*RemoveAllCPUIDLeaves)(IMachine *pThis ); + + nsresult (*GetHWVirtExProperty)( + IMachine *pThis, + PRUint32 property, + PRBool * value + ); + + nsresult (*SetHWVirtExProperty)( + IMachine *pThis, + PRUint32 property, + PRBool value + ); + + nsresult (*SaveSettings)(IMachine *pThis ); + + nsresult (*DiscardSettings)(IMachine *pThis ); + + nsresult (*Unregister)( + IMachine *pThis, + PRUint32 cleanupMode, + PRUint32 *aMediaSize, + IMedium *** aMedia + ); + + nsresult (*Delete)( + IMachine *pThis, + PRUint32 aMediaSize, + IMedium ** aMedia, + IProgress * * aProgress + ); + + nsresult (*Export)( + IMachine *pThis, + IAppliance * aAppliance, + PRUnichar * location, + IVirtualSystemDescription * * aDescription + ); + + nsresult (*FindSnapshot)( + IMachine *pThis, + PRUnichar * nameOrId, + ISnapshot * * snapshot + ); + + nsresult (*CreateSharedFolder)( + IMachine *pThis, + PRUnichar * name, + PRUnichar * hostPath, + PRBool writable, + PRBool automount + ); + + nsresult (*RemoveSharedFolder)( + IMachine *pThis, + PRUnichar * name + ); + + nsresult (*CanShowConsoleWindow)( + IMachine *pThis, + PRBool * canShow + ); + + nsresult (*ShowConsoleWindow)( + IMachine *pThis, + PRInt64 * winId + ); + + nsresult (*GetGuestProperty)( + IMachine *pThis, + PRUnichar * name, + PRUnichar * * value, + PRInt64 * timestamp, + PRUnichar * * flags + ); + + nsresult (*GetGuestPropertyValue)( + IMachine *pThis, + PRUnichar * property, + PRUnichar * * value + ); + + nsresult (*GetGuestPropertyTimestamp)( + IMachine *pThis, + PRUnichar * property, + PRInt64 * value + ); + + nsresult (*SetGuestProperty)( + IMachine *pThis, + PRUnichar * property, + PRUnichar * value, + PRUnichar * flags + ); + + nsresult (*SetGuestPropertyValue)( + IMachine *pThis, + PRUnichar * property, + PRUnichar * value + ); + + nsresult (*DeleteGuestProperty)( + IMachine *pThis, + PRUnichar * name + ); + + nsresult (*EnumerateGuestProperties)( + IMachine *pThis, + PRUnichar * patterns, + PRUint32 *nameSize, + PRUnichar *** name, + PRUint32 *valueSize, + PRUnichar *** value, + PRUint32 *timestampSize, + PRInt64** timestamp, + PRUint32 *flagsSize, + PRUnichar *** flags + ); + + nsresult (*QuerySavedGuestScreenInfo)( + IMachine *pThis, + PRUint32 screenId, + PRUint32 * originX, + PRUint32 * originY, + PRUint32 * width, + PRUint32 * height, + PRBool * enabled + ); + + nsresult (*QuerySavedThumbnailSize)( + IMachine *pThis, + PRUint32 screenId, + PRUint32 * size, + PRUint32 * width, + PRUint32 * height + ); + + nsresult (*ReadSavedThumbnailToArray)( + IMachine *pThis, + PRUint32 screenId, + PRBool BGR, + PRUint32 * width, + PRUint32 * height, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*ReadSavedThumbnailPNGToArray)( + IMachine *pThis, + PRUint32 screenId, + PRUint32 * width, + PRUint32 * height, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*QuerySavedScreenshotPNGSize)( + IMachine *pThis, + PRUint32 screenId, + PRUint32 * size, + PRUint32 * width, + PRUint32 * height + ); + + nsresult (*ReadSavedScreenshotPNGToArray)( + IMachine *pThis, + PRUint32 screenId, + PRUint32 * width, + PRUint32 * height, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*HotPlugCPU)( + IMachine *pThis, + PRUint32 cpu + ); + + nsresult (*HotUnplugCPU)( + IMachine *pThis, + PRUint32 cpu + ); + + nsresult (*GetCPUStatus)( + IMachine *pThis, + PRUint32 cpu, + PRBool * attached + ); + + nsresult (*QueryLogFilename)( + IMachine *pThis, + PRUint32 idx, + PRUnichar * * filename + ); + + nsresult (*ReadLog)( + IMachine *pThis, + PRUint32 idx, + PRInt64 offset, + PRInt64 size, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*CloneTo)( + IMachine *pThis, + IMachine * target, + PRUint32 mode, + PRUint32 optionsSize, + PRUint32* options, + IProgress * * progress + ); + +}; + +struct IMachine +{ + struct IMachine_vtbl *vtbl; +}; +/* End of struct IMachine Declaration */ + + +/* Start of struct IVRDEServerInfo Declaration */ +#define IVRDESERVERINFO_IID_STR "714434a1-58c3-4aab-9049-7652c5df113b" +#define IVRDESERVERINFO_IID { \ + 0x714434a1, 0x58c3, 0x4aab, \ + { 0x90, 0x49, 0x76, 0x52, 0xc5, 0xdf, 0x11, 0x3b } \ +} +struct IVRDEServerInfo_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetActive)(IVRDEServerInfo *pThis, PRBool *active); + + nsresult (*GetPort)(IVRDEServerInfo *pThis, PRInt32 *port); + + nsresult (*GetNumberOfClients)(IVRDEServerInfo *pThis, PRUint32 *numberOfClients); + + nsresult (*GetBeginTime)(IVRDEServerInfo *pThis, PRInt64 *beginTime); + + nsresult (*GetEndTime)(IVRDEServerInfo *pThis, PRInt64 *endTime); + + nsresult (*GetBytesSent)(IVRDEServerInfo *pThis, PRInt64 *bytesSent); + + nsresult (*GetBytesSentTotal)(IVRDEServerInfo *pThis, PRInt64 *bytesSentTotal); + + nsresult (*GetBytesReceived)(IVRDEServerInfo *pThis, PRInt64 *bytesReceived); + + nsresult (*GetBytesReceivedTotal)(IVRDEServerInfo *pThis, PRInt64 *bytesReceivedTotal); + + nsresult (*GetUser)(IVRDEServerInfo *pThis, PRUnichar * *user); + + nsresult (*GetDomain)(IVRDEServerInfo *pThis, PRUnichar * *domain); + + nsresult (*GetClientName)(IVRDEServerInfo *pThis, PRUnichar * *clientName); + + nsresult (*GetClientIP)(IVRDEServerInfo *pThis, PRUnichar * *clientIP); + + nsresult (*GetClientVersion)(IVRDEServerInfo *pThis, PRUint32 *clientVersion); + + nsresult (*GetEncryptionStyle)(IVRDEServerInfo *pThis, PRUint32 *encryptionStyle); + +}; + +struct IVRDEServerInfo +{ + struct IVRDEServerInfo_vtbl *vtbl; +}; +/* End of struct IVRDEServerInfo Declaration */ + + +/* Start of struct IConsole Declaration */ +#define ICONSOLE_IID_STR "db7ab4ca-2a3f-4183-9243-c1208da92392" +#define ICONSOLE_IID { \ + 0xdb7ab4ca, 0x2a3f, 0x4183, \ + { 0x92, 0x43, 0xc1, 0x20, 0x8d, 0xa9, 0x23, 0x92 } \ +} +struct IConsole_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMachine)(IConsole *pThis, IMachine * *machine); + + nsresult (*GetState)(IConsole *pThis, PRUint32 *state); + + nsresult (*GetGuest)(IConsole *pThis, IGuest * *guest); + + nsresult (*GetKeyboard)(IConsole *pThis, IKeyboard * *keyboard); + + nsresult (*GetMouse)(IConsole *pThis, IMouse * *mouse); + + nsresult (*GetDisplay)(IConsole *pThis, IDisplay * *display); + + nsresult (*GetDebugger)(IConsole *pThis, IMachineDebugger * *debugger); + + nsresult (*GetUSBDevices)(IConsole *pThis, PRUint32 *USBDevicesSize, IUSBDevice * **USBDevices); + + nsresult (*GetRemoteUSBDevices)(IConsole *pThis, PRUint32 *remoteUSBDevicesSize, IHostUSBDevice * **remoteUSBDevices); + + nsresult (*GetSharedFolders)(IConsole *pThis, PRUint32 *sharedFoldersSize, ISharedFolder * **sharedFolders); + + nsresult (*GetVRDEServerInfo)(IConsole *pThis, IVRDEServerInfo * *VRDEServerInfo); + + nsresult (*GetEventSource)(IConsole *pThis, IEventSource * *eventSource); + + nsresult (*GetAttachedPCIDevices)(IConsole *pThis, PRUint32 *attachedPCIDevicesSize, IPCIDeviceAttachment * **attachedPCIDevices); + + nsresult (*GetUseHostClipboard)(IConsole *pThis, PRBool *useHostClipboard); + nsresult (*SetUseHostClipboard)(IConsole *pThis, PRBool useHostClipboard); + + nsresult (*PowerUp)( + IConsole *pThis, + IProgress * * progress + ); + + nsresult (*PowerUpPaused)( + IConsole *pThis, + IProgress * * progress + ); + + nsresult (*PowerDown)( + IConsole *pThis, + IProgress * * progress + ); + + nsresult (*Reset)(IConsole *pThis ); + + nsresult (*Pause)(IConsole *pThis ); + + nsresult (*Resume)(IConsole *pThis ); + + nsresult (*PowerButton)(IConsole *pThis ); + + nsresult (*SleepButton)(IConsole *pThis ); + + nsresult (*GetPowerButtonHandled)( + IConsole *pThis, + PRBool * handled + ); + + nsresult (*GetGuestEnteredACPIMode)( + IConsole *pThis, + PRBool * entered + ); + + nsresult (*SaveState)( + IConsole *pThis, + IProgress * * progress + ); + + nsresult (*AdoptSavedState)( + IConsole *pThis, + PRUnichar * savedStateFile + ); + + nsresult (*DiscardSavedState)( + IConsole *pThis, + PRBool fRemoveFile + ); + + nsresult (*GetDeviceActivity)( + IConsole *pThis, + PRUint32 type, + PRUint32 * activity + ); + + nsresult (*AttachUSBDevice)( + IConsole *pThis, + PRUnichar * id + ); + + nsresult (*DetachUSBDevice)( + IConsole *pThis, + PRUnichar * id, + IUSBDevice * * device + ); + + nsresult (*FindUSBDeviceByAddress)( + IConsole *pThis, + PRUnichar * name, + IUSBDevice * * device + ); + + nsresult (*FindUSBDeviceById)( + IConsole *pThis, + PRUnichar * id, + IUSBDevice * * device + ); + + nsresult (*CreateSharedFolder)( + IConsole *pThis, + PRUnichar * name, + PRUnichar * hostPath, + PRBool writable, + PRBool automount + ); + + nsresult (*RemoveSharedFolder)( + IConsole *pThis, + PRUnichar * name + ); + + nsresult (*TakeSnapshot)( + IConsole *pThis, + PRUnichar * name, + PRUnichar * description, + IProgress * * progress + ); + + nsresult (*DeleteSnapshot)( + IConsole *pThis, + PRUnichar * id, + IProgress * * progress + ); + + nsresult (*DeleteSnapshotAndAllChildren)( + IConsole *pThis, + PRUnichar * id, + IProgress * * progress + ); + + nsresult (*DeleteSnapshotRange)( + IConsole *pThis, + PRUnichar * startId, + PRUnichar * endId, + IProgress * * progress + ); + + nsresult (*RestoreSnapshot)( + IConsole *pThis, + ISnapshot * snapshot, + IProgress * * progress + ); + + nsresult (*Teleport)( + IConsole *pThis, + PRUnichar * hostname, + PRUint32 tcpport, + PRUnichar * password, + PRUint32 maxDowntime, + IProgress * * progress + ); + +}; + +struct IConsole +{ + struct IConsole_vtbl *vtbl; +}; +/* End of struct IConsole Declaration */ + + +/* Start of struct IHostNetworkInterface Declaration */ +#define IHOSTNETWORKINTERFACE_IID_STR "87a4153d-6889-4dd6-9654-2e9ff0ae8dec" +#define IHOSTNETWORKINTERFACE_IID { \ + 0x87a4153d, 0x6889, 0x4dd6, \ + { 0x96, 0x54, 0x2e, 0x9f, 0xf0, 0xae, 0x8d, 0xec } \ +} +struct IHostNetworkInterface_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IHostNetworkInterface *pThis, PRUnichar * *name); + + nsresult (*GetId)(IHostNetworkInterface *pThis, PRUnichar * *id); + + nsresult (*GetNetworkName)(IHostNetworkInterface *pThis, PRUnichar * *networkName); + + nsresult (*GetDHCPEnabled)(IHostNetworkInterface *pThis, PRBool *DHCPEnabled); + + nsresult (*GetIPAddress)(IHostNetworkInterface *pThis, PRUnichar * *IPAddress); + + nsresult (*GetNetworkMask)(IHostNetworkInterface *pThis, PRUnichar * *networkMask); + + nsresult (*GetIPV6Supported)(IHostNetworkInterface *pThis, PRBool *IPV6Supported); + + nsresult (*GetIPV6Address)(IHostNetworkInterface *pThis, PRUnichar * *IPV6Address); + + nsresult (*GetIPV6NetworkMaskPrefixLength)(IHostNetworkInterface *pThis, PRUint32 *IPV6NetworkMaskPrefixLength); + + nsresult (*GetHardwareAddress)(IHostNetworkInterface *pThis, PRUnichar * *hardwareAddress); + + nsresult (*GetMediumType)(IHostNetworkInterface *pThis, PRUint32 *mediumType); + + nsresult (*GetStatus)(IHostNetworkInterface *pThis, PRUint32 *status); + + nsresult (*GetInterfaceType)(IHostNetworkInterface *pThis, PRUint32 *interfaceType); + + nsresult (*EnableStaticIPConfig)( + IHostNetworkInterface *pThis, + PRUnichar * IPAddress, + PRUnichar * networkMask + ); + + nsresult (*EnableStaticIPConfigV6)( + IHostNetworkInterface *pThis, + PRUnichar * IPV6Address, + PRUint32 IPV6NetworkMaskPrefixLength + ); + + nsresult (*EnableDynamicIPConfig)(IHostNetworkInterface *pThis ); + + nsresult (*DHCPRediscover)(IHostNetworkInterface *pThis ); + +}; + +struct IHostNetworkInterface +{ + struct IHostNetworkInterface_vtbl *vtbl; +}; +/* End of struct IHostNetworkInterface Declaration */ + + +/* Start of struct IHost Declaration */ +#define IHOST_IID_STR "30678943-32df-4830-b413-931b25ac86a0" +#define IHOST_IID { \ + 0x30678943, 0x32df, 0x4830, \ + { 0xb4, 0x13, 0x93, 0x1b, 0x25, 0xac, 0x86, 0xa0 } \ +} +struct IHost_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetDVDDrives)(IHost *pThis, PRUint32 *DVDDrivesSize, IMedium * **DVDDrives); + + nsresult (*GetFloppyDrives)(IHost *pThis, PRUint32 *floppyDrivesSize, IMedium * **floppyDrives); + + nsresult (*GetUSBDevices)(IHost *pThis, PRUint32 *USBDevicesSize, IHostUSBDevice * **USBDevices); + + nsresult (*GetUSBDeviceFilters)(IHost *pThis, PRUint32 *USBDeviceFiltersSize, IHostUSBDeviceFilter * **USBDeviceFilters); + + nsresult (*GetNetworkInterfaces)(IHost *pThis, PRUint32 *networkInterfacesSize, IHostNetworkInterface * **networkInterfaces); + + nsresult (*GetProcessorCount)(IHost *pThis, PRUint32 *processorCount); + + nsresult (*GetProcessorOnlineCount)(IHost *pThis, PRUint32 *processorOnlineCount); + + nsresult (*GetProcessorCoreCount)(IHost *pThis, PRUint32 *processorCoreCount); + + nsresult (*GetMemorySize)(IHost *pThis, PRUint32 *memorySize); + + nsresult (*GetMemoryAvailable)(IHost *pThis, PRUint32 *memoryAvailable); + + nsresult (*GetOperatingSystem)(IHost *pThis, PRUnichar * *operatingSystem); + + nsresult (*GetOSVersion)(IHost *pThis, PRUnichar * *OSVersion); + + nsresult (*GetUTCTime)(IHost *pThis, PRInt64 *UTCTime); + + nsresult (*GetAcceleration3DAvailable)(IHost *pThis, PRBool *acceleration3DAvailable); + + nsresult (*GetProcessorSpeed)( + IHost *pThis, + PRUint32 cpuId, + PRUint32 * speed + ); + + nsresult (*GetProcessorFeature)( + IHost *pThis, + PRUint32 feature, + PRBool * supported + ); + + nsresult (*GetProcessorDescription)( + IHost *pThis, + PRUint32 cpuId, + PRUnichar * * description + ); + + nsresult (*GetProcessorCPUIDLeaf)( + IHost *pThis, + PRUint32 cpuId, + PRUint32 leaf, + PRUint32 subLeaf, + PRUint32 * valEax, + PRUint32 * valEbx, + PRUint32 * valEcx, + PRUint32 * valEdx + ); + + nsresult (*CreateHostOnlyNetworkInterface)( + IHost *pThis, + IHostNetworkInterface * * hostInterface, + IProgress * * progress + ); + + nsresult (*RemoveHostOnlyNetworkInterface)( + IHost *pThis, + PRUnichar * id, + IProgress * * progress + ); + + nsresult (*CreateUSBDeviceFilter)( + IHost *pThis, + PRUnichar * name, + IHostUSBDeviceFilter * * filter + ); + + nsresult (*InsertUSBDeviceFilter)( + IHost *pThis, + PRUint32 position, + IHostUSBDeviceFilter * filter + ); + + nsresult (*RemoveUSBDeviceFilter)( + IHost *pThis, + PRUint32 position + ); + + nsresult (*FindHostDVDDrive)( + IHost *pThis, + PRUnichar * name, + IMedium * * drive + ); + + nsresult (*FindHostFloppyDrive)( + IHost *pThis, + PRUnichar * name, + IMedium * * drive + ); + + nsresult (*FindHostNetworkInterfaceByName)( + IHost *pThis, + PRUnichar * name, + IHostNetworkInterface * * networkInterface + ); + + nsresult (*FindHostNetworkInterfaceById)( + IHost *pThis, + PRUnichar * id, + IHostNetworkInterface * * networkInterface + ); + + nsresult (*FindHostNetworkInterfacesOfType)( + IHost *pThis, + PRUint32 type, + PRUint32 *networkInterfacesSize, + IHostNetworkInterface *** networkInterfaces + ); + + nsresult (*FindUSBDeviceById)( + IHost *pThis, + PRUnichar * id, + IHostUSBDevice * * device + ); + + nsresult (*FindUSBDeviceByAddress)( + IHost *pThis, + PRUnichar * name, + IHostUSBDevice * * device + ); + + nsresult (*GenerateMACAddress)( + IHost *pThis, + PRUnichar * * address + ); + +}; + +struct IHost +{ + struct IHost_vtbl *vtbl; +}; +/* End of struct IHost Declaration */ + + +/* Start of struct ISystemProperties Declaration */ +#define ISYSTEMPROPERTIES_IID_STR "1d7aca29-97f0-4287-9874-a60ec4f80ea6" +#define ISYSTEMPROPERTIES_IID { \ + 0x1d7aca29, 0x97f0, 0x4287, \ + { 0x98, 0x74, 0xa6, 0x0e, 0xc4, 0xf8, 0x0e, 0xa6 } \ +} +struct ISystemProperties_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMinGuestRAM)(ISystemProperties *pThis, PRUint32 *minGuestRAM); + + nsresult (*GetMaxGuestRAM)(ISystemProperties *pThis, PRUint32 *maxGuestRAM); + + nsresult (*GetMinGuestVRAM)(ISystemProperties *pThis, PRUint32 *minGuestVRAM); + + nsresult (*GetMaxGuestVRAM)(ISystemProperties *pThis, PRUint32 *maxGuestVRAM); + + nsresult (*GetMinGuestCPUCount)(ISystemProperties *pThis, PRUint32 *minGuestCPUCount); + + nsresult (*GetMaxGuestCPUCount)(ISystemProperties *pThis, PRUint32 *maxGuestCPUCount); + + nsresult (*GetMaxGuestMonitors)(ISystemProperties *pThis, PRUint32 *maxGuestMonitors); + + nsresult (*GetInfoVDSize)(ISystemProperties *pThis, PRInt64 *infoVDSize); + + nsresult (*GetSerialPortCount)(ISystemProperties *pThis, PRUint32 *serialPortCount); + + nsresult (*GetParallelPortCount)(ISystemProperties *pThis, PRUint32 *parallelPortCount); + + nsresult (*GetMaxBootPosition)(ISystemProperties *pThis, PRUint32 *maxBootPosition); + + nsresult (*GetDefaultMachineFolder)(ISystemProperties *pThis, PRUnichar * *defaultMachineFolder); + nsresult (*SetDefaultMachineFolder)(ISystemProperties *pThis, PRUnichar * defaultMachineFolder); + + nsresult (*GetMediumFormats)(ISystemProperties *pThis, PRUint32 *mediumFormatsSize, IMediumFormat * **mediumFormats); + + nsresult (*GetDefaultHardDiskFormat)(ISystemProperties *pThis, PRUnichar * *defaultHardDiskFormat); + nsresult (*SetDefaultHardDiskFormat)(ISystemProperties *pThis, PRUnichar * defaultHardDiskFormat); + + nsresult (*GetFreeDiskSpaceWarning)(ISystemProperties *pThis, PRInt64 *freeDiskSpaceWarning); + nsresult (*SetFreeDiskSpaceWarning)(ISystemProperties *pThis, PRInt64 freeDiskSpaceWarning); + + nsresult (*GetFreeDiskSpacePercentWarning)(ISystemProperties *pThis, PRUint32 *freeDiskSpacePercentWarning); + nsresult (*SetFreeDiskSpacePercentWarning)(ISystemProperties *pThis, PRUint32 freeDiskSpacePercentWarning); + + nsresult (*GetFreeDiskSpaceError)(ISystemProperties *pThis, PRInt64 *freeDiskSpaceError); + nsresult (*SetFreeDiskSpaceError)(ISystemProperties *pThis, PRInt64 freeDiskSpaceError); + + nsresult (*GetFreeDiskSpacePercentError)(ISystemProperties *pThis, PRUint32 *freeDiskSpacePercentError); + nsresult (*SetFreeDiskSpacePercentError)(ISystemProperties *pThis, PRUint32 freeDiskSpacePercentError); + + nsresult (*GetVRDEAuthLibrary)(ISystemProperties *pThis, PRUnichar * *VRDEAuthLibrary); + nsresult (*SetVRDEAuthLibrary)(ISystemProperties *pThis, PRUnichar * VRDEAuthLibrary); + + nsresult (*GetWebServiceAuthLibrary)(ISystemProperties *pThis, PRUnichar * *webServiceAuthLibrary); + nsresult (*SetWebServiceAuthLibrary)(ISystemProperties *pThis, PRUnichar * webServiceAuthLibrary); + + nsresult (*GetDefaultVRDEExtPack)(ISystemProperties *pThis, PRUnichar * *defaultVRDEExtPack); + nsresult (*SetDefaultVRDEExtPack)(ISystemProperties *pThis, PRUnichar * defaultVRDEExtPack); + + nsresult (*GetLogHistoryCount)(ISystemProperties *pThis, PRUint32 *logHistoryCount); + nsresult (*SetLogHistoryCount)(ISystemProperties *pThis, PRUint32 logHistoryCount); + + nsresult (*GetDefaultAudioDriver)(ISystemProperties *pThis, PRUint32 *defaultAudioDriver); + + nsresult (*GetAutostartDatabasePath)(ISystemProperties *pThis, PRUnichar * *autostartDatabasePath); + nsresult (*SetAutostartDatabasePath)(ISystemProperties *pThis, PRUnichar * autostartDatabasePath); + + nsresult (*GetDefaultAdditionsISO)(ISystemProperties *pThis, PRUnichar * *defaultAdditionsISO); + nsresult (*SetDefaultAdditionsISO)(ISystemProperties *pThis, PRUnichar * defaultAdditionsISO); + + nsresult (*GetMaxNetworkAdapters)( + ISystemProperties *pThis, + PRUint32 chipset, + PRUint32 * maxNetworkAdapters + ); + + nsresult (*GetMaxNetworkAdaptersOfType)( + ISystemProperties *pThis, + PRUint32 chipset, + PRUint32 type, + PRUint32 * maxNetworkAdapters + ); + + nsresult (*GetMaxDevicesPerPortForStorageBus)( + ISystemProperties *pThis, + PRUint32 bus, + PRUint32 * maxDevicesPerPort + ); + + nsresult (*GetMinPortCountForStorageBus)( + ISystemProperties *pThis, + PRUint32 bus, + PRUint32 * minPortCount + ); + + nsresult (*GetMaxPortCountForStorageBus)( + ISystemProperties *pThis, + PRUint32 bus, + PRUint32 * maxPortCount + ); + + nsresult (*GetMaxInstancesOfStorageBus)( + ISystemProperties *pThis, + PRUint32 chipset, + PRUint32 bus, + PRUint32 * maxInstances + ); + + nsresult (*GetDeviceTypesForStorageBus)( + ISystemProperties *pThis, + PRUint32 bus, + PRUint32 *deviceTypesSize, + PRUint32** deviceTypes + ); + + nsresult (*GetDefaultIoCacheSettingForStorageController)( + ISystemProperties *pThis, + PRUint32 controllerType, + PRBool * enabled + ); + +}; + +struct ISystemProperties +{ + struct ISystemProperties_vtbl *vtbl; +}; +/* End of struct ISystemProperties Declaration */ + + +/* Start of struct IGuestOSType Declaration */ +#define IGUESTOSTYPE_IID_STR "6d968f9a-858b-4c50-bf17-241f069e94c2" +#define IGUESTOSTYPE_IID { \ + 0x6d968f9a, 0x858b, 0x4c50, \ + { 0xbf, 0x17, 0x24, 0x1f, 0x06, 0x9e, 0x94, 0xc2 } \ +} +struct IGuestOSType_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetFamilyId)(IGuestOSType *pThis, PRUnichar * *familyId); + + nsresult (*GetFamilyDescription)(IGuestOSType *pThis, PRUnichar * *familyDescription); + + nsresult (*GetId)(IGuestOSType *pThis, PRUnichar * *id); + + nsresult (*GetDescription)(IGuestOSType *pThis, PRUnichar * *description); + + nsresult (*GetIs64Bit)(IGuestOSType *pThis, PRBool *is64Bit); + + nsresult (*GetRecommendedIOAPIC)(IGuestOSType *pThis, PRBool *recommendedIOAPIC); + + nsresult (*GetRecommendedVirtEx)(IGuestOSType *pThis, PRBool *recommendedVirtEx); + + nsresult (*GetRecommendedRAM)(IGuestOSType *pThis, PRUint32 *recommendedRAM); + + nsresult (*GetRecommendedVRAM)(IGuestOSType *pThis, PRUint32 *recommendedVRAM); + + nsresult (*GetRecommended2DVideoAcceleration)(IGuestOSType *pThis, PRBool *recommended2DVideoAcceleration); + + nsresult (*GetRecommended3DAcceleration)(IGuestOSType *pThis, PRBool *recommended3DAcceleration); + + nsresult (*GetRecommendedHDD)(IGuestOSType *pThis, PRInt64 *recommendedHDD); + + nsresult (*GetAdapterType)(IGuestOSType *pThis, PRUint32 *adapterType); + + nsresult (*GetRecommendedPAE)(IGuestOSType *pThis, PRBool *recommendedPAE); + + nsresult (*GetRecommendedDVDStorageController)(IGuestOSType *pThis, PRUint32 *recommendedDVDStorageController); + + nsresult (*GetRecommendedDVDStorageBus)(IGuestOSType *pThis, PRUint32 *recommendedDVDStorageBus); + + nsresult (*GetRecommendedHDStorageController)(IGuestOSType *pThis, PRUint32 *recommendedHDStorageController); + + nsresult (*GetRecommendedHDStorageBus)(IGuestOSType *pThis, PRUint32 *recommendedHDStorageBus); + + nsresult (*GetRecommendedFirmware)(IGuestOSType *pThis, PRUint32 *recommendedFirmware); + + nsresult (*GetRecommendedUSBHID)(IGuestOSType *pThis, PRBool *recommendedUSBHID); + + nsresult (*GetRecommendedHPET)(IGuestOSType *pThis, PRBool *recommendedHPET); + + nsresult (*GetRecommendedUSBTablet)(IGuestOSType *pThis, PRBool *recommendedUSBTablet); + + nsresult (*GetRecommendedRTCUseUTC)(IGuestOSType *pThis, PRBool *recommendedRTCUseUTC); + + nsresult (*GetRecommendedChipset)(IGuestOSType *pThis, PRUint32 *recommendedChipset); + + nsresult (*GetRecommendedAudioController)(IGuestOSType *pThis, PRUint32 *recommendedAudioController); + + nsresult (*GetRecommendedFloppy)(IGuestOSType *pThis, PRBool *recommendedFloppy); + + nsresult (*GetRecommendedUSB)(IGuestOSType *pThis, PRBool *recommendedUSB); + +}; + +struct IGuestOSType +{ + struct IGuestOSType_vtbl *vtbl; +}; +/* End of struct IGuestOSType Declaration */ + + +/* Start of struct IAdditionsFacility Declaration */ +#define IADDITIONSFACILITY_IID_STR "54992946-6af1-4e49-98ec-58b558b7291e" +#define IADDITIONSFACILITY_IID { \ + 0x54992946, 0x6af1, 0x4e49, \ + { 0x98, 0xec, 0x58, 0xb5, 0x58, 0xb7, 0x29, 0x1e } \ +} +struct IAdditionsFacility_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetClassType)(IAdditionsFacility *pThis, PRUint32 *classType); + + nsresult (*GetLastUpdated)(IAdditionsFacility *pThis, PRInt64 *lastUpdated); + + nsresult (*GetName)(IAdditionsFacility *pThis, PRUnichar * *name); + + nsresult (*GetStatus)(IAdditionsFacility *pThis, PRUint32 *status); + + nsresult (*GetType)(IAdditionsFacility *pThis, PRUint32 *type); + +}; + +struct IAdditionsFacility +{ + struct IAdditionsFacility_vtbl *vtbl; +}; +/* End of struct IAdditionsFacility Declaration */ + + +/* Start of struct IGuestSession Declaration */ +#define IGUESTSESSION_IID_STR "57eb82a8-822b-42c1-9d1c-5c54bc3d3250" +#define IGUESTSESSION_IID { \ + 0x57eb82a8, 0x822b, 0x42c1, \ + { 0x9d, 0x1c, 0x5c, 0x54, 0xbc, 0x3d, 0x32, 0x50 } \ +} +struct IGuestSession_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetUser)(IGuestSession *pThis, PRUnichar * *user); + + nsresult (*GetDomain)(IGuestSession *pThis, PRUnichar * *domain); + + nsresult (*GetName)(IGuestSession *pThis, PRUnichar * *name); + + nsresult (*GetId)(IGuestSession *pThis, PRUint32 *id); + + nsresult (*GetTimeout)(IGuestSession *pThis, PRUint32 *timeout); + nsresult (*SetTimeout)(IGuestSession *pThis, PRUint32 timeout); + + nsresult (*GetEnvironment)(IGuestSession *pThis, PRUint32 *environmentSize, PRUnichar * **environment); + nsresult (*SetEnvironment)(IGuestSession *pThis, PRUint32 environmentSize, PRUnichar * *environment); + + nsresult (*GetProcesses)(IGuestSession *pThis, PRUint32 *processesSize, IGuestProcess * **processes); + + nsresult (*GetDirectories)(IGuestSession *pThis, PRUint32 *directoriesSize, IGuestDirectory * **directories); + + nsresult (*GetFiles)(IGuestSession *pThis, PRUint32 *filesSize, IGuestFile * **files); + + nsresult (*Close)(IGuestSession *pThis ); + + nsresult (*CopyFrom)( + IGuestSession *pThis, + PRUnichar * source, + PRUnichar * dest, + PRUint32 flagsSize, + PRUint32* flags, + IProgress * * progress + ); + + nsresult (*CopyTo)( + IGuestSession *pThis, + PRUnichar * source, + PRUnichar * dest, + PRUint32 flagsSize, + PRUint32* flags, + IProgress * * progress + ); + + nsresult (*DirectoryCreate)( + IGuestSession *pThis, + PRUnichar * path, + PRUint32 mode, + PRUint32 flagsSize, + PRUint32* flags + ); + + nsresult (*DirectoryCreateTemp)( + IGuestSession *pThis, + PRUnichar * templateName, + PRUint32 mode, + PRUnichar * path, + PRBool secure, + PRUnichar * * directory + ); + + nsresult (*DirectoryExists)( + IGuestSession *pThis, + PRUnichar * path, + PRBool * exists + ); + + nsresult (*DirectoryOpen)( + IGuestSession *pThis, + PRUnichar * path, + PRUnichar * filter, + PRUint32 flagsSize, + PRUint32* flags, + IGuestDirectory * * directory + ); + + nsresult (*DirectoryQueryInfo)( + IGuestSession *pThis, + PRUnichar * path, + IGuestFsObjInfo * * info + ); + + nsresult (*DirectoryRemove)( + IGuestSession *pThis, + PRUnichar * path + ); + + nsresult (*DirectoryRemoveRecursive)( + IGuestSession *pThis, + PRUnichar * path, + PRUint32 flagsSize, + PRUint32* flags, + IProgress * * progress + ); + + nsresult (*DirectoryRename)( + IGuestSession *pThis, + PRUnichar * source, + PRUnichar * dest, + PRUint32 flagsSize, + PRUint32* flags + ); + + nsresult (*DirectorySetACL)( + IGuestSession *pThis, + PRUnichar * path, + PRUnichar * acl + ); + + nsresult (*EnvironmentClear)(IGuestSession *pThis ); + + nsresult (*EnvironmentGet)( + IGuestSession *pThis, + PRUnichar * name, + PRUnichar * * value + ); + + nsresult (*EnvironmentSet)( + IGuestSession *pThis, + PRUnichar * name, + PRUnichar * value + ); + + nsresult (*EnvironmentUnset)( + IGuestSession *pThis, + PRUnichar * name + ); + + nsresult (*FileCreateTemp)( + IGuestSession *pThis, + PRUnichar * templateName, + PRUint32 mode, + PRUnichar * path, + PRBool secure, + IGuestFile * * file + ); + + nsresult (*FileExists)( + IGuestSession *pThis, + PRUnichar * path, + PRBool * exists + ); + + nsresult (*FileRemove)( + IGuestSession *pThis, + PRUnichar * path + ); + + nsresult (*FileOpen)( + IGuestSession *pThis, + PRUnichar * path, + PRUnichar * openMode, + PRUnichar * disposition, + PRUint32 creationMode, + PRInt64 offset, + IGuestFile * * file + ); + + nsresult (*FileQueryInfo)( + IGuestSession *pThis, + PRUnichar * path, + IGuestFsObjInfo * * info + ); + + nsresult (*FileQuerySize)( + IGuestSession *pThis, + PRUnichar * path, + PRInt64 * size + ); + + nsresult (*FileRename)( + IGuestSession *pThis, + PRUnichar * source, + PRUnichar * dest, + PRUint32 flagsSize, + PRUint32* flags + ); + + nsresult (*FileSetACL)( + IGuestSession *pThis, + PRUnichar * file, + PRUnichar * acl + ); + + nsresult (*ProcessCreate)( + IGuestSession *pThis, + PRUnichar * command, + PRUint32 argumentsSize, + PRUnichar ** arguments, + PRUint32 environmentSize, + PRUnichar ** environment, + PRUint32 flagsSize, + PRUint32* flags, + PRUint32 timeoutMS, + IGuestProcess * * guestProcess + ); + + nsresult (*ProcessCreateEx)( + IGuestSession *pThis, + PRUnichar * command, + PRUint32 argumentsSize, + PRUnichar ** arguments, + PRUint32 environmentSize, + PRUnichar ** environment, + PRUint32 flagsSize, + PRUint32* flags, + PRUint32 timeoutMS, + PRUint32 priority, + PRUint32 affinitySize, + PRInt32* affinity, + IGuestProcess * * guestProcess + ); + + nsresult (*ProcessGet)( + IGuestSession *pThis, + PRUint32 pid, + IGuestProcess * * guestProcess + ); + + nsresult (*SymlinkCreate)( + IGuestSession *pThis, + PRUnichar * source, + PRUnichar * target, + PRUint32 type + ); + + nsresult (*SymlinkExists)( + IGuestSession *pThis, + PRUnichar * symlink, + PRBool * exists + ); + + nsresult (*SymlinkRead)( + IGuestSession *pThis, + PRUnichar * symlink, + PRUint32 flagsSize, + PRUint32* flags, + PRUnichar * * target + ); + + nsresult (*SymlinkRemoveDirectory)( + IGuestSession *pThis, + PRUnichar * path + ); + + nsresult (*SymlinkRemoveFile)( + IGuestSession *pThis, + PRUnichar * file + ); + +}; + +struct IGuestSession +{ + struct IGuestSession_vtbl *vtbl; +}; +/* End of struct IGuestSession Declaration */ + + +/* Start of struct IProcess Declaration */ +#define IPROCESS_IID_STR "08864d56-96ab-418b-adbc-5a679532aeb0" +#define IPROCESS_IID { \ + 0x08864d56, 0x96ab, 0x418b, \ + { 0xad, 0xbc, 0x5a, 0x67, 0x95, 0x32, 0xae, 0xb0 } \ +} +struct IProcess_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetPID)(IProcess *pThis, PRUint32 *PID); + + nsresult (*GetStatus)(IProcess *pThis, PRUint32 *status); + + nsresult (*GetExitCode)(IProcess *pThis, PRInt32 *exitCode); + + nsresult (*GetEnvironment)(IProcess *pThis, PRUint32 *environmentSize, PRUnichar * **environment); + + nsresult (*GetArguments)(IProcess *pThis, PRUint32 *argumentsSize, PRUnichar * **arguments); + + nsresult (*GetExecutablePath)(IProcess *pThis, PRUnichar * *executablePath); + + nsresult (*GetName)(IProcess *pThis, PRUnichar * *name); + + nsresult (*WaitFor)( + IProcess *pThis, + PRUint32 waitFor, + PRUint32 timeoutMS, + PRUint32 * reason + ); + + nsresult (*WaitForArray)( + IProcess *pThis, + PRUint32 waitForSize, + PRUint32* waitFor, + PRUint32 timeoutMS, + PRUint32 * reason + ); + + nsresult (*Read)( + IProcess *pThis, + PRUint32 handle, + PRUint32 toRead, + PRUint32 timeoutMS, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*Write)( + IProcess *pThis, + PRUint32 handle, + PRUint32 flags, + PRUint32 dataSize, + PRUint8* data, + PRUint32 timeoutMS, + PRUint32 * written + ); + + nsresult (*WriteArray)( + IProcess *pThis, + PRUint32 handle, + PRUint32 flagsSize, + PRUint32* flags, + PRUint32 dataSize, + PRUint8* data, + PRUint32 timeoutMS, + PRUint32 * written + ); + + nsresult (*Terminate)(IProcess *pThis ); + +}; + +struct IProcess +{ + struct IProcess_vtbl *vtbl; +}; +/* End of struct IProcess Declaration */ + + +/* Start of struct IGuestProcess Declaration */ +#define IGUESTPROCESS_IID_STR "dfa39a36-5d43-4840-a025-67ea956b3111" +#define IGUESTPROCESS_IID { \ + 0xdfa39a36, 0x5d43, 0x4840, \ + { 0xa0, 0x25, 0x67, 0xea, 0x95, 0x6b, 0x31, 0x11 } \ +} +struct IGuestProcess_vtbl +{ + struct IProcess_vtbl iprocess; + +}; + +struct IGuestProcess +{ + struct IGuestProcess_vtbl *vtbl; +}; +/* End of struct IGuestProcess Declaration */ + + +/* Start of struct IDirectory Declaration */ +#define IDIRECTORY_IID_STR "1b70dd03-26d7-483a-8877-89bbb0f87b70" +#define IDIRECTORY_IID { \ + 0x1b70dd03, 0x26d7, 0x483a, \ + { 0x88, 0x77, 0x89, 0xbb, 0xb0, 0xf8, 0x7b, 0x70 } \ +} +struct IDirectory_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetDirectoryName)(IDirectory *pThis, PRUnichar * *directoryName); + + nsresult (*GetFilter)(IDirectory *pThis, PRUnichar * *filter); + + nsresult (*Close)(IDirectory *pThis ); + + nsresult (*Read)( + IDirectory *pThis, + IFsObjInfo * * objInfo + ); + +}; + +struct IDirectory +{ + struct IDirectory_vtbl *vtbl; +}; +/* End of struct IDirectory Declaration */ + + +/* Start of struct IGuestDirectory Declaration */ +#define IGUESTDIRECTORY_IID_STR "af4a8ce0-0725-42b7-8826-46e3c7ba7357" +#define IGUESTDIRECTORY_IID { \ + 0xaf4a8ce0, 0x0725, 0x42b7, \ + { 0x88, 0x26, 0x46, 0xe3, 0xc7, 0xba, 0x73, 0x57 } \ +} +struct IGuestDirectory_vtbl +{ + struct IDirectory_vtbl idirectory; + +}; + +struct IGuestDirectory +{ + struct IGuestDirectory_vtbl *vtbl; +}; +/* End of struct IGuestDirectory Declaration */ + + +/* Start of struct IFile Declaration */ +#define IFILE_IID_STR "b702a560-6139-4a8e-a892-bbf14b97bf97" +#define IFILE_IID { \ + 0xb702a560, 0x6139, 0x4a8e, \ + { 0xa8, 0x92, 0xbb, 0xf1, 0x4b, 0x97, 0xbf, 0x97 } \ +} +struct IFile_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetCreationMode)(IFile *pThis, PRUint32 *creationMode); + + nsresult (*GetDisposition)(IFile *pThis, PRUint32 *disposition); + + nsresult (*GetFileName)(IFile *pThis, PRUnichar * *fileName); + + nsresult (*GetInitialSize)(IFile *pThis, PRInt64 *initialSize); + + nsresult (*GetOpenMode)(IFile *pThis, PRUint32 *openMode); + + nsresult (*GetOffset)(IFile *pThis, PRInt64 *offset); + + nsresult (*Close)(IFile *pThis ); + + nsresult (*QueryInfo)( + IFile *pThis, + IFsObjInfo * * objInfo + ); + + nsresult (*Read)( + IFile *pThis, + PRUint32 toRead, + PRUint32 timeoutMS, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*ReadAt)( + IFile *pThis, + PRInt64 offset, + PRUint32 toRead, + PRUint32 timeoutMS, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*Seek)( + IFile *pThis, + PRInt64 offset, + PRUint32 whence + ); + + nsresult (*SetACL)( + IFile *pThis, + PRUnichar * acl + ); + + nsresult (*Write)( + IFile *pThis, + PRUint32 dataSize, + PRUint8* data, + PRUint32 timeoutMS, + PRUint32 * written + ); + + nsresult (*WriteAt)( + IFile *pThis, + PRInt64 offset, + PRUint32 dataSize, + PRUint8* data, + PRUint32 timeoutMS, + PRUint32 * written + ); + +}; + +struct IFile +{ + struct IFile_vtbl *vtbl; +}; +/* End of struct IFile Declaration */ + + +/* Start of struct IGuestFile Declaration */ +#define IGUESTFILE_IID_STR "60661aec-145f-4d11-b80e-8ea151598093" +#define IGUESTFILE_IID { \ + 0x60661aec, 0x145f, 0x4d11, \ + { 0xb8, 0x0e, 0x8e, 0xa1, 0x51, 0x59, 0x80, 0x93 } \ +} +struct IGuestFile_vtbl +{ + struct IFile_vtbl ifile; + +}; + +struct IGuestFile +{ + struct IGuestFile_vtbl *vtbl; +}; +/* End of struct IGuestFile Declaration */ + + +/* Start of struct IFsObjInfo Declaration */ +#define IFSOBJINFO_IID_STR "4047ba30-7006-4966-ae86-94164e5e20eb" +#define IFSOBJINFO_IID { \ + 0x4047ba30, 0x7006, 0x4966, \ + { 0xae, 0x86, 0x94, 0x16, 0x4e, 0x5e, 0x20, 0xeb } \ +} +struct IFsObjInfo_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetAccessTime)(IFsObjInfo *pThis, PRInt64 *accessTime); + + nsresult (*GetAllocatedSize)(IFsObjInfo *pThis, PRInt64 *allocatedSize); + + nsresult (*GetBirthTime)(IFsObjInfo *pThis, PRInt64 *birthTime); + + nsresult (*GetChangeTime)(IFsObjInfo *pThis, PRInt64 *changeTime); + + nsresult (*GetDeviceNumber)(IFsObjInfo *pThis, PRUint32 *deviceNumber); + + nsresult (*GetFileAttributes)(IFsObjInfo *pThis, PRUnichar * *fileAttributes); + + nsresult (*GetGenerationId)(IFsObjInfo *pThis, PRUint32 *generationId); + + nsresult (*GetGID)(IFsObjInfo *pThis, PRUint32 *GID); + + nsresult (*GetGroupName)(IFsObjInfo *pThis, PRUnichar * *groupName); + + nsresult (*GetHardLinks)(IFsObjInfo *pThis, PRUint32 *hardLinks); + + nsresult (*GetModificationTime)(IFsObjInfo *pThis, PRInt64 *modificationTime); + + nsresult (*GetName)(IFsObjInfo *pThis, PRUnichar * *name); + + nsresult (*GetNodeId)(IFsObjInfo *pThis, PRInt64 *nodeId); + + nsresult (*GetNodeIdDevice)(IFsObjInfo *pThis, PRUint32 *nodeIdDevice); + + nsresult (*GetObjectSize)(IFsObjInfo *pThis, PRInt64 *objectSize); + + nsresult (*GetType)(IFsObjInfo *pThis, PRUint32 *type); + + nsresult (*GetUID)(IFsObjInfo *pThis, PRUint32 *UID); + + nsresult (*GetUserFlags)(IFsObjInfo *pThis, PRUint32 *userFlags); + + nsresult (*GetUserName)(IFsObjInfo *pThis, PRUnichar * *userName); + +}; + +struct IFsObjInfo +{ + struct IFsObjInfo_vtbl *vtbl; +}; +/* End of struct IFsObjInfo Declaration */ + + +/* Start of struct IGuestFsObjInfo Declaration */ +#define IGUESTFSOBJINFO_IID_STR "d5cf678e-3484-4e4a-ac55-329e15462e18" +#define IGUESTFSOBJINFO_IID { \ + 0xd5cf678e, 0x3484, 0x4e4a, \ + { 0xac, 0x55, 0x32, 0x9e, 0x15, 0x46, 0x2e, 0x18 } \ +} +struct IGuestFsObjInfo_vtbl +{ + struct IFsObjInfo_vtbl ifsobjinfo; + +}; + +struct IGuestFsObjInfo +{ + struct IGuestFsObjInfo_vtbl *vtbl; +}; +/* End of struct IGuestFsObjInfo Declaration */ + + +/* Start of struct IGuest Declaration */ +#define IGUEST_IID_STR "19c32350-0618-4ede-b0c3-2b4311bf0d9b" +#define IGUEST_IID { \ + 0x19c32350, 0x0618, 0x4ede, \ + { 0xb0, 0xc3, 0x2b, 0x43, 0x11, 0xbf, 0x0d, 0x9b } \ +} +struct IGuest_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetOSTypeId)(IGuest *pThis, PRUnichar * *OSTypeId); + + nsresult (*GetAdditionsRunLevel)(IGuest *pThis, PRUint32 *additionsRunLevel); + + nsresult (*GetAdditionsVersion)(IGuest *pThis, PRUnichar * *additionsVersion); + + nsresult (*GetAdditionsRevision)(IGuest *pThis, PRUint32 *additionsRevision); + + nsresult (*GetFacilities)(IGuest *pThis, PRUint32 *facilitiesSize, IAdditionsFacility * **facilities); + + nsresult (*GetSessions)(IGuest *pThis, PRUint32 *sessionsSize, IGuestSession * **sessions); + + nsresult (*GetMemoryBalloonSize)(IGuest *pThis, PRUint32 *memoryBalloonSize); + nsresult (*SetMemoryBalloonSize)(IGuest *pThis, PRUint32 memoryBalloonSize); + + nsresult (*GetStatisticsUpdateInterval)(IGuest *pThis, PRUint32 *statisticsUpdateInterval); + nsresult (*SetStatisticsUpdateInterval)(IGuest *pThis, PRUint32 statisticsUpdateInterval); + + nsresult (*InternalGetStatistics)( + IGuest *pThis, + PRUint32 * cpuUser, + PRUint32 * cpuKernel, + PRUint32 * cpuIdle, + PRUint32 * memTotal, + PRUint32 * memFree, + PRUint32 * memBalloon, + PRUint32 * memShared, + PRUint32 * memCache, + PRUint32 * pagedTotal, + PRUint32 * memAllocTotal, + PRUint32 * memFreeTotal, + PRUint32 * memBalloonTotal, + PRUint32 * memSharedTotal + ); + + nsresult (*GetFacilityStatus)( + IGuest *pThis, + PRUint32 facility, + PRInt64 * timestamp, + PRUint32 * status + ); + + nsresult (*GetAdditionsStatus)( + IGuest *pThis, + PRUint32 level, + PRBool * active + ); + + nsresult (*SetCredentials)( + IGuest *pThis, + PRUnichar * userName, + PRUnichar * password, + PRUnichar * domain, + PRBool allowInteractiveLogon + ); + + nsresult (*DragHGEnter)( + IGuest *pThis, + PRUint32 screenId, + PRUint32 y, + PRUint32 x, + PRUint32 defaultAction, + PRUint32 allowedActionsSize, + PRUint32* allowedActions, + PRUint32 formatsSize, + PRUnichar ** formats, + PRUint32 * resultAction + ); + + nsresult (*DragHGMove)( + IGuest *pThis, + PRUint32 screenId, + PRUint32 x, + PRUint32 y, + PRUint32 defaultAction, + PRUint32 allowedActionsSize, + PRUint32* allowedActions, + PRUint32 formatsSize, + PRUnichar ** formats, + PRUint32 * resultAction + ); + + nsresult (*DragHGLeave)( + IGuest *pThis, + PRUint32 screenId + ); + + nsresult (*DragHGDrop)( + IGuest *pThis, + PRUint32 screenId, + PRUint32 x, + PRUint32 y, + PRUint32 defaultAction, + PRUint32 allowedActionsSize, + PRUint32* allowedActions, + PRUint32 formatsSize, + PRUnichar ** formats, + PRUnichar * * format, + PRUint32 * resultAction + ); + + nsresult (*DragHGPutData)( + IGuest *pThis, + PRUint32 screenId, + PRUnichar * format, + PRUint32 dataSize, + PRUint8* data, + IProgress * * progress + ); + + nsresult (*DragGHPending)( + IGuest *pThis, + PRUint32 screenId, + PRUint32 *formatSize, + PRUnichar *** format, + PRUint32 *allowedActionsSize, + PRUint32** allowedActions, + PRUint32 * defaultAction + ); + + nsresult (*DragGHDropped)( + IGuest *pThis, + PRUnichar * format, + PRUint32 action, + IProgress * * progress + ); + + nsresult (*DragGHGetData)( + IGuest *pThis, + PRUint32 *dataSize, + PRUint8** data + ); + + nsresult (*CreateSession)( + IGuest *pThis, + PRUnichar * user, + PRUnichar * password, + PRUnichar * domain, + PRUnichar * sessionName, + IGuestSession * * guestSession + ); + + nsresult (*FindSession)( + IGuest *pThis, + PRUnichar * sessionName, + PRUint32 *sessionsSize, + IGuestSession *** sessions + ); + + nsresult (*UpdateGuestAdditions)( + IGuest *pThis, + PRUnichar * source, + PRUint32 flagsSize, + PRUint32* flags, + IProgress * * progress + ); + +}; + +struct IGuest +{ + struct IGuest_vtbl *vtbl; +}; +/* End of struct IGuest Declaration */ + + +/* Start of struct IProgress Declaration */ +#define IPROGRESS_IID_STR "c20238e4-3221-4d3f-8891-81ce92d9f913" +#define IPROGRESS_IID { \ + 0xc20238e4, 0x3221, 0x4d3f, \ + { 0x88, 0x91, 0x81, 0xce, 0x92, 0xd9, 0xf9, 0x13 } \ +} +struct IProgress_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetId)(IProgress *pThis, PRUnichar * *id); + + nsresult (*GetDescription)(IProgress *pThis, PRUnichar * *description); + + nsresult (*GetInitiator)(IProgress *pThis, nsISupports * *initiator); + + nsresult (*GetCancelable)(IProgress *pThis, PRBool *cancelable); + + nsresult (*GetPercent)(IProgress *pThis, PRUint32 *percent); + + nsresult (*GetTimeRemaining)(IProgress *pThis, PRInt32 *timeRemaining); + + nsresult (*GetCompleted)(IProgress *pThis, PRBool *completed); + + nsresult (*GetCanceled)(IProgress *pThis, PRBool *canceled); + + nsresult (*GetResultCode)(IProgress *pThis, PRInt32 *resultCode); + + nsresult (*GetErrorInfo)(IProgress *pThis, IVirtualBoxErrorInfo * *errorInfo); + + nsresult (*GetOperationCount)(IProgress *pThis, PRUint32 *operationCount); + + nsresult (*GetOperation)(IProgress *pThis, PRUint32 *operation); + + nsresult (*GetOperationDescription)(IProgress *pThis, PRUnichar * *operationDescription); + + nsresult (*GetOperationPercent)(IProgress *pThis, PRUint32 *operationPercent); + + nsresult (*GetOperationWeight)(IProgress *pThis, PRUint32 *operationWeight); + + nsresult (*GetTimeout)(IProgress *pThis, PRUint32 *timeout); + nsresult (*SetTimeout)(IProgress *pThis, PRUint32 timeout); + + nsresult (*SetCurrentOperationProgress)( + IProgress *pThis, + PRUint32 percent + ); + + nsresult (*SetNextOperation)( + IProgress *pThis, + PRUnichar * nextOperationDescription, + PRUint32 nextOperationsWeight + ); + + nsresult (*WaitForCompletion)( + IProgress *pThis, + PRInt32 timeout + ); + + nsresult (*WaitForOperationCompletion)( + IProgress *pThis, + PRUint32 operation, + PRInt32 timeout + ); + + nsresult (*WaitForAsyncProgressCompletion)( + IProgress *pThis, + IProgress * pProgressAsync + ); + + nsresult (*Cancel)(IProgress *pThis ); + +}; + +struct IProgress +{ + struct IProgress_vtbl *vtbl; +}; +/* End of struct IProgress Declaration */ + + +/* Start of struct ISnapshot Declaration */ +#define ISNAPSHOT_IID_STR "0472823b-c6e7-472a-8e9f-d732e86b8463" +#define ISNAPSHOT_IID { \ + 0x0472823b, 0xc6e7, 0x472a, \ + { 0x8e, 0x9f, 0xd7, 0x32, 0xe8, 0x6b, 0x84, 0x63 } \ +} +struct ISnapshot_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetId)(ISnapshot *pThis, PRUnichar * *id); + + nsresult (*GetName)(ISnapshot *pThis, PRUnichar * *name); + nsresult (*SetName)(ISnapshot *pThis, PRUnichar * name); + + nsresult (*GetDescription)(ISnapshot *pThis, PRUnichar * *description); + nsresult (*SetDescription)(ISnapshot *pThis, PRUnichar * description); + + nsresult (*GetTimeStamp)(ISnapshot *pThis, PRInt64 *timeStamp); + + nsresult (*GetOnline)(ISnapshot *pThis, PRBool *online); + + nsresult (*GetMachine)(ISnapshot *pThis, IMachine * *machine); + + nsresult (*GetParent)(ISnapshot *pThis, ISnapshot * *parent); + + nsresult (*GetChildren)(ISnapshot *pThis, PRUint32 *childrenSize, ISnapshot * **children); + + nsresult (*GetChildrenCount)( + ISnapshot *pThis, + PRUint32 * childrenCount + ); + +}; + +struct ISnapshot +{ + struct ISnapshot_vtbl *vtbl; +}; +/* End of struct ISnapshot Declaration */ + + +/* Start of struct IMediumAttachment Declaration */ +#define IMEDIUMATTACHMENT_IID_STR "5ee464d6-0613-4331-b154-7ce12170ef9f" +#define IMEDIUMATTACHMENT_IID { \ + 0x5ee464d6, 0x0613, 0x4331, \ + { 0xb1, 0x54, 0x7c, 0xe1, 0x21, 0x70, 0xef, 0x9f } \ +} +struct IMediumAttachment_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMedium)(IMediumAttachment *pThis, IMedium * *medium); + + nsresult (*GetController)(IMediumAttachment *pThis, PRUnichar * *controller); + + nsresult (*GetPort)(IMediumAttachment *pThis, PRInt32 *port); + + nsresult (*GetDevice)(IMediumAttachment *pThis, PRInt32 *device); + + nsresult (*GetType)(IMediumAttachment *pThis, PRUint32 *type); + + nsresult (*GetPassthrough)(IMediumAttachment *pThis, PRBool *passthrough); + + nsresult (*GetTemporaryEject)(IMediumAttachment *pThis, PRBool *temporaryEject); + + nsresult (*GetIsEjected)(IMediumAttachment *pThis, PRBool *isEjected); + + nsresult (*GetNonRotational)(IMediumAttachment *pThis, PRBool *nonRotational); + + nsresult (*GetDiscard)(IMediumAttachment *pThis, PRBool *discard); + + nsresult (*GetBandwidthGroup)(IMediumAttachment *pThis, IBandwidthGroup * *bandwidthGroup); + +}; + +struct IMediumAttachment +{ + struct IMediumAttachment_vtbl *vtbl; +}; +/* End of struct IMediumAttachment Declaration */ + + +/* Start of struct IMedium Declaration */ +#define IMEDIUM_IID_STR "29989373-b111-4654-8493-2e1176cba890" +#define IMEDIUM_IID { \ + 0x29989373, 0xb111, 0x4654, \ + { 0x84, 0x93, 0x2e, 0x11, 0x76, 0xcb, 0xa8, 0x90 } \ +} +struct IMedium_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetId)(IMedium *pThis, PRUnichar * *id); + + nsresult (*GetDescription)(IMedium *pThis, PRUnichar * *description); + nsresult (*SetDescription)(IMedium *pThis, PRUnichar * description); + + nsresult (*GetState)(IMedium *pThis, PRUint32 *state); + + nsresult (*GetVariant)(IMedium *pThis, PRUint32 *variant); + + nsresult (*GetLocation)(IMedium *pThis, PRUnichar * *location); + nsresult (*SetLocation)(IMedium *pThis, PRUnichar * location); + + nsresult (*GetName)(IMedium *pThis, PRUnichar * *name); + + nsresult (*GetDeviceType)(IMedium *pThis, PRUint32 *deviceType); + + nsresult (*GetHostDrive)(IMedium *pThis, PRBool *hostDrive); + + nsresult (*GetSize)(IMedium *pThis, PRInt64 *size); + + nsresult (*GetFormat)(IMedium *pThis, PRUnichar * *format); + + nsresult (*GetMediumFormat)(IMedium *pThis, IMediumFormat * *mediumFormat); + + nsresult (*GetType)(IMedium *pThis, PRUint32 *type); + nsresult (*SetType)(IMedium *pThis, PRUint32 type); + + nsresult (*GetAllowedTypes)(IMedium *pThis, PRUint32 *allowedTypesSize, PRUint32 **allowedTypes); + + nsresult (*GetParent)(IMedium *pThis, IMedium * *parent); + + nsresult (*GetChildren)(IMedium *pThis, PRUint32 *childrenSize, IMedium * **children); + + nsresult (*GetBase)(IMedium *pThis, IMedium * *base); + + nsresult (*GetReadOnly)(IMedium *pThis, PRBool *readOnly); + + nsresult (*GetLogicalSize)(IMedium *pThis, PRInt64 *logicalSize); + + nsresult (*GetAutoReset)(IMedium *pThis, PRBool *autoReset); + nsresult (*SetAutoReset)(IMedium *pThis, PRBool autoReset); + + nsresult (*GetLastAccessError)(IMedium *pThis, PRUnichar * *lastAccessError); + + nsresult (*GetMachineIds)(IMedium *pThis, PRUint32 *machineIdsSize, PRUnichar * **machineIds); + + nsresult (*SetIds)( + IMedium *pThis, + PRBool setImageId, + PRUnichar * imageId, + PRBool setParentId, + PRUnichar * parentId + ); + + nsresult (*RefreshState)( + IMedium *pThis, + PRUint32 * state + ); + + nsresult (*GetSnapshotIds)( + IMedium *pThis, + PRUnichar * machineId, + PRUint32 *snapshotIdsSize, + PRUnichar *** snapshotIds + ); + + nsresult (*LockRead)( + IMedium *pThis, + PRUint32 * state + ); + + nsresult (*UnlockRead)( + IMedium *pThis, + PRUint32 * state + ); + + nsresult (*LockWrite)( + IMedium *pThis, + PRUint32 * state + ); + + nsresult (*UnlockWrite)( + IMedium *pThis, + PRUint32 * state + ); + + nsresult (*Close)(IMedium *pThis ); + + nsresult (*GetProperty)( + IMedium *pThis, + PRUnichar * name, + PRUnichar * * value + ); + + nsresult (*SetProperty)( + IMedium *pThis, + PRUnichar * name, + PRUnichar * value + ); + + nsresult (*GetProperties)( + IMedium *pThis, + PRUnichar * names, + PRUint32 *returnNamesSize, + PRUnichar *** returnNames, + PRUint32 *returnValuesSize, + PRUnichar *** returnValues + ); + + nsresult (*SetProperties)( + IMedium *pThis, + PRUint32 namesSize, + PRUnichar ** names, + PRUint32 valuesSize, + PRUnichar ** values + ); + + nsresult (*CreateBaseStorage)( + IMedium *pThis, + PRInt64 logicalSize, + PRUint32 variant, + IProgress * * progress + ); + + nsresult (*DeleteStorage)( + IMedium *pThis, + IProgress * * progress + ); + + nsresult (*CreateDiffStorage)( + IMedium *pThis, + IMedium * target, + PRUint32 variant, + IProgress * * progress + ); + + nsresult (*MergeTo)( + IMedium *pThis, + IMedium * target, + IProgress * * progress + ); + + nsresult (*CloneTo)( + IMedium *pThis, + IMedium * target, + PRUint32 variant, + IMedium * parent, + IProgress * * progress + ); + + nsresult (*CloneToBase)( + IMedium *pThis, + IMedium * target, + PRUint32 variant, + IProgress * * progress + ); + + nsresult (*Compact)( + IMedium *pThis, + IProgress * * progress + ); + + nsresult (*Resize)( + IMedium *pThis, + PRInt64 logicalSize, + IProgress * * progress + ); + + nsresult (*Reset)( + IMedium *pThis, + IProgress * * progress + ); + +}; + +struct IMedium +{ + struct IMedium_vtbl *vtbl; +}; +/* End of struct IMedium Declaration */ + + +/* Start of struct IMediumFormat Declaration */ +#define IMEDIUMFORMAT_IID_STR "9bd5b655-ea47-4637-99f3-aad0948be35b" +#define IMEDIUMFORMAT_IID { \ + 0x9bd5b655, 0xea47, 0x4637, \ + { 0x99, 0xf3, 0xaa, 0xd0, 0x94, 0x8b, 0xe3, 0x5b } \ +} +struct IMediumFormat_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetId)(IMediumFormat *pThis, PRUnichar * *id); + + nsresult (*GetName)(IMediumFormat *pThis, PRUnichar * *name); + + nsresult (*GetCapabilities)(IMediumFormat *pThis, PRUint32 *capabilities); + + nsresult (*DescribeFileExtensions)( + IMediumFormat *pThis, + PRUint32 *extensionsSize, + PRUnichar *** extensions, + PRUint32 *typeSize, + PRUint32** type + ); + + nsresult (*DescribeProperties)( + IMediumFormat *pThis, + PRUint32 *namesSize, + PRUnichar *** names, + PRUint32 *descriptionSize, + PRUnichar *** description, + PRUint32 *typesSize, + PRUint32** types, + PRUint32 *flagsSize, + PRUint32** flags, + PRUint32 *defaultsSize, + PRUnichar *** defaults + ); + +}; + +struct IMediumFormat +{ + struct IMediumFormat_vtbl *vtbl; +}; +/* End of struct IMediumFormat Declaration */ + + +/* Start of struct IKeyboard Declaration */ +#define IKEYBOARD_IID_STR "f6916ec5-a881-4237-898f-7de58cf88672" +#define IKEYBOARD_IID { \ + 0xf6916ec5, 0xa881, 0x4237, \ + { 0x89, 0x8f, 0x7d, 0xe5, 0x8c, 0xf8, 0x86, 0x72 } \ +} +struct IKeyboard_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetEventSource)(IKeyboard *pThis, IEventSource * *eventSource); + + nsresult (*PutScancode)( + IKeyboard *pThis, + PRInt32 scancode + ); + + nsresult (*PutScancodes)( + IKeyboard *pThis, + PRUint32 scancodesSize, + PRInt32* scancodes, + PRUint32 * codesStored + ); + + nsresult (*PutCAD)(IKeyboard *pThis ); + +}; + +struct IKeyboard +{ + struct IKeyboard_vtbl *vtbl; +}; +/* End of struct IKeyboard Declaration */ + + +/* Start of struct IMouse Declaration */ +#define IMOUSE_IID_STR "05044a52-7811-4f00-ae3a-0ab7ff707b10" +#define IMOUSE_IID { \ + 0x05044a52, 0x7811, 0x4f00, \ + { 0xae, 0x3a, 0x0a, 0xb7, 0xff, 0x70, 0x7b, 0x10 } \ +} +struct IMouse_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetAbsoluteSupported)(IMouse *pThis, PRBool *absoluteSupported); + + nsresult (*GetRelativeSupported)(IMouse *pThis, PRBool *relativeSupported); + + nsresult (*GetNeedsHostCursor)(IMouse *pThis, PRBool *needsHostCursor); + + nsresult (*GetEventSource)(IMouse *pThis, IEventSource * *eventSource); + + nsresult (*PutMouseEvent)( + IMouse *pThis, + PRInt32 dx, + PRInt32 dy, + PRInt32 dz, + PRInt32 dw, + PRInt32 buttonState + ); + + nsresult (*PutMouseEventAbsolute)( + IMouse *pThis, + PRInt32 x, + PRInt32 y, + PRInt32 dz, + PRInt32 dw, + PRInt32 buttonState + ); + +}; + +struct IMouse +{ + struct IMouse_vtbl *vtbl; +}; +/* End of struct IMouse Declaration */ + + +/* Start of struct IFramebuffer Declaration */ +#define IFRAMEBUFFER_IID_STR "b7ed347a-5765-40a0-ae1c-f543eb4ddeaf" +#define IFRAMEBUFFER_IID { \ + 0xb7ed347a, 0x5765, 0x40a0, \ + { 0xae, 0x1c, 0xf5, 0x43, 0xeb, 0x4d, 0xde, 0xaf } \ +} +struct IFramebuffer_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetAddress)(IFramebuffer *pThis, PRUint8 * *address); + + nsresult (*GetWidth)(IFramebuffer *pThis, PRUint32 *width); + + nsresult (*GetHeight)(IFramebuffer *pThis, PRUint32 *height); + + nsresult (*GetBitsPerPixel)(IFramebuffer *pThis, PRUint32 *bitsPerPixel); + + nsresult (*GetBytesPerLine)(IFramebuffer *pThis, PRUint32 *bytesPerLine); + + nsresult (*GetPixelFormat)(IFramebuffer *pThis, PRUint32 *pixelFormat); + + nsresult (*GetUsesGuestVRAM)(IFramebuffer *pThis, PRBool *usesGuestVRAM); + + nsresult (*GetHeightReduction)(IFramebuffer *pThis, PRUint32 *heightReduction); + + nsresult (*GetOverlay)(IFramebuffer *pThis, IFramebufferOverlay * *overlay); + + nsresult (*GetWinId)(IFramebuffer *pThis, PRInt64 *winId); + + nsresult (*Lock)(IFramebuffer *pThis ); + + nsresult (*Unlock)(IFramebuffer *pThis ); + + nsresult (*NotifyUpdate)( + IFramebuffer *pThis, + PRUint32 x, + PRUint32 y, + PRUint32 width, + PRUint32 height + ); + + nsresult (*RequestResize)( + IFramebuffer *pThis, + PRUint32 screenId, + PRUint32 pixelFormat, + PRUint8 * VRAM, + PRUint32 bitsPerPixel, + PRUint32 bytesPerLine, + PRUint32 width, + PRUint32 height, + PRBool * finished + ); + + nsresult (*VideoModeSupported)( + IFramebuffer *pThis, + PRUint32 width, + PRUint32 height, + PRUint32 bpp, + PRBool * supported + ); + + nsresult (*GetVisibleRegion)( + IFramebuffer *pThis, + PRUint8 * rectangles, + PRUint32 count, + PRUint32 * countCopied + ); + + nsresult (*SetVisibleRegion)( + IFramebuffer *pThis, + PRUint8 * rectangles, + PRUint32 count + ); + + nsresult (*ProcessVHWACommand)( + IFramebuffer *pThis, + PRUint8 * command + ); + +}; + +struct IFramebuffer +{ + struct IFramebuffer_vtbl *vtbl; +}; +/* End of struct IFramebuffer Declaration */ + + +/* Start of struct IFramebufferOverlay Declaration */ +#define IFRAMEBUFFEROVERLAY_IID_STR "0bcc1c7e-e415-47d2-bfdb-e4c705fb0f47" +#define IFRAMEBUFFEROVERLAY_IID { \ + 0x0bcc1c7e, 0xe415, 0x47d2, \ + { 0xbf, 0xdb, 0xe4, 0xc7, 0x05, 0xfb, 0x0f, 0x47 } \ +} +struct IFramebufferOverlay_vtbl +{ + struct IFramebuffer_vtbl iframebuffer; + + nsresult (*GetX)(IFramebufferOverlay *pThis, PRUint32 *x); + + nsresult (*GetY)(IFramebufferOverlay *pThis, PRUint32 *y); + + nsresult (*GetVisible)(IFramebufferOverlay *pThis, PRBool *visible); + nsresult (*SetVisible)(IFramebufferOverlay *pThis, PRBool visible); + + nsresult (*GetAlpha)(IFramebufferOverlay *pThis, PRUint32 *alpha); + nsresult (*SetAlpha)(IFramebufferOverlay *pThis, PRUint32 alpha); + + nsresult (*Move)( + IFramebufferOverlay *pThis, + PRUint32 x, + PRUint32 y + ); + +}; + +struct IFramebufferOverlay +{ + struct IFramebufferOverlay_vtbl *vtbl; +}; +/* End of struct IFramebufferOverlay Declaration */ + + +/* Start of struct IDisplay Declaration */ +#define IDISPLAY_IID_STR "b83ee395-8679-40ca-8d60-1a0cbe724930" +#define IDISPLAY_IID { \ + 0xb83ee395, 0x8679, 0x40ca, \ + { 0x8d, 0x60, 0x1a, 0x0c, 0xbe, 0x72, 0x49, 0x30 } \ +} +struct IDisplay_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetScreenResolution)( + IDisplay *pThis, + PRUint32 screenId, + PRUint32 * width, + PRUint32 * height, + PRUint32 * bitsPerPixel + ); + + nsresult (*SetFramebuffer)( + IDisplay *pThis, + PRUint32 screenId, + IFramebuffer * framebuffer + ); + + nsresult (*GetFramebuffer)( + IDisplay *pThis, + PRUint32 screenId, + IFramebuffer * * framebuffer, + PRInt32 * xOrigin, + PRInt32 * yOrigin + ); + + nsresult (*SetVideoModeHint)( + IDisplay *pThis, + PRUint32 display, + PRBool enabled, + PRBool changeOrigin, + PRInt32 originX, + PRInt32 originY, + PRUint32 width, + PRUint32 height, + PRUint32 bitsPerPixel + ); + + nsresult (*SetSeamlessMode)( + IDisplay *pThis, + PRBool enabled + ); + + nsresult (*TakeScreenShot)( + IDisplay *pThis, + PRUint32 screenId, + PRUint8 * address, + PRUint32 width, + PRUint32 height + ); + + nsresult (*TakeScreenShotToArray)( + IDisplay *pThis, + PRUint32 screenId, + PRUint32 width, + PRUint32 height, + PRUint32 *screenDataSize, + PRUint8** screenData + ); + + nsresult (*TakeScreenShotPNGToArray)( + IDisplay *pThis, + PRUint32 screenId, + PRUint32 width, + PRUint32 height, + PRUint32 *screenDataSize, + PRUint8** screenData + ); + + nsresult (*DrawToScreen)( + IDisplay *pThis, + PRUint32 screenId, + PRUint8 * address, + PRUint32 x, + PRUint32 y, + PRUint32 width, + PRUint32 height + ); + + nsresult (*InvalidateAndUpdate)(IDisplay *pThis ); + + nsresult (*ResizeCompleted)( + IDisplay *pThis, + PRUint32 screenId + ); + + nsresult (*CompleteVHWACommand)( + IDisplay *pThis, + PRUint8 * command + ); + + nsresult (*ViewportChanged)( + IDisplay *pThis, + PRUint32 screenId, + PRUint32 x, + PRUint32 y, + PRUint32 width, + PRUint32 height + ); + +}; + +struct IDisplay +{ + struct IDisplay_vtbl *vtbl; +}; +/* End of struct IDisplay Declaration */ + + +/* Start of struct INetworkAdapter Declaration */ +#define INETWORKADAPTER_IID_STR "efa0f965-63c7-4c60-afdf-b1cc9943b9c0" +#define INETWORKADAPTER_IID { \ + 0xefa0f965, 0x63c7, 0x4c60, \ + { 0xaf, 0xdf, 0xb1, 0xcc, 0x99, 0x43, 0xb9, 0xc0 } \ +} +struct INetworkAdapter_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetAdapterType)(INetworkAdapter *pThis, PRUint32 *adapterType); + nsresult (*SetAdapterType)(INetworkAdapter *pThis, PRUint32 adapterType); + + nsresult (*GetSlot)(INetworkAdapter *pThis, PRUint32 *slot); + + nsresult (*GetEnabled)(INetworkAdapter *pThis, PRBool *enabled); + nsresult (*SetEnabled)(INetworkAdapter *pThis, PRBool enabled); + + nsresult (*GetMACAddress)(INetworkAdapter *pThis, PRUnichar * *MACAddress); + nsresult (*SetMACAddress)(INetworkAdapter *pThis, PRUnichar * MACAddress); + + nsresult (*GetAttachmentType)(INetworkAdapter *pThis, PRUint32 *attachmentType); + nsresult (*SetAttachmentType)(INetworkAdapter *pThis, PRUint32 attachmentType); + + nsresult (*GetBridgedInterface)(INetworkAdapter *pThis, PRUnichar * *bridgedInterface); + nsresult (*SetBridgedInterface)(INetworkAdapter *pThis, PRUnichar * bridgedInterface); + + nsresult (*GetHostOnlyInterface)(INetworkAdapter *pThis, PRUnichar * *hostOnlyInterface); + nsresult (*SetHostOnlyInterface)(INetworkAdapter *pThis, PRUnichar * hostOnlyInterface); + + nsresult (*GetInternalNetwork)(INetworkAdapter *pThis, PRUnichar * *internalNetwork); + nsresult (*SetInternalNetwork)(INetworkAdapter *pThis, PRUnichar * internalNetwork); + + nsresult (*GetNATNetwork)(INetworkAdapter *pThis, PRUnichar * *NATNetwork); + nsresult (*SetNATNetwork)(INetworkAdapter *pThis, PRUnichar * NATNetwork); + + nsresult (*GetGenericDriver)(INetworkAdapter *pThis, PRUnichar * *genericDriver); + nsresult (*SetGenericDriver)(INetworkAdapter *pThis, PRUnichar * genericDriver); + + nsresult (*GetCableConnected)(INetworkAdapter *pThis, PRBool *cableConnected); + nsresult (*SetCableConnected)(INetworkAdapter *pThis, PRBool cableConnected); + + nsresult (*GetLineSpeed)(INetworkAdapter *pThis, PRUint32 *lineSpeed); + nsresult (*SetLineSpeed)(INetworkAdapter *pThis, PRUint32 lineSpeed); + + nsresult (*GetPromiscModePolicy)(INetworkAdapter *pThis, PRUint32 *promiscModePolicy); + nsresult (*SetPromiscModePolicy)(INetworkAdapter *pThis, PRUint32 promiscModePolicy); + + nsresult (*GetTraceEnabled)(INetworkAdapter *pThis, PRBool *traceEnabled); + nsresult (*SetTraceEnabled)(INetworkAdapter *pThis, PRBool traceEnabled); + + nsresult (*GetTraceFile)(INetworkAdapter *pThis, PRUnichar * *traceFile); + nsresult (*SetTraceFile)(INetworkAdapter *pThis, PRUnichar * traceFile); + + nsresult (*GetNATEngine)(INetworkAdapter *pThis, INATEngine * *NATEngine); + + nsresult (*GetBootPriority)(INetworkAdapter *pThis, PRUint32 *bootPriority); + nsresult (*SetBootPriority)(INetworkAdapter *pThis, PRUint32 bootPriority); + + nsresult (*GetBandwidthGroup)(INetworkAdapter *pThis, IBandwidthGroup * *bandwidthGroup); + nsresult (*SetBandwidthGroup)(INetworkAdapter *pThis, IBandwidthGroup * bandwidthGroup); + + nsresult (*GetProperty)( + INetworkAdapter *pThis, + PRUnichar * key, + PRUnichar * * value + ); + + nsresult (*SetProperty)( + INetworkAdapter *pThis, + PRUnichar * key, + PRUnichar * value + ); + + nsresult (*GetProperties)( + INetworkAdapter *pThis, + PRUnichar * names, + PRUint32 *returnNamesSize, + PRUnichar *** returnNames, + PRUint32 *returnValuesSize, + PRUnichar *** returnValues + ); + +}; + +struct INetworkAdapter +{ + struct INetworkAdapter_vtbl *vtbl; +}; +/* End of struct INetworkAdapter Declaration */ + + +/* Start of struct ISerialPort Declaration */ +#define ISERIALPORT_IID_STR "937f6970-5103-4745-b78e-d28dcf1479a8" +#define ISERIALPORT_IID { \ + 0x937f6970, 0x5103, 0x4745, \ + { 0xb7, 0x8e, 0xd2, 0x8d, 0xcf, 0x14, 0x79, 0xa8 } \ +} +struct ISerialPort_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetSlot)(ISerialPort *pThis, PRUint32 *slot); + + nsresult (*GetEnabled)(ISerialPort *pThis, PRBool *enabled); + nsresult (*SetEnabled)(ISerialPort *pThis, PRBool enabled); + + nsresult (*GetIOBase)(ISerialPort *pThis, PRUint32 *IOBase); + nsresult (*SetIOBase)(ISerialPort *pThis, PRUint32 IOBase); + + nsresult (*GetIRQ)(ISerialPort *pThis, PRUint32 *IRQ); + nsresult (*SetIRQ)(ISerialPort *pThis, PRUint32 IRQ); + + nsresult (*GetHostMode)(ISerialPort *pThis, PRUint32 *hostMode); + nsresult (*SetHostMode)(ISerialPort *pThis, PRUint32 hostMode); + + nsresult (*GetServer)(ISerialPort *pThis, PRBool *server); + nsresult (*SetServer)(ISerialPort *pThis, PRBool server); + + nsresult (*GetPath)(ISerialPort *pThis, PRUnichar * *path); + nsresult (*SetPath)(ISerialPort *pThis, PRUnichar * path); + +}; + +struct ISerialPort +{ + struct ISerialPort_vtbl *vtbl; +}; +/* End of struct ISerialPort Declaration */ + + +/* Start of struct IParallelPort Declaration */ +#define IPARALLELPORT_IID_STR "0c925f06-dd10-4b77-8de8-294d738c3214" +#define IPARALLELPORT_IID { \ + 0x0c925f06, 0xdd10, 0x4b77, \ + { 0x8d, 0xe8, 0x29, 0x4d, 0x73, 0x8c, 0x32, 0x14 } \ +} +struct IParallelPort_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetSlot)(IParallelPort *pThis, PRUint32 *slot); + + nsresult (*GetEnabled)(IParallelPort *pThis, PRBool *enabled); + nsresult (*SetEnabled)(IParallelPort *pThis, PRBool enabled); + + nsresult (*GetIOBase)(IParallelPort *pThis, PRUint32 *IOBase); + nsresult (*SetIOBase)(IParallelPort *pThis, PRUint32 IOBase); + + nsresult (*GetIRQ)(IParallelPort *pThis, PRUint32 *IRQ); + nsresult (*SetIRQ)(IParallelPort *pThis, PRUint32 IRQ); + + nsresult (*GetPath)(IParallelPort *pThis, PRUnichar * *path); + nsresult (*SetPath)(IParallelPort *pThis, PRUnichar * path); + +}; + +struct IParallelPort +{ + struct IParallelPort_vtbl *vtbl; +}; +/* End of struct IParallelPort Declaration */ + + +/* Start of struct IMachineDebugger Declaration */ +#define IMACHINEDEBUGGER_IID_STR "a9abbb7c-d678-43b2-bed2-19ec0e32303d" +#define IMACHINEDEBUGGER_IID { \ + 0xa9abbb7c, 0xd678, 0x43b2, \ + { 0xbe, 0xd2, 0x19, 0xec, 0x0e, 0x32, 0x30, 0x3d } \ +} +struct IMachineDebugger_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetSingleStep)(IMachineDebugger *pThis, PRBool *singleStep); + nsresult (*SetSingleStep)(IMachineDebugger *pThis, PRBool singleStep); + + nsresult (*GetRecompileUser)(IMachineDebugger *pThis, PRBool *recompileUser); + nsresult (*SetRecompileUser)(IMachineDebugger *pThis, PRBool recompileUser); + + nsresult (*GetRecompileSupervisor)(IMachineDebugger *pThis, PRBool *recompileSupervisor); + nsresult (*SetRecompileSupervisor)(IMachineDebugger *pThis, PRBool recompileSupervisor); + + nsresult (*GetPATMEnabled)(IMachineDebugger *pThis, PRBool *PATMEnabled); + nsresult (*SetPATMEnabled)(IMachineDebugger *pThis, PRBool PATMEnabled); + + nsresult (*GetCSAMEnabled)(IMachineDebugger *pThis, PRBool *CSAMEnabled); + nsresult (*SetCSAMEnabled)(IMachineDebugger *pThis, PRBool CSAMEnabled); + + nsresult (*GetLogEnabled)(IMachineDebugger *pThis, PRBool *logEnabled); + nsresult (*SetLogEnabled)(IMachineDebugger *pThis, PRBool logEnabled); + + nsresult (*GetLogDbgFlags)(IMachineDebugger *pThis, PRUnichar * *logDbgFlags); + + nsresult (*GetLogDbgGroups)(IMachineDebugger *pThis, PRUnichar * *logDbgGroups); + + nsresult (*GetLogDbgDestinations)(IMachineDebugger *pThis, PRUnichar * *logDbgDestinations); + + nsresult (*GetLogRelFlags)(IMachineDebugger *pThis, PRUnichar * *logRelFlags); + + nsresult (*GetLogRelGroups)(IMachineDebugger *pThis, PRUnichar * *logRelGroups); + + nsresult (*GetLogRelDestinations)(IMachineDebugger *pThis, PRUnichar * *logRelDestinations); + + nsresult (*GetHWVirtExEnabled)(IMachineDebugger *pThis, PRBool *HWVirtExEnabled); + + nsresult (*GetHWVirtExNestedPagingEnabled)(IMachineDebugger *pThis, PRBool *HWVirtExNestedPagingEnabled); + + nsresult (*GetHWVirtExVPIDEnabled)(IMachineDebugger *pThis, PRBool *HWVirtExVPIDEnabled); + + nsresult (*GetOSName)(IMachineDebugger *pThis, PRUnichar * *OSName); + + nsresult (*GetOSVersion)(IMachineDebugger *pThis, PRUnichar * *OSVersion); + + nsresult (*GetPAEEnabled)(IMachineDebugger *pThis, PRBool *PAEEnabled); + + nsresult (*GetVirtualTimeRate)(IMachineDebugger *pThis, PRUint32 *virtualTimeRate); + nsresult (*SetVirtualTimeRate)(IMachineDebugger *pThis, PRUint32 virtualTimeRate); + + nsresult (*GetVM)(IMachineDebugger *pThis, PRInt64 *VM); + + nsresult (*DumpGuestCore)( + IMachineDebugger *pThis, + PRUnichar * filename, + PRUnichar * compression + ); + + nsresult (*DumpHostProcessCore)( + IMachineDebugger *pThis, + PRUnichar * filename, + PRUnichar * compression + ); + + nsresult (*Info)( + IMachineDebugger *pThis, + PRUnichar * name, + PRUnichar * args, + PRUnichar * * info + ); + + nsresult (*InjectNMI)(IMachineDebugger *pThis ); + + nsresult (*ModifyLogGroups)( + IMachineDebugger *pThis, + PRUnichar * settings + ); + + nsresult (*ModifyLogFlags)( + IMachineDebugger *pThis, + PRUnichar * settings + ); + + nsresult (*ModifyLogDestinations)( + IMachineDebugger *pThis, + PRUnichar * settings + ); + + nsresult (*ReadPhysicalMemory)( + IMachineDebugger *pThis, + PRInt64 address, + PRUint32 size, + PRUint32 *bytesSize, + PRUint8** bytes + ); + + nsresult (*WritePhysicalMemory)( + IMachineDebugger *pThis, + PRInt64 address, + PRUint32 size, + PRUint32 bytesSize, + PRUint8* bytes + ); + + nsresult (*ReadVirtualMemory)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRInt64 address, + PRUint32 size, + PRUint32 *bytesSize, + PRUint8** bytes + ); + + nsresult (*WriteVirtualMemory)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRInt64 address, + PRUint32 size, + PRUint32 bytesSize, + PRUint8* bytes + ); + + nsresult (*DetectOS)( + IMachineDebugger *pThis, + PRUnichar * * os + ); + + nsresult (*GetRegister)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRUnichar * name, + PRUnichar * * value + ); + + nsresult (*GetRegisters)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRUint32 *namesSize, + PRUnichar *** names, + PRUint32 *valuesSize, + PRUnichar *** values + ); + + nsresult (*SetRegister)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRUnichar * name, + PRUnichar * value + ); + + nsresult (*SetRegisters)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRUint32 namesSize, + PRUnichar ** names, + PRUint32 valuesSize, + PRUnichar ** values + ); + + nsresult (*DumpGuestStack)( + IMachineDebugger *pThis, + PRUint32 cpuId, + PRUnichar * * stack + ); + + nsresult (*ResetStats)( + IMachineDebugger *pThis, + PRUnichar * pattern + ); + + nsresult (*DumpStats)( + IMachineDebugger *pThis, + PRUnichar * pattern + ); + + nsresult (*GetStats)( + IMachineDebugger *pThis, + PRUnichar * pattern, + PRBool withDescriptions, + PRUnichar * * stats + ); + +}; + +struct IMachineDebugger +{ + struct IMachineDebugger_vtbl *vtbl; +}; +/* End of struct IMachineDebugger Declaration */ + + +/* Start of struct IUSBController Declaration */ +#define IUSBCONTROLLER_IID_STR "01e6f13a-0580-452f-a40f-74e32a5e4921" +#define IUSBCONTROLLER_IID { \ + 0x01e6f13a, 0x0580, 0x452f, \ + { 0xa4, 0x0f, 0x74, 0xe3, 0x2a, 0x5e, 0x49, 0x21 } \ +} +struct IUSBController_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetEnabled)(IUSBController *pThis, PRBool *enabled); + nsresult (*SetEnabled)(IUSBController *pThis, PRBool enabled); + + nsresult (*GetEnabledEHCI)(IUSBController *pThis, PRBool *enabledEHCI); + nsresult (*SetEnabledEHCI)(IUSBController *pThis, PRBool enabledEHCI); + + nsresult (*GetProxyAvailable)(IUSBController *pThis, PRBool *proxyAvailable); + + nsresult (*GetUSBStandard)(IUSBController *pThis, PRUint16 *USBStandard); + + nsresult (*GetDeviceFilters)(IUSBController *pThis, PRUint32 *deviceFiltersSize, IUSBDeviceFilter * **deviceFilters); + + nsresult (*CreateDeviceFilter)( + IUSBController *pThis, + PRUnichar * name, + IUSBDeviceFilter * * filter + ); + + nsresult (*InsertDeviceFilter)( + IUSBController *pThis, + PRUint32 position, + IUSBDeviceFilter * filter + ); + + nsresult (*RemoveDeviceFilter)( + IUSBController *pThis, + PRUint32 position, + IUSBDeviceFilter * * filter + ); + +}; + +struct IUSBController +{ + struct IUSBController_vtbl *vtbl; +}; +/* End of struct IUSBController Declaration */ + + +/* Start of struct IUSBDevice Declaration */ +#define IUSBDEVICE_IID_STR "f8967b0b-4483-400f-92b5-8b675d98a85b" +#define IUSBDEVICE_IID { \ + 0xf8967b0b, 0x4483, 0x400f, \ + { 0x92, 0xb5, 0x8b, 0x67, 0x5d, 0x98, 0xa8, 0x5b } \ +} +struct IUSBDevice_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetId)(IUSBDevice *pThis, PRUnichar * *id); + + nsresult (*GetVendorId)(IUSBDevice *pThis, PRUint16 *vendorId); + + nsresult (*GetProductId)(IUSBDevice *pThis, PRUint16 *productId); + + nsresult (*GetRevision)(IUSBDevice *pThis, PRUint16 *revision); + + nsresult (*GetManufacturer)(IUSBDevice *pThis, PRUnichar * *manufacturer); + + nsresult (*GetProduct)(IUSBDevice *pThis, PRUnichar * *product); + + nsresult (*GetSerialNumber)(IUSBDevice *pThis, PRUnichar * *serialNumber); + + nsresult (*GetAddress)(IUSBDevice *pThis, PRUnichar * *address); + + nsresult (*GetPort)(IUSBDevice *pThis, PRUint16 *port); + + nsresult (*GetVersion)(IUSBDevice *pThis, PRUint16 *version); + + nsresult (*GetPortVersion)(IUSBDevice *pThis, PRUint16 *portVersion); + + nsresult (*GetRemote)(IUSBDevice *pThis, PRBool *remote); + +}; + +struct IUSBDevice +{ + struct IUSBDevice_vtbl *vtbl; +}; +/* End of struct IUSBDevice Declaration */ + + +/* Start of struct IUSBDeviceFilter Declaration */ +#define IUSBDEVICEFILTER_IID_STR "d6831fb4-1a94-4c2c-96ef-8d0d6192066d" +#define IUSBDEVICEFILTER_IID { \ + 0xd6831fb4, 0x1a94, 0x4c2c, \ + { 0x96, 0xef, 0x8d, 0x0d, 0x61, 0x92, 0x06, 0x6d } \ +} +struct IUSBDeviceFilter_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IUSBDeviceFilter *pThis, PRUnichar * *name); + nsresult (*SetName)(IUSBDeviceFilter *pThis, PRUnichar * name); + + nsresult (*GetActive)(IUSBDeviceFilter *pThis, PRBool *active); + nsresult (*SetActive)(IUSBDeviceFilter *pThis, PRBool active); + + nsresult (*GetVendorId)(IUSBDeviceFilter *pThis, PRUnichar * *vendorId); + nsresult (*SetVendorId)(IUSBDeviceFilter *pThis, PRUnichar * vendorId); + + nsresult (*GetProductId)(IUSBDeviceFilter *pThis, PRUnichar * *productId); + nsresult (*SetProductId)(IUSBDeviceFilter *pThis, PRUnichar * productId); + + nsresult (*GetRevision)(IUSBDeviceFilter *pThis, PRUnichar * *revision); + nsresult (*SetRevision)(IUSBDeviceFilter *pThis, PRUnichar * revision); + + nsresult (*GetManufacturer)(IUSBDeviceFilter *pThis, PRUnichar * *manufacturer); + nsresult (*SetManufacturer)(IUSBDeviceFilter *pThis, PRUnichar * manufacturer); + + nsresult (*GetProduct)(IUSBDeviceFilter *pThis, PRUnichar * *product); + nsresult (*SetProduct)(IUSBDeviceFilter *pThis, PRUnichar * product); + + nsresult (*GetSerialNumber)(IUSBDeviceFilter *pThis, PRUnichar * *serialNumber); + nsresult (*SetSerialNumber)(IUSBDeviceFilter *pThis, PRUnichar * serialNumber); + + nsresult (*GetPort)(IUSBDeviceFilter *pThis, PRUnichar * *port); + nsresult (*SetPort)(IUSBDeviceFilter *pThis, PRUnichar * port); + + nsresult (*GetRemote)(IUSBDeviceFilter *pThis, PRUnichar * *remote); + nsresult (*SetRemote)(IUSBDeviceFilter *pThis, PRUnichar * remote); + + nsresult (*GetMaskedInterfaces)(IUSBDeviceFilter *pThis, PRUint32 *maskedInterfaces); + nsresult (*SetMaskedInterfaces)(IUSBDeviceFilter *pThis, PRUint32 maskedInterfaces); + +}; + +struct IUSBDeviceFilter +{ + struct IUSBDeviceFilter_vtbl *vtbl; +}; +/* End of struct IUSBDeviceFilter Declaration */ + + +/* Start of struct IHostUSBDevice Declaration */ +#define IHOSTUSBDEVICE_IID_STR "173b4b44-d268-4334-a00d-b6521c9a740a" +#define IHOSTUSBDEVICE_IID { \ + 0x173b4b44, 0xd268, 0x4334, \ + { 0xa0, 0x0d, 0xb6, 0x52, 0x1c, 0x9a, 0x74, 0x0a } \ +} +struct IHostUSBDevice_vtbl +{ + struct IUSBDevice_vtbl iusbdevice; + + nsresult (*GetState)(IHostUSBDevice *pThis, PRUint32 *state); + +}; + +struct IHostUSBDevice +{ + struct IHostUSBDevice_vtbl *vtbl; +}; +/* End of struct IHostUSBDevice Declaration */ + + +/* Start of struct IHostUSBDeviceFilter Declaration */ +#define IHOSTUSBDEVICEFILTER_IID_STR "4cc70246-d74a-400f-8222-3900489c0374" +#define IHOSTUSBDEVICEFILTER_IID { \ + 0x4cc70246, 0xd74a, 0x400f, \ + { 0x82, 0x22, 0x39, 0x00, 0x48, 0x9c, 0x03, 0x74 } \ +} +struct IHostUSBDeviceFilter_vtbl +{ + struct IUSBDeviceFilter_vtbl iusbdevicefilter; + + nsresult (*GetAction)(IHostUSBDeviceFilter *pThis, PRUint32 *action); + nsresult (*SetAction)(IHostUSBDeviceFilter *pThis, PRUint32 action); + +}; + +struct IHostUSBDeviceFilter +{ + struct IHostUSBDeviceFilter_vtbl *vtbl; +}; +/* End of struct IHostUSBDeviceFilter Declaration */ + + +/* Start of struct IAudioAdapter Declaration */ +#define IAUDIOADAPTER_IID_STR "921873db-5f3f-4b69-91f9-7be9e535a2cb" +#define IAUDIOADAPTER_IID { \ + 0x921873db, 0x5f3f, 0x4b69, \ + { 0x91, 0xf9, 0x7b, 0xe9, 0xe5, 0x35, 0xa2, 0xcb } \ +} +struct IAudioAdapter_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetEnabled)(IAudioAdapter *pThis, PRBool *enabled); + nsresult (*SetEnabled)(IAudioAdapter *pThis, PRBool enabled); + + nsresult (*GetAudioController)(IAudioAdapter *pThis, PRUint32 *audioController); + nsresult (*SetAudioController)(IAudioAdapter *pThis, PRUint32 audioController); + + nsresult (*GetAudioDriver)(IAudioAdapter *pThis, PRUint32 *audioDriver); + nsresult (*SetAudioDriver)(IAudioAdapter *pThis, PRUint32 audioDriver); + +}; + +struct IAudioAdapter +{ + struct IAudioAdapter_vtbl *vtbl; +}; +/* End of struct IAudioAdapter Declaration */ + + +/* Start of struct IVRDEServer Declaration */ +#define IVRDESERVER_IID_STR "d38de40a-c2c1-4e95-b5a4-167b05f5694c" +#define IVRDESERVER_IID { \ + 0xd38de40a, 0xc2c1, 0x4e95, \ + { 0xb5, 0xa4, 0x16, 0x7b, 0x05, 0xf5, 0x69, 0x4c } \ +} +struct IVRDEServer_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetEnabled)(IVRDEServer *pThis, PRBool *enabled); + nsresult (*SetEnabled)(IVRDEServer *pThis, PRBool enabled); + + nsresult (*GetAuthType)(IVRDEServer *pThis, PRUint32 *authType); + nsresult (*SetAuthType)(IVRDEServer *pThis, PRUint32 authType); + + nsresult (*GetAuthTimeout)(IVRDEServer *pThis, PRUint32 *authTimeout); + nsresult (*SetAuthTimeout)(IVRDEServer *pThis, PRUint32 authTimeout); + + nsresult (*GetAllowMultiConnection)(IVRDEServer *pThis, PRBool *allowMultiConnection); + nsresult (*SetAllowMultiConnection)(IVRDEServer *pThis, PRBool allowMultiConnection); + + nsresult (*GetReuseSingleConnection)(IVRDEServer *pThis, PRBool *reuseSingleConnection); + nsresult (*SetReuseSingleConnection)(IVRDEServer *pThis, PRBool reuseSingleConnection); + + nsresult (*GetVRDEExtPack)(IVRDEServer *pThis, PRUnichar * *VRDEExtPack); + nsresult (*SetVRDEExtPack)(IVRDEServer *pThis, PRUnichar * VRDEExtPack); + + nsresult (*GetAuthLibrary)(IVRDEServer *pThis, PRUnichar * *authLibrary); + nsresult (*SetAuthLibrary)(IVRDEServer *pThis, PRUnichar * authLibrary); + + nsresult (*GetVRDEProperties)(IVRDEServer *pThis, PRUint32 *VRDEPropertiesSize, PRUnichar * **VRDEProperties); + + nsresult (*SetVRDEProperty)( + IVRDEServer *pThis, + PRUnichar * key, + PRUnichar * value + ); + + nsresult (*GetVRDEProperty)( + IVRDEServer *pThis, + PRUnichar * key, + PRUnichar * * value + ); + +}; + +struct IVRDEServer +{ + struct IVRDEServer_vtbl *vtbl; +}; +/* End of struct IVRDEServer Declaration */ + + +/* Start of struct ISharedFolder Declaration */ +#define ISHAREDFOLDER_IID_STR "8388da11-b559-4574-a5b7-2bd7acd5cef8" +#define ISHAREDFOLDER_IID { \ + 0x8388da11, 0xb559, 0x4574, \ + { 0xa5, 0xb7, 0x2b, 0xd7, 0xac, 0xd5, 0xce, 0xf8 } \ +} +struct ISharedFolder_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(ISharedFolder *pThis, PRUnichar * *name); + + nsresult (*GetHostPath)(ISharedFolder *pThis, PRUnichar * *hostPath); + + nsresult (*GetAccessible)(ISharedFolder *pThis, PRBool *accessible); + + nsresult (*GetWritable)(ISharedFolder *pThis, PRBool *writable); + + nsresult (*GetAutoMount)(ISharedFolder *pThis, PRBool *autoMount); + + nsresult (*GetLastAccessError)(ISharedFolder *pThis, PRUnichar * *lastAccessError); + +}; + +struct ISharedFolder +{ + struct ISharedFolder_vtbl *vtbl; +}; +/* End of struct ISharedFolder Declaration */ + + +/* Start of struct IInternalSessionControl Declaration */ +#define IINTERNALSESSIONCONTROL_IID_STR "cddf451c-a006-4c33-8245-63b3c9ae6586" +#define IINTERNALSESSIONCONTROL_IID { \ + 0xcddf451c, 0xa006, 0x4c33, \ + { 0x82, 0x45, 0x63, 0xb3, 0xc9, 0xae, 0x65, 0x86 } \ +} +struct IInternalSessionControl_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetPID)( + IInternalSessionControl *pThis, + PRUint32 * pid + ); + + nsresult (*GetRemoteConsole)( + IInternalSessionControl *pThis, + IConsole * * console + ); + + nsresult (*AssignMachine)( + IInternalSessionControl *pThis, + IMachine * machine, + PRUint32 lockType + ); + + nsresult (*AssignRemoteMachine)( + IInternalSessionControl *pThis, + IMachine * machine, + IConsole * console + ); + + nsresult (*UpdateMachineState)( + IInternalSessionControl *pThis, + PRUint32 aMachineState + ); + + nsresult (*Uninitialize)(IInternalSessionControl *pThis ); + + nsresult (*OnNetworkAdapterChange)( + IInternalSessionControl *pThis, + INetworkAdapter * networkAdapter, + PRBool changeAdapter + ); + + nsresult (*OnSerialPortChange)( + IInternalSessionControl *pThis, + ISerialPort * serialPort + ); + + nsresult (*OnParallelPortChange)( + IInternalSessionControl *pThis, + IParallelPort * parallelPort + ); + + nsresult (*OnStorageControllerChange)(IInternalSessionControl *pThis ); + + nsresult (*OnMediumChange)( + IInternalSessionControl *pThis, + IMediumAttachment * mediumAttachment, + PRBool force + ); + + nsresult (*OnStorageDeviceChange)( + IInternalSessionControl *pThis, + IMediumAttachment * mediumAttachment, + PRBool remove, + PRBool silent + ); + + nsresult (*OnClipboardModeChange)( + IInternalSessionControl *pThis, + PRUint32 clipboardMode + ); + + nsresult (*OnDragAndDropModeChange)( + IInternalSessionControl *pThis, + PRUint32 dragAndDropMode + ); + + nsresult (*OnCPUChange)( + IInternalSessionControl *pThis, + PRUint32 cpu, + PRBool add + ); + + nsresult (*OnCPUExecutionCapChange)( + IInternalSessionControl *pThis, + PRUint32 executionCap + ); + + nsresult (*OnVRDEServerChange)( + IInternalSessionControl *pThis, + PRBool restart + ); + + nsresult (*OnUSBControllerChange)(IInternalSessionControl *pThis ); + + nsresult (*OnSharedFolderChange)( + IInternalSessionControl *pThis, + PRBool global + ); + + nsresult (*OnUSBDeviceAttach)( + IInternalSessionControl *pThis, + IUSBDevice * device, + IVirtualBoxErrorInfo * error, + PRUint32 maskedInterfaces + ); + + nsresult (*OnUSBDeviceDetach)( + IInternalSessionControl *pThis, + PRUnichar * id, + IVirtualBoxErrorInfo * error + ); + + nsresult (*OnShowWindow)( + IInternalSessionControl *pThis, + PRBool check, + PRBool * canShow, + PRInt64 * winId + ); + + nsresult (*OnBandwidthGroupChange)( + IInternalSessionControl *pThis, + IBandwidthGroup * bandwidthGroup + ); + + nsresult (*AccessGuestProperty)( + IInternalSessionControl *pThis, + PRUnichar * name, + PRUnichar * value, + PRUnichar * flags, + PRBool isSetter, + PRUnichar * * retValue, + PRInt64 * retTimestamp, + PRUnichar * * retFlags + ); + + nsresult (*EnumerateGuestProperties)( + IInternalSessionControl *pThis, + PRUnichar * patterns, + PRUint32 *keySize, + PRUnichar *** key, + PRUint32 *valueSize, + PRUnichar *** value, + PRUint32 *timestampSize, + PRInt64** timestamp, + PRUint32 *flagsSize, + PRUnichar *** flags + ); + + nsresult (*OnlineMergeMedium)( + IInternalSessionControl *pThis, + IMediumAttachment * mediumAttachment, + PRUint32 sourceIdx, + PRUint32 targetIdx, + IMedium * source, + IMedium * target, + PRBool mergeForward, + IMedium * parentForTarget, + PRUint32 childrenToReparentSize, + IMedium ** childrenToReparent, + IProgress * progress + ); + + nsresult (*EnableVMMStatistics)( + IInternalSessionControl *pThis, + PRBool enable + ); + + nsresult (*PauseWithReason)( + IInternalSessionControl *pThis, + PRUint32 reason + ); + + nsresult (*ResumeWithReason)( + IInternalSessionControl *pThis, + PRUint32 reason + ); + + nsresult (*SaveStateWithReason)( + IInternalSessionControl *pThis, + PRUint32 reason, + IProgress * * progress + ); + +}; + +struct IInternalSessionControl +{ + struct IInternalSessionControl_vtbl *vtbl; +}; +/* End of struct IInternalSessionControl Declaration */ + + +/* Start of struct ISession Declaration */ +#define ISESSION_IID_STR "12F4DCDB-12B2-4EC1-B7CD-DDD9F6C5BF4D" +#define ISESSION_IID { \ + 0x12F4DCDB, 0x12B2, 0x4EC1, \ + { 0xB7, 0xCD, 0xDD, 0xD9, 0xF6, 0xC5, 0xBF, 0x4D } \ +} +struct ISession_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetState)(ISession *pThis, PRUint32 *state); + + nsresult (*GetType)(ISession *pThis, PRUint32 *type); + + nsresult (*GetMachine)(ISession *pThis, IMachine * *machine); + + nsresult (*GetConsole)(ISession *pThis, IConsole * *console); + + nsresult (*UnlockMachine)(ISession *pThis ); + +}; + +struct ISession +{ + struct ISession_vtbl *vtbl; +}; +/* End of struct ISession Declaration */ + + +/* Start of struct IStorageController Declaration */ +#define ISTORAGECONTROLLER_IID_STR "a1556333-09b6-46d9-bfb7-fc239b7fbe1e" +#define ISTORAGECONTROLLER_IID { \ + 0xa1556333, 0x09b6, 0x46d9, \ + { 0xbf, 0xb7, 0xfc, 0x23, 0x9b, 0x7f, 0xbe, 0x1e } \ +} +struct IStorageController_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IStorageController *pThis, PRUnichar * *name); + + nsresult (*GetMaxDevicesPerPortCount)(IStorageController *pThis, PRUint32 *maxDevicesPerPortCount); + + nsresult (*GetMinPortCount)(IStorageController *pThis, PRUint32 *minPortCount); + + nsresult (*GetMaxPortCount)(IStorageController *pThis, PRUint32 *maxPortCount); + + nsresult (*GetInstance)(IStorageController *pThis, PRUint32 *instance); + nsresult (*SetInstance)(IStorageController *pThis, PRUint32 instance); + + nsresult (*GetPortCount)(IStorageController *pThis, PRUint32 *portCount); + nsresult (*SetPortCount)(IStorageController *pThis, PRUint32 portCount); + + nsresult (*GetBus)(IStorageController *pThis, PRUint32 *bus); + + nsresult (*GetControllerType)(IStorageController *pThis, PRUint32 *controllerType); + nsresult (*SetControllerType)(IStorageController *pThis, PRUint32 controllerType); + + nsresult (*GetUseHostIOCache)(IStorageController *pThis, PRBool *useHostIOCache); + nsresult (*SetUseHostIOCache)(IStorageController *pThis, PRBool useHostIOCache); + + nsresult (*GetBootable)(IStorageController *pThis, PRBool *bootable); + +}; + +struct IStorageController +{ + struct IStorageController_vtbl *vtbl; +}; +/* End of struct IStorageController Declaration */ + + +/* Start of struct IPerformanceMetric Declaration */ +#define IPERFORMANCEMETRIC_IID_STR "2a1a60ae-9345-4019-ad53-d34ba41cbfe9" +#define IPERFORMANCEMETRIC_IID { \ + 0x2a1a60ae, 0x9345, 0x4019, \ + { 0xad, 0x53, 0xd3, 0x4b, 0xa4, 0x1c, 0xbf, 0xe9 } \ +} +struct IPerformanceMetric_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMetricName)(IPerformanceMetric *pThis, PRUnichar * *metricName); + + nsresult (*GetObject)(IPerformanceMetric *pThis, nsISupports * *object); + + nsresult (*GetDescription)(IPerformanceMetric *pThis, PRUnichar * *description); + + nsresult (*GetPeriod)(IPerformanceMetric *pThis, PRUint32 *period); + + nsresult (*GetCount)(IPerformanceMetric *pThis, PRUint32 *count); + + nsresult (*GetUnit)(IPerformanceMetric *pThis, PRUnichar * *unit); + + nsresult (*GetMinimumValue)(IPerformanceMetric *pThis, PRInt32 *minimumValue); + + nsresult (*GetMaximumValue)(IPerformanceMetric *pThis, PRInt32 *maximumValue); + +}; + +struct IPerformanceMetric +{ + struct IPerformanceMetric_vtbl *vtbl; +}; +/* End of struct IPerformanceMetric Declaration */ + + +/* Start of struct IPerformanceCollector Declaration */ +#define IPERFORMANCECOLLECTOR_IID_STR "e22e1acb-ac4a-43bb-a31c-17321659b0c6" +#define IPERFORMANCECOLLECTOR_IID { \ + 0xe22e1acb, 0xac4a, 0x43bb, \ + { 0xa3, 0x1c, 0x17, 0x32, 0x16, 0x59, 0xb0, 0xc6 } \ +} +struct IPerformanceCollector_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMetricNames)(IPerformanceCollector *pThis, PRUint32 *metricNamesSize, PRUnichar * **metricNames); + + nsresult (*GetMetrics)( + IPerformanceCollector *pThis, + PRUint32 metricNamesSize, + PRUnichar ** metricNames, + PRUint32 objectsSize, + nsISupports ** objects, + PRUint32 *metricsSize, + IPerformanceMetric *** metrics + ); + + nsresult (*SetupMetrics)( + IPerformanceCollector *pThis, + PRUint32 metricNamesSize, + PRUnichar ** metricNames, + PRUint32 objectsSize, + nsISupports ** objects, + PRUint32 period, + PRUint32 count, + PRUint32 *affectedMetricsSize, + IPerformanceMetric *** affectedMetrics + ); + + nsresult (*EnableMetrics)( + IPerformanceCollector *pThis, + PRUint32 metricNamesSize, + PRUnichar ** metricNames, + PRUint32 objectsSize, + nsISupports ** objects, + PRUint32 *affectedMetricsSize, + IPerformanceMetric *** affectedMetrics + ); + + nsresult (*DisableMetrics)( + IPerformanceCollector *pThis, + PRUint32 metricNamesSize, + PRUnichar ** metricNames, + PRUint32 objectsSize, + nsISupports ** objects, + PRUint32 *affectedMetricsSize, + IPerformanceMetric *** affectedMetrics + ); + + nsresult (*QueryMetricsData)( + IPerformanceCollector *pThis, + PRUint32 metricNamesSize, + PRUnichar ** metricNames, + PRUint32 objectsSize, + nsISupports ** objects, + PRUint32 *returnMetricNamesSize, + PRUnichar *** returnMetricNames, + PRUint32 *returnObjectsSize, + nsISupports *** returnObjects, + PRUint32 *returnUnitsSize, + PRUnichar *** returnUnits, + PRUint32 *returnScalesSize, + PRUint32** returnScales, + PRUint32 *returnSequenceNumbersSize, + PRUint32** returnSequenceNumbers, + PRUint32 *returnDataIndicesSize, + PRUint32** returnDataIndices, + PRUint32 *returnDataLengthsSize, + PRUint32** returnDataLengths, + PRUint32 *returnDataSize, + PRInt32** returnData + ); + +}; + +struct IPerformanceCollector +{ + struct IPerformanceCollector_vtbl *vtbl; +}; +/* End of struct IPerformanceCollector Declaration */ + + +/* Start of struct INATEngine Declaration */ +#define INATENGINE_IID_STR "26451b99-3b2d-4dcb-8e4b-d63654218175" +#define INATENGINE_IID { \ + 0x26451b99, 0x3b2d, 0x4dcb, \ + { 0x8e, 0x4b, 0xd6, 0x36, 0x54, 0x21, 0x81, 0x75 } \ +} +struct INATEngine_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetNetwork)(INATEngine *pThis, PRUnichar * *network); + nsresult (*SetNetwork)(INATEngine *pThis, PRUnichar * network); + + nsresult (*GetHostIP)(INATEngine *pThis, PRUnichar * *hostIP); + nsresult (*SetHostIP)(INATEngine *pThis, PRUnichar * hostIP); + + nsresult (*GetTFTPPrefix)(INATEngine *pThis, PRUnichar * *TFTPPrefix); + nsresult (*SetTFTPPrefix)(INATEngine *pThis, PRUnichar * TFTPPrefix); + + nsresult (*GetTFTPBootFile)(INATEngine *pThis, PRUnichar * *TFTPBootFile); + nsresult (*SetTFTPBootFile)(INATEngine *pThis, PRUnichar * TFTPBootFile); + + nsresult (*GetTFTPNextServer)(INATEngine *pThis, PRUnichar * *TFTPNextServer); + nsresult (*SetTFTPNextServer)(INATEngine *pThis, PRUnichar * TFTPNextServer); + + nsresult (*GetAliasMode)(INATEngine *pThis, PRUint32 *aliasMode); + nsresult (*SetAliasMode)(INATEngine *pThis, PRUint32 aliasMode); + + nsresult (*GetDNSPassDomain)(INATEngine *pThis, PRBool *DNSPassDomain); + nsresult (*SetDNSPassDomain)(INATEngine *pThis, PRBool DNSPassDomain); + + nsresult (*GetDNSProxy)(INATEngine *pThis, PRBool *DNSProxy); + nsresult (*SetDNSProxy)(INATEngine *pThis, PRBool DNSProxy); + + nsresult (*GetDNSUseHostResolver)(INATEngine *pThis, PRBool *DNSUseHostResolver); + nsresult (*SetDNSUseHostResolver)(INATEngine *pThis, PRBool DNSUseHostResolver); + + nsresult (*GetRedirects)(INATEngine *pThis, PRUint32 *redirectsSize, PRUnichar * **redirects); + + nsresult (*SetNetworkSettings)( + INATEngine *pThis, + PRUint32 mtu, + PRUint32 sockSnd, + PRUint32 sockRcv, + PRUint32 TcpWndSnd, + PRUint32 TcpWndRcv + ); + + nsresult (*GetNetworkSettings)( + INATEngine *pThis, + PRUint32 * mtu, + PRUint32 * sockSnd, + PRUint32 * sockRcv, + PRUint32 * TcpWndSnd, + PRUint32 * TcpWndRcv + ); + + nsresult (*AddRedirect)( + INATEngine *pThis, + PRUnichar * name, + PRUint32 proto, + PRUnichar * hostIP, + PRUint16 hostPort, + PRUnichar * guestIP, + PRUint16 guestPort + ); + + nsresult (*RemoveRedirect)( + INATEngine *pThis, + PRUnichar * name + ); + +}; + +struct INATEngine +{ + struct INATEngine_vtbl *vtbl; +}; +/* End of struct INATEngine Declaration */ + + +/* Start of struct IExtPackPlugIn Declaration */ +#define IEXTPACKPLUGIN_IID_STR "58000040-e718-4746-bbce-4b86d96da461" +#define IEXTPACKPLUGIN_IID { \ + 0x58000040, 0xe718, 0x4746, \ + { 0xbb, 0xce, 0x4b, 0x86, 0xd9, 0x6d, 0xa4, 0x61 } \ +} +struct IExtPackPlugIn_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IExtPackPlugIn *pThis, PRUnichar * *name); + + nsresult (*GetDescription)(IExtPackPlugIn *pThis, PRUnichar * *description); + + nsresult (*GetFrontend)(IExtPackPlugIn *pThis, PRUnichar * *frontend); + + nsresult (*GetModulePath)(IExtPackPlugIn *pThis, PRUnichar * *modulePath); + +}; + +struct IExtPackPlugIn +{ + struct IExtPackPlugIn_vtbl *vtbl; +}; +/* End of struct IExtPackPlugIn Declaration */ + + +/* Start of struct IExtPackBase Declaration */ +#define IEXTPACKBASE_IID_STR "f79b75d8-2890-4f34-ffff-ffffa144e82c" +#define IEXTPACKBASE_IID { \ + 0xf79b75d8, 0x2890, 0x4f34, \ + { 0xff, 0xff, 0xff, 0xff, 0xa1, 0x44, 0xe8, 0x2c } \ +} +struct IExtPackBase_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IExtPackBase *pThis, PRUnichar * *name); + + nsresult (*GetDescription)(IExtPackBase *pThis, PRUnichar * *description); + + nsresult (*GetVersion)(IExtPackBase *pThis, PRUnichar * *version); + + nsresult (*GetRevision)(IExtPackBase *pThis, PRUint32 *revision); + + nsresult (*GetEdition)(IExtPackBase *pThis, PRUnichar * *edition); + + nsresult (*GetVRDEModule)(IExtPackBase *pThis, PRUnichar * *VRDEModule); + + nsresult (*GetPlugIns)(IExtPackBase *pThis, PRUint32 *plugInsSize, IExtPackPlugIn * **plugIns); + + nsresult (*GetUsable)(IExtPackBase *pThis, PRBool *usable); + + nsresult (*GetWhyUnusable)(IExtPackBase *pThis, PRUnichar * *whyUnusable); + + nsresult (*GetShowLicense)(IExtPackBase *pThis, PRBool *showLicense); + + nsresult (*GetLicense)(IExtPackBase *pThis, PRUnichar * *license); + + nsresult (*QueryLicense)( + IExtPackBase *pThis, + PRUnichar * preferredLocale, + PRUnichar * preferredLanguage, + PRUnichar * format, + PRUnichar * * licenseText + ); + +}; + +struct IExtPackBase +{ + struct IExtPackBase_vtbl *vtbl; +}; +/* End of struct IExtPackBase Declaration */ + + +/* Start of struct IExtPack Declaration */ +#define IEXTPACK_IID_STR "431685da-3618-4ebc-b038-833ba829b4b2" +#define IEXTPACK_IID { \ + 0x431685da, 0x3618, 0x4ebc, \ + { 0xb0, 0x38, 0x83, 0x3b, 0xa8, 0x29, 0xb4, 0xb2 } \ +} +struct IExtPack_vtbl +{ + struct IExtPackBase_vtbl iextpackbase; + + nsresult (*QueryObject)( + IExtPack *pThis, + PRUnichar * objUuid, + nsISupports * * returnInterface + ); + +}; + +struct IExtPack +{ + struct IExtPack_vtbl *vtbl; +}; +/* End of struct IExtPack Declaration */ + + +/* Start of struct IExtPackFile Declaration */ +#define IEXTPACKFILE_IID_STR "b6b49f55-efcc-4f08-b486-56e8d8afb10b" +#define IEXTPACKFILE_IID { \ + 0xb6b49f55, 0xefcc, 0x4f08, \ + { 0xb4, 0x86, 0x56, 0xe8, 0xd8, 0xaf, 0xb1, 0x0b } \ +} +struct IExtPackFile_vtbl +{ + struct IExtPackBase_vtbl iextpackbase; + + nsresult (*GetFilePath)(IExtPackFile *pThis, PRUnichar * *filePath); + + nsresult (*Install)( + IExtPackFile *pThis, + PRBool replace, + PRUnichar * displayInfo, + IProgress * * progess + ); + +}; + +struct IExtPackFile +{ + struct IExtPackFile_vtbl *vtbl; +}; +/* End of struct IExtPackFile Declaration */ + + +/* Start of struct IExtPackManager Declaration */ +#define IEXTPACKMANAGER_IID_STR "3295e6ce-b051-47b2-9514-2c588bfe7554" +#define IEXTPACKMANAGER_IID { \ + 0x3295e6ce, 0xb051, 0x47b2, \ + { 0x95, 0x14, 0x2c, 0x58, 0x8b, 0xfe, 0x75, 0x54 } \ +} +struct IExtPackManager_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetInstalledExtPacks)(IExtPackManager *pThis, PRUint32 *installedExtPacksSize, IExtPack * **installedExtPacks); + + nsresult (*Find)( + IExtPackManager *pThis, + PRUnichar * name, + IExtPack * * returnData + ); + + nsresult (*OpenExtPackFile)( + IExtPackManager *pThis, + PRUnichar * path, + IExtPackFile * * file + ); + + nsresult (*Uninstall)( + IExtPackManager *pThis, + PRUnichar * name, + PRBool forcedRemoval, + PRUnichar * displayInfo, + IProgress * * progess + ); + + nsresult (*Cleanup)(IExtPackManager *pThis ); + + nsresult (*QueryAllPlugInsForFrontend)( + IExtPackManager *pThis, + PRUnichar * frontendName, + PRUint32 *plugInModulesSize, + PRUnichar *** plugInModules + ); + + nsresult (*IsExtPackUsable)( + IExtPackManager *pThis, + PRUnichar * name, + PRBool * usable + ); + +}; + +struct IExtPackManager +{ + struct IExtPackManager_vtbl *vtbl; +}; +/* End of struct IExtPackManager Declaration */ + + +/* Start of struct IBandwidthGroup Declaration */ +#define IBANDWIDTHGROUP_IID_STR "badea2d7-0261-4146-89f0-6a57cc34833d" +#define IBANDWIDTHGROUP_IID { \ + 0xbadea2d7, 0x0261, 0x4146, \ + { 0x89, 0xf0, 0x6a, 0x57, 0xcc, 0x34, 0x83, 0x3d } \ +} +struct IBandwidthGroup_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetName)(IBandwidthGroup *pThis, PRUnichar * *name); + + nsresult (*GetType)(IBandwidthGroup *pThis, PRUint32 *type); + + nsresult (*GetReference)(IBandwidthGroup *pThis, PRUint32 *reference); + + nsresult (*GetMaxBytesPerSec)(IBandwidthGroup *pThis, PRInt64 *maxBytesPerSec); + nsresult (*SetMaxBytesPerSec)(IBandwidthGroup *pThis, PRInt64 maxBytesPerSec); + +}; + +struct IBandwidthGroup +{ + struct IBandwidthGroup_vtbl *vtbl; +}; +/* End of struct IBandwidthGroup Declaration */ + + +/* Start of struct IBandwidthControl Declaration */ +#define IBANDWIDTHCONTROL_IID_STR "e2eb3930-d2f4-4f87-be17-0707e30f019f" +#define IBANDWIDTHCONTROL_IID { \ + 0xe2eb3930, 0xd2f4, 0x4f87, \ + { 0xbe, 0x17, 0x07, 0x07, 0xe3, 0x0f, 0x01, 0x9f } \ +} +struct IBandwidthControl_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetNumGroups)(IBandwidthControl *pThis, PRUint32 *numGroups); + + nsresult (*CreateBandwidthGroup)( + IBandwidthControl *pThis, + PRUnichar * name, + PRUint32 type, + PRInt64 maxBytesPerSec + ); + + nsresult (*DeleteBandwidthGroup)( + IBandwidthControl *pThis, + PRUnichar * name + ); + + nsresult (*GetBandwidthGroup)( + IBandwidthControl *pThis, + PRUnichar * name, + IBandwidthGroup * * bandwidthGroup + ); + + nsresult (*GetAllBandwidthGroups)( + IBandwidthControl *pThis, + PRUint32 *bandwidthGroupsSize, + IBandwidthGroup *** bandwidthGroups + ); + +}; + +struct IBandwidthControl +{ + struct IBandwidthControl_vtbl *vtbl; +}; +/* End of struct IBandwidthControl Declaration */ + + +/* Start of struct IVirtualBoxClient Declaration */ +#define IVIRTUALBOXCLIENT_IID_STR "5fe0bd48-1181-40d1-991f-3b02f269a823" +#define IVIRTUALBOXCLIENT_IID { \ + 0x5fe0bd48, 0x1181, 0x40d1, \ + { 0x99, 0x1f, 0x3b, 0x02, 0xf2, 0x69, 0xa8, 0x23 } \ +} +struct IVirtualBoxClient_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetVirtualBox)(IVirtualBoxClient *pThis, IVirtualBox * *virtualBox); + + nsresult (*GetSession)(IVirtualBoxClient *pThis, ISession * *session); + + nsresult (*GetEventSource)(IVirtualBoxClient *pThis, IEventSource * *eventSource); + +}; + +struct IVirtualBoxClient +{ + struct IVirtualBoxClient_vtbl *vtbl; +}; +/* End of struct IVirtualBoxClient Declaration */ + + +/* Start of struct IEventSource Declaration */ +#define IEVENTSOURCE_IID_STR "9b6e1aee-35f3-4f4d-b5bb-ed0ecefd8538" +#define IEVENTSOURCE_IID { \ + 0x9b6e1aee, 0x35f3, 0x4f4d, \ + { 0xb5, 0xbb, 0xed, 0x0e, 0xce, 0xfd, 0x85, 0x38 } \ +} +struct IEventSource_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*CreateListener)( + IEventSource *pThis, + IEventListener * * listener + ); + + nsresult (*CreateAggregator)( + IEventSource *pThis, + PRUint32 subordinatesSize, + IEventSource ** subordinates, + IEventSource * * result + ); + + nsresult (*RegisterListener)( + IEventSource *pThis, + IEventListener * listener, + PRUint32 interestingSize, + PRUint32* interesting, + PRBool active + ); + + nsresult (*UnregisterListener)( + IEventSource *pThis, + IEventListener * listener + ); + + nsresult (*FireEvent)( + IEventSource *pThis, + IEvent * event, + PRInt32 timeout, + PRBool * result + ); + + nsresult (*GetEvent)( + IEventSource *pThis, + IEventListener * listener, + PRInt32 timeout, + IEvent * * event + ); + + nsresult (*EventProcessed)( + IEventSource *pThis, + IEventListener * listener, + IEvent * event + ); + +}; + +struct IEventSource +{ + struct IEventSource_vtbl *vtbl; +}; +/* End of struct IEventSource Declaration */ + + +/* Start of struct IEventListener Declaration */ +#define IEVENTLISTENER_IID_STR "67099191-32e7-4f6c-85ee-422304c71b90" +#define IEVENTLISTENER_IID { \ + 0x67099191, 0x32e7, 0x4f6c, \ + { 0x85, 0xee, 0x42, 0x23, 0x04, 0xc7, 0x1b, 0x90 } \ +} +struct IEventListener_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*HandleEvent)( + IEventListener *pThis, + IEvent * event + ); + +}; + +struct IEventListener +{ + struct IEventListener_vtbl *vtbl; +}; +/* End of struct IEventListener Declaration */ + + +/* Start of struct IEvent Declaration */ +#define IEVENT_IID_STR "0ca2adba-8f30-401b-a8cd-fe31dbe839c0" +#define IEVENT_IID { \ + 0x0ca2adba, 0x8f30, 0x401b, \ + { 0xa8, 0xcd, 0xfe, 0x31, 0xdb, 0xe8, 0x39, 0xc0 } \ +} +struct IEvent_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetType)(IEvent *pThis, PRUint32 *type); + + nsresult (*GetSource)(IEvent *pThis, IEventSource * *source); + + nsresult (*GetWaitable)(IEvent *pThis, PRBool *waitable); + + nsresult (*SetProcessed)(IEvent *pThis ); + + nsresult (*WaitProcessed)( + IEvent *pThis, + PRInt32 timeout, + PRBool * result + ); + +}; + +struct IEvent +{ + struct IEvent_vtbl *vtbl; +}; +/* End of struct IEvent Declaration */ + + +/* Start of struct IReusableEvent Declaration */ +#define IREUSABLEEVENT_IID_STR "69bfb134-80f6-4266-8e20-16371f68fa25" +#define IREUSABLEEVENT_IID { \ + 0x69bfb134, 0x80f6, 0x4266, \ + { 0x8e, 0x20, 0x16, 0x37, 0x1f, 0x68, 0xfa, 0x25 } \ +} +struct IReusableEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetGeneration)(IReusableEvent *pThis, PRUint32 *generation); + + nsresult (*Reuse)(IReusableEvent *pThis ); + +}; + +struct IReusableEvent +{ + struct IReusableEvent_vtbl *vtbl; +}; +/* End of struct IReusableEvent Declaration */ + + +/* Start of struct IMachineEvent Declaration */ +#define IMACHINEEVENT_IID_STR "92ed7b1a-0d96-40ed-ae46-a564d484325e" +#define IMACHINEEVENT_IID { \ + 0x92ed7b1a, 0x0d96, 0x40ed, \ + { 0xae, 0x46, 0xa5, 0x64, 0xd4, 0x84, 0x32, 0x5e } \ +} +struct IMachineEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetMachineId)(IMachineEvent *pThis, PRUnichar * *machineId); + +}; + +struct IMachineEvent +{ + struct IMachineEvent_vtbl *vtbl; +}; +/* End of struct IMachineEvent Declaration */ + + +/* Start of struct IMachineStateChangedEvent Declaration */ +#define IMACHINESTATECHANGEDEVENT_IID_STR "5748F794-48DF-438D-85EB-98FFD70D18C9" +#define IMACHINESTATECHANGEDEVENT_IID { \ + 0x5748F794, 0x48DF, 0x438D, \ + { 0x85, 0xEB, 0x98, 0xFF, 0xD7, 0x0D, 0x18, 0xC9 } \ +} +struct IMachineStateChangedEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetState)(IMachineStateChangedEvent *pThis, PRUint32 *state); + +}; + +struct IMachineStateChangedEvent +{ + struct IMachineStateChangedEvent_vtbl *vtbl; +}; +/* End of struct IMachineStateChangedEvent Declaration */ + + +/* Start of struct IMachineDataChangedEvent Declaration */ +#define IMACHINEDATACHANGEDEVENT_IID_STR "abe94809-2e88-4436-83d7-50f3e64d0503" +#define IMACHINEDATACHANGEDEVENT_IID { \ + 0xabe94809, 0x2e88, 0x4436, \ + { 0x83, 0xd7, 0x50, 0xf3, 0xe6, 0x4d, 0x05, 0x03 } \ +} +struct IMachineDataChangedEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetTemporary)(IMachineDataChangedEvent *pThis, PRBool *temporary); + +}; + +struct IMachineDataChangedEvent +{ + struct IMachineDataChangedEvent_vtbl *vtbl; +}; +/* End of struct IMachineDataChangedEvent Declaration */ + + +/* Start of struct IMediumRegisteredEvent Declaration */ +#define IMEDIUMREGISTEREDEVENT_IID_STR "53fac49a-b7f1-4a5a-a4ef-a11dd9c2a458" +#define IMEDIUMREGISTEREDEVENT_IID { \ + 0x53fac49a, 0xb7f1, 0x4a5a, \ + { 0xa4, 0xef, 0xa1, 0x1d, 0xd9, 0xc2, 0xa4, 0x58 } \ +} +struct IMediumRegisteredEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetMediumId)(IMediumRegisteredEvent *pThis, PRUnichar * *mediumId); + + nsresult (*GetMediumType)(IMediumRegisteredEvent *pThis, PRUint32 *mediumType); + + nsresult (*GetRegistered)(IMediumRegisteredEvent *pThis, PRBool *registered); + +}; + +struct IMediumRegisteredEvent +{ + struct IMediumRegisteredEvent_vtbl *vtbl; +}; +/* End of struct IMediumRegisteredEvent Declaration */ + + +/* Start of struct IMachineRegisteredEvent Declaration */ +#define IMACHINEREGISTEREDEVENT_IID_STR "c354a762-3ff2-4f2e-8f09-07382ee25088" +#define IMACHINEREGISTEREDEVENT_IID { \ + 0xc354a762, 0x3ff2, 0x4f2e, \ + { 0x8f, 0x09, 0x07, 0x38, 0x2e, 0xe2, 0x50, 0x88 } \ +} +struct IMachineRegisteredEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetRegistered)(IMachineRegisteredEvent *pThis, PRBool *registered); + +}; + +struct IMachineRegisteredEvent +{ + struct IMachineRegisteredEvent_vtbl *vtbl; +}; +/* End of struct IMachineRegisteredEvent Declaration */ + + +/* Start of struct ISessionStateChangedEvent Declaration */ +#define ISESSIONSTATECHANGEDEVENT_IID_STR "714a3eef-799a-4489-86cd-fe8e45b2ff8e" +#define ISESSIONSTATECHANGEDEVENT_IID { \ + 0x714a3eef, 0x799a, 0x4489, \ + { 0x86, 0xcd, 0xfe, 0x8e, 0x45, 0xb2, 0xff, 0x8e } \ +} +struct ISessionStateChangedEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetState)(ISessionStateChangedEvent *pThis, PRUint32 *state); + +}; + +struct ISessionStateChangedEvent +{ + struct ISessionStateChangedEvent_vtbl *vtbl; +}; +/* End of struct ISessionStateChangedEvent Declaration */ + + +/* Start of struct IGuestPropertyChangedEvent Declaration */ +#define IGUESTPROPERTYCHANGEDEVENT_IID_STR "3f63597a-26f1-4edb-8dd2-6bddd0912368" +#define IGUESTPROPERTYCHANGEDEVENT_IID { \ + 0x3f63597a, 0x26f1, 0x4edb, \ + { 0x8d, 0xd2, 0x6b, 0xdd, 0xd0, 0x91, 0x23, 0x68 } \ +} +struct IGuestPropertyChangedEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetName)(IGuestPropertyChangedEvent *pThis, PRUnichar * *name); + + nsresult (*GetValue)(IGuestPropertyChangedEvent *pThis, PRUnichar * *value); + + nsresult (*GetFlags)(IGuestPropertyChangedEvent *pThis, PRUnichar * *flags); + +}; + +struct IGuestPropertyChangedEvent +{ + struct IGuestPropertyChangedEvent_vtbl *vtbl; +}; +/* End of struct IGuestPropertyChangedEvent Declaration */ + + +/* Start of struct ISnapshotEvent Declaration */ +#define ISNAPSHOTEVENT_IID_STR "21637b0e-34b8-42d3-acfb-7e96daf77c22" +#define ISNAPSHOTEVENT_IID { \ + 0x21637b0e, 0x34b8, 0x42d3, \ + { 0xac, 0xfb, 0x7e, 0x96, 0xda, 0xf7, 0x7c, 0x22 } \ +} +struct ISnapshotEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetSnapshotId)(ISnapshotEvent *pThis, PRUnichar * *snapshotId); + +}; + +struct ISnapshotEvent +{ + struct ISnapshotEvent_vtbl *vtbl; +}; +/* End of struct ISnapshotEvent Declaration */ + + +/* Start of struct ISnapshotTakenEvent Declaration */ +#define ISNAPSHOTTAKENEVENT_IID_STR "d27c0b3d-6038-422c-b45e-6d4a0503d9f1" +#define ISNAPSHOTTAKENEVENT_IID { \ + 0xd27c0b3d, 0x6038, 0x422c, \ + { 0xb4, 0x5e, 0x6d, 0x4a, 0x05, 0x03, 0xd9, 0xf1 } \ +} +struct ISnapshotTakenEvent_vtbl +{ + struct ISnapshotEvent_vtbl isnapshotevent; + +}; + +struct ISnapshotTakenEvent +{ + struct ISnapshotTakenEvent_vtbl *vtbl; +}; +/* End of struct ISnapshotTakenEvent Declaration */ + + +/* Start of struct ISnapshotDeletedEvent Declaration */ +#define ISNAPSHOTDELETEDEVENT_IID_STR "c48f3401-4a9e-43f4-b7a7-54bd285e22f4" +#define ISNAPSHOTDELETEDEVENT_IID { \ + 0xc48f3401, 0x4a9e, 0x43f4, \ + { 0xb7, 0xa7, 0x54, 0xbd, 0x28, 0x5e, 0x22, 0xf4 } \ +} +struct ISnapshotDeletedEvent_vtbl +{ + struct ISnapshotEvent_vtbl isnapshotevent; + +}; + +struct ISnapshotDeletedEvent +{ + struct ISnapshotDeletedEvent_vtbl *vtbl; +}; +/* End of struct ISnapshotDeletedEvent Declaration */ + + +/* Start of struct ISnapshotChangedEvent Declaration */ +#define ISNAPSHOTCHANGEDEVENT_IID_STR "07541941-8079-447a-a33e-47a69c7980db" +#define ISNAPSHOTCHANGEDEVENT_IID { \ + 0x07541941, 0x8079, 0x447a, \ + { 0xa3, 0x3e, 0x47, 0xa6, 0x9c, 0x79, 0x80, 0xdb } \ +} +struct ISnapshotChangedEvent_vtbl +{ + struct ISnapshotEvent_vtbl isnapshotevent; + +}; + +struct ISnapshotChangedEvent +{ + struct ISnapshotChangedEvent_vtbl *vtbl; +}; +/* End of struct ISnapshotChangedEvent Declaration */ + + +/* Start of struct IMousePointerShapeChangedEvent Declaration */ +#define IMOUSEPOINTERSHAPECHANGEDEVENT_IID_STR "a6dcf6e8-416b-4181-8c4a-45ec95177aef" +#define IMOUSEPOINTERSHAPECHANGEDEVENT_IID { \ + 0xa6dcf6e8, 0x416b, 0x4181, \ + { 0x8c, 0x4a, 0x45, 0xec, 0x95, 0x17, 0x7a, 0xef } \ +} +struct IMousePointerShapeChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetVisible)(IMousePointerShapeChangedEvent *pThis, PRBool *visible); + + nsresult (*GetAlpha)(IMousePointerShapeChangedEvent *pThis, PRBool *alpha); + + nsresult (*GetXhot)(IMousePointerShapeChangedEvent *pThis, PRUint32 *xhot); + + nsresult (*GetYhot)(IMousePointerShapeChangedEvent *pThis, PRUint32 *yhot); + + nsresult (*GetWidth)(IMousePointerShapeChangedEvent *pThis, PRUint32 *width); + + nsresult (*GetHeight)(IMousePointerShapeChangedEvent *pThis, PRUint32 *height); + + nsresult (*GetShape)(IMousePointerShapeChangedEvent *pThis, PRUint32 *shapeSize, PRUint8 **shape); + +}; + +struct IMousePointerShapeChangedEvent +{ + struct IMousePointerShapeChangedEvent_vtbl *vtbl; +}; +/* End of struct IMousePointerShapeChangedEvent Declaration */ + + +/* Start of struct IMouseCapabilityChangedEvent Declaration */ +#define IMOUSECAPABILITYCHANGEDEVENT_IID_STR "d633ad48-820c-4207-b46c-6bd3596640d5" +#define IMOUSECAPABILITYCHANGEDEVENT_IID { \ + 0xd633ad48, 0x820c, 0x4207, \ + { 0xb4, 0x6c, 0x6b, 0xd3, 0x59, 0x66, 0x40, 0xd5 } \ +} +struct IMouseCapabilityChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetSupportsAbsolute)(IMouseCapabilityChangedEvent *pThis, PRBool *supportsAbsolute); + + nsresult (*GetSupportsRelative)(IMouseCapabilityChangedEvent *pThis, PRBool *supportsRelative); + + nsresult (*GetNeedsHostCursor)(IMouseCapabilityChangedEvent *pThis, PRBool *needsHostCursor); + +}; + +struct IMouseCapabilityChangedEvent +{ + struct IMouseCapabilityChangedEvent_vtbl *vtbl; +}; +/* End of struct IMouseCapabilityChangedEvent Declaration */ + + +/* Start of struct IKeyboardLedsChangedEvent Declaration */ +#define IKEYBOARDLEDSCHANGEDEVENT_IID_STR "6DDEF35E-4737-457B-99FC-BC52C851A44F" +#define IKEYBOARDLEDSCHANGEDEVENT_IID { \ + 0x6DDEF35E, 0x4737, 0x457B, \ + { 0x99, 0xFC, 0xBC, 0x52, 0xC8, 0x51, 0xA4, 0x4F } \ +} +struct IKeyboardLedsChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetNumLock)(IKeyboardLedsChangedEvent *pThis, PRBool *numLock); + + nsresult (*GetCapsLock)(IKeyboardLedsChangedEvent *pThis, PRBool *capsLock); + + nsresult (*GetScrollLock)(IKeyboardLedsChangedEvent *pThis, PRBool *scrollLock); + +}; + +struct IKeyboardLedsChangedEvent +{ + struct IKeyboardLedsChangedEvent_vtbl *vtbl; +}; +/* End of struct IKeyboardLedsChangedEvent Declaration */ + + +/* Start of struct IStateChangedEvent Declaration */ +#define ISTATECHANGEDEVENT_IID_STR "4376693C-CF37-453B-9289-3B0F521CAF27" +#define ISTATECHANGEDEVENT_IID { \ + 0x4376693C, 0xCF37, 0x453B, \ + { 0x92, 0x89, 0x3B, 0x0F, 0x52, 0x1C, 0xAF, 0x27 } \ +} +struct IStateChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetState)(IStateChangedEvent *pThis, PRUint32 *state); + +}; + +struct IStateChangedEvent +{ + struct IStateChangedEvent_vtbl *vtbl; +}; +/* End of struct IStateChangedEvent Declaration */ + + +/* Start of struct IAdditionsStateChangedEvent Declaration */ +#define IADDITIONSSTATECHANGEDEVENT_IID_STR "D70F7915-DA7C-44C8-A7AC-9F173490446A" +#define IADDITIONSSTATECHANGEDEVENT_IID { \ + 0xD70F7915, 0xDA7C, 0x44C8, \ + { 0xA7, 0xAC, 0x9F, 0x17, 0x34, 0x90, 0x44, 0x6A } \ +} +struct IAdditionsStateChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + +}; + +struct IAdditionsStateChangedEvent +{ + struct IAdditionsStateChangedEvent_vtbl *vtbl; +}; +/* End of struct IAdditionsStateChangedEvent Declaration */ + + +/* Start of struct INetworkAdapterChangedEvent Declaration */ +#define INETWORKADAPTERCHANGEDEVENT_IID_STR "08889892-1EC6-4883-801D-77F56CFD0103" +#define INETWORKADAPTERCHANGEDEVENT_IID { \ + 0x08889892, 0x1EC6, 0x4883, \ + { 0x80, 0x1D, 0x77, 0xF5, 0x6C, 0xFD, 0x01, 0x03 } \ +} +struct INetworkAdapterChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetNetworkAdapter)(INetworkAdapterChangedEvent *pThis, INetworkAdapter * *networkAdapter); + +}; + +struct INetworkAdapterChangedEvent +{ + struct INetworkAdapterChangedEvent_vtbl *vtbl; +}; +/* End of struct INetworkAdapterChangedEvent Declaration */ + + +/* Start of struct ISerialPortChangedEvent Declaration */ +#define ISERIALPORTCHANGEDEVENT_IID_STR "3BA329DC-659C-488B-835C-4ECA7AE71C6C" +#define ISERIALPORTCHANGEDEVENT_IID { \ + 0x3BA329DC, 0x659C, 0x488B, \ + { 0x83, 0x5C, 0x4E, 0xCA, 0x7A, 0xE7, 0x1C, 0x6C } \ +} +struct ISerialPortChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetSerialPort)(ISerialPortChangedEvent *pThis, ISerialPort * *serialPort); + +}; + +struct ISerialPortChangedEvent +{ + struct ISerialPortChangedEvent_vtbl *vtbl; +}; +/* End of struct ISerialPortChangedEvent Declaration */ + + +/* Start of struct IParallelPortChangedEvent Declaration */ +#define IPARALLELPORTCHANGEDEVENT_IID_STR "813C99FC-9849-4F47-813E-24A75DC85615" +#define IPARALLELPORTCHANGEDEVENT_IID { \ + 0x813C99FC, 0x9849, 0x4F47, \ + { 0x81, 0x3E, 0x24, 0xA7, 0x5D, 0xC8, 0x56, 0x15 } \ +} +struct IParallelPortChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetParallelPort)(IParallelPortChangedEvent *pThis, IParallelPort * *parallelPort); + +}; + +struct IParallelPortChangedEvent +{ + struct IParallelPortChangedEvent_vtbl *vtbl; +}; +/* End of struct IParallelPortChangedEvent Declaration */ + + +/* Start of struct IStorageControllerChangedEvent Declaration */ +#define ISTORAGECONTROLLERCHANGEDEVENT_IID_STR "715212BF-DA59-426E-8230-3831FAA52C56" +#define ISTORAGECONTROLLERCHANGEDEVENT_IID { \ + 0x715212BF, 0xDA59, 0x426E, \ + { 0x82, 0x30, 0x38, 0x31, 0xFA, 0xA5, 0x2C, 0x56 } \ +} +struct IStorageControllerChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + +}; + +struct IStorageControllerChangedEvent +{ + struct IStorageControllerChangedEvent_vtbl *vtbl; +}; +/* End of struct IStorageControllerChangedEvent Declaration */ + + +/* Start of struct IMediumChangedEvent Declaration */ +#define IMEDIUMCHANGEDEVENT_IID_STR "0FE2DA40-5637-472A-9736-72019EABD7DE" +#define IMEDIUMCHANGEDEVENT_IID { \ + 0x0FE2DA40, 0x5637, 0x472A, \ + { 0x97, 0x36, 0x72, 0x01, 0x9E, 0xAB, 0xD7, 0xDE } \ +} +struct IMediumChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetMediumAttachment)(IMediumChangedEvent *pThis, IMediumAttachment * *mediumAttachment); + +}; + +struct IMediumChangedEvent +{ + struct IMediumChangedEvent_vtbl *vtbl; +}; +/* End of struct IMediumChangedEvent Declaration */ + + +/* Start of struct IClipboardModeChangedEvent Declaration */ +#define ICLIPBOARDMODECHANGEDEVENT_IID_STR "cac21692-7997-4595-a731-3a509db604e5" +#define ICLIPBOARDMODECHANGEDEVENT_IID { \ + 0xcac21692, 0x7997, 0x4595, \ + { 0xa7, 0x31, 0x3a, 0x50, 0x9d, 0xb6, 0x04, 0xe5 } \ +} +struct IClipboardModeChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetClipboardMode)(IClipboardModeChangedEvent *pThis, PRUint32 *clipboardMode); + +}; + +struct IClipboardModeChangedEvent +{ + struct IClipboardModeChangedEvent_vtbl *vtbl; +}; +/* End of struct IClipboardModeChangedEvent Declaration */ + + +/* Start of struct IDragAndDropModeChangedEvent Declaration */ +#define IDRAGANDDROPMODECHANGEDEVENT_IID_STR "e90b8850-ac8e-4dff-8059-4100ae2c3c3d" +#define IDRAGANDDROPMODECHANGEDEVENT_IID { \ + 0xe90b8850, 0xac8e, 0x4dff, \ + { 0x80, 0x59, 0x41, 0x00, 0xae, 0x2c, 0x3c, 0x3d } \ +} +struct IDragAndDropModeChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetDragAndDropMode)(IDragAndDropModeChangedEvent *pThis, PRUint32 *dragAndDropMode); + +}; + +struct IDragAndDropModeChangedEvent +{ + struct IDragAndDropModeChangedEvent_vtbl *vtbl; +}; +/* End of struct IDragAndDropModeChangedEvent Declaration */ + + +/* Start of struct ICPUChangedEvent Declaration */ +#define ICPUCHANGEDEVENT_IID_STR "4da2dec7-71b2-4817-9a64-4ed12c17388e" +#define ICPUCHANGEDEVENT_IID { \ + 0x4da2dec7, 0x71b2, 0x4817, \ + { 0x9a, 0x64, 0x4e, 0xd1, 0x2c, 0x17, 0x38, 0x8e } \ +} +struct ICPUChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetCPU)(ICPUChangedEvent *pThis, PRUint32 *CPU); + + nsresult (*GetAdd)(ICPUChangedEvent *pThis, PRBool *add); + +}; + +struct ICPUChangedEvent +{ + struct ICPUChangedEvent_vtbl *vtbl; +}; +/* End of struct ICPUChangedEvent Declaration */ + + +/* Start of struct ICPUExecutionCapChangedEvent Declaration */ +#define ICPUEXECUTIONCAPCHANGEDEVENT_IID_STR "dfa7e4f5-b4a4-44ce-85a8-127ac5eb59dc" +#define ICPUEXECUTIONCAPCHANGEDEVENT_IID { \ + 0xdfa7e4f5, 0xb4a4, 0x44ce, \ + { 0x85, 0xa8, 0x12, 0x7a, 0xc5, 0xeb, 0x59, 0xdc } \ +} +struct ICPUExecutionCapChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetExecutionCap)(ICPUExecutionCapChangedEvent *pThis, PRUint32 *executionCap); + +}; + +struct ICPUExecutionCapChangedEvent +{ + struct ICPUExecutionCapChangedEvent_vtbl *vtbl; +}; +/* End of struct ICPUExecutionCapChangedEvent Declaration */ + + +/* Start of struct IGuestKeyboardEvent Declaration */ +#define IGUESTKEYBOARDEVENT_IID_STR "88394258-7006-40d4-b339-472ee3801844" +#define IGUESTKEYBOARDEVENT_IID { \ + 0x88394258, 0x7006, 0x40d4, \ + { 0xb3, 0x39, 0x47, 0x2e, 0xe3, 0x80, 0x18, 0x44 } \ +} +struct IGuestKeyboardEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetScancodes)(IGuestKeyboardEvent *pThis, PRUint32 *scancodesSize, PRInt32 **scancodes); + +}; + +struct IGuestKeyboardEvent +{ + struct IGuestKeyboardEvent_vtbl *vtbl; +}; +/* End of struct IGuestKeyboardEvent Declaration */ + + +/* Start of struct IGuestMouseEvent Declaration */ +#define IGUESTMOUSEEVENT_IID_STR "1f85d35c-c524-40ff-8e98-307000df0992" +#define IGUESTMOUSEEVENT_IID { \ + 0x1f85d35c, 0xc524, 0x40ff, \ + { 0x8e, 0x98, 0x30, 0x70, 0x00, 0xdf, 0x09, 0x92 } \ +} +struct IGuestMouseEvent_vtbl +{ + struct IReusableEvent_vtbl ireusableevent; + + nsresult (*GetAbsolute)(IGuestMouseEvent *pThis, PRBool *absolute); + + nsresult (*GetX)(IGuestMouseEvent *pThis, PRInt32 *x); + + nsresult (*GetY)(IGuestMouseEvent *pThis, PRInt32 *y); + + nsresult (*GetZ)(IGuestMouseEvent *pThis, PRInt32 *z); + + nsresult (*GetW)(IGuestMouseEvent *pThis, PRInt32 *w); + + nsresult (*GetButtons)(IGuestMouseEvent *pThis, PRInt32 *buttons); + +}; + +struct IGuestMouseEvent +{ + struct IGuestMouseEvent_vtbl *vtbl; +}; +/* End of struct IGuestMouseEvent Declaration */ + + +/* Start of struct IVRDEServerChangedEvent Declaration */ +#define IVRDESERVERCHANGEDEVENT_IID_STR "a06fd66a-3188-4c8c-8756-1395e8cb691c" +#define IVRDESERVERCHANGEDEVENT_IID { \ + 0xa06fd66a, 0x3188, 0x4c8c, \ + { 0x87, 0x56, 0x13, 0x95, 0xe8, 0xcb, 0x69, 0x1c } \ +} +struct IVRDEServerChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + +}; + +struct IVRDEServerChangedEvent +{ + struct IVRDEServerChangedEvent_vtbl *vtbl; +}; +/* End of struct IVRDEServerChangedEvent Declaration */ + + +/* Start of struct IVRDEServerInfoChangedEvent Declaration */ +#define IVRDESERVERINFOCHANGEDEVENT_IID_STR "dd6a1080-e1b7-4339-a549-f0878115596e" +#define IVRDESERVERINFOCHANGEDEVENT_IID { \ + 0xdd6a1080, 0xe1b7, 0x4339, \ + { 0xa5, 0x49, 0xf0, 0x87, 0x81, 0x15, 0x59, 0x6e } \ +} +struct IVRDEServerInfoChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + +}; + +struct IVRDEServerInfoChangedEvent +{ + struct IVRDEServerInfoChangedEvent_vtbl *vtbl; +}; +/* End of struct IVRDEServerInfoChangedEvent Declaration */ + + +/* Start of struct IUSBControllerChangedEvent Declaration */ +#define IUSBCONTROLLERCHANGEDEVENT_IID_STR "93BADC0C-61D9-4940-A084-E6BB29AF3D83" +#define IUSBCONTROLLERCHANGEDEVENT_IID { \ + 0x93BADC0C, 0x61D9, 0x4940, \ + { 0xA0, 0x84, 0xE6, 0xBB, 0x29, 0xAF, 0x3D, 0x83 } \ +} +struct IUSBControllerChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + +}; + +struct IUSBControllerChangedEvent +{ + struct IUSBControllerChangedEvent_vtbl *vtbl; +}; +/* End of struct IUSBControllerChangedEvent Declaration */ + + +/* Start of struct IUSBDeviceStateChangedEvent Declaration */ +#define IUSBDEVICESTATECHANGEDEVENT_IID_STR "806da61b-6679-422a-b629-51b06b0c6d93" +#define IUSBDEVICESTATECHANGEDEVENT_IID { \ + 0x806da61b, 0x6679, 0x422a, \ + { 0xb6, 0x29, 0x51, 0xb0, 0x6b, 0x0c, 0x6d, 0x93 } \ +} +struct IUSBDeviceStateChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetDevice)(IUSBDeviceStateChangedEvent *pThis, IUSBDevice * *device); + + nsresult (*GetAttached)(IUSBDeviceStateChangedEvent *pThis, PRBool *attached); + + nsresult (*GetError)(IUSBDeviceStateChangedEvent *pThis, IVirtualBoxErrorInfo * *error); + +}; + +struct IUSBDeviceStateChangedEvent +{ + struct IUSBDeviceStateChangedEvent_vtbl *vtbl; +}; +/* End of struct IUSBDeviceStateChangedEvent Declaration */ + + +/* Start of struct ISharedFolderChangedEvent Declaration */ +#define ISHAREDFOLDERCHANGEDEVENT_IID_STR "B66349B5-3534-4239-B2DE-8E1535D94C0B" +#define ISHAREDFOLDERCHANGEDEVENT_IID { \ + 0xB66349B5, 0x3534, 0x4239, \ + { 0xB2, 0xDE, 0x8E, 0x15, 0x35, 0xD9, 0x4C, 0x0B } \ +} +struct ISharedFolderChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetScope)(ISharedFolderChangedEvent *pThis, PRUint32 *scope); + +}; + +struct ISharedFolderChangedEvent +{ + struct ISharedFolderChangedEvent_vtbl *vtbl; +}; +/* End of struct ISharedFolderChangedEvent Declaration */ + + +/* Start of struct IRuntimeErrorEvent Declaration */ +#define IRUNTIMEERROREVENT_IID_STR "883DD18B-0721-4CDE-867C-1A82ABAF914C" +#define IRUNTIMEERROREVENT_IID { \ + 0x883DD18B, 0x0721, 0x4CDE, \ + { 0x86, 0x7C, 0x1A, 0x82, 0xAB, 0xAF, 0x91, 0x4C } \ +} +struct IRuntimeErrorEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetFatal)(IRuntimeErrorEvent *pThis, PRBool *fatal); + + nsresult (*GetId)(IRuntimeErrorEvent *pThis, PRUnichar * *id); + + nsresult (*GetMessage)(IRuntimeErrorEvent *pThis, PRUnichar * *message); + +}; + +struct IRuntimeErrorEvent +{ + struct IRuntimeErrorEvent_vtbl *vtbl; +}; +/* End of struct IRuntimeErrorEvent Declaration */ + + +/* Start of struct IEventSourceChangedEvent Declaration */ +#define IEVENTSOURCECHANGEDEVENT_IID_STR "e7932cb8-f6d4-4ab6-9cbf-558eb8959a6a" +#define IEVENTSOURCECHANGEDEVENT_IID { \ + 0xe7932cb8, 0xf6d4, 0x4ab6, \ + { 0x9c, 0xbf, 0x55, 0x8e, 0xb8, 0x95, 0x9a, 0x6a } \ +} +struct IEventSourceChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetListener)(IEventSourceChangedEvent *pThis, IEventListener * *listener); + + nsresult (*GetAdd)(IEventSourceChangedEvent *pThis, PRBool *add); + +}; + +struct IEventSourceChangedEvent +{ + struct IEventSourceChangedEvent_vtbl *vtbl; +}; +/* End of struct IEventSourceChangedEvent Declaration */ + + +/* Start of struct IExtraDataChangedEvent Declaration */ +#define IEXTRADATACHANGEDEVENT_IID_STR "024F00CE-6E0B-492A-A8D0-968472A94DC7" +#define IEXTRADATACHANGEDEVENT_IID { \ + 0x024F00CE, 0x6E0B, 0x492A, \ + { 0xA8, 0xD0, 0x96, 0x84, 0x72, 0xA9, 0x4D, 0xC7 } \ +} +struct IExtraDataChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetMachineId)(IExtraDataChangedEvent *pThis, PRUnichar * *machineId); + + nsresult (*GetKey)(IExtraDataChangedEvent *pThis, PRUnichar * *key); + + nsresult (*GetValue)(IExtraDataChangedEvent *pThis, PRUnichar * *value); + +}; + +struct IExtraDataChangedEvent +{ + struct IExtraDataChangedEvent_vtbl *vtbl; +}; +/* End of struct IExtraDataChangedEvent Declaration */ + + +/* Start of struct IVetoEvent Declaration */ +#define IVETOEVENT_IID_STR "9a1a4130-69fe-472f-ac10-c6fa25d75007" +#define IVETOEVENT_IID { \ + 0x9a1a4130, 0x69fe, 0x472f, \ + { 0xac, 0x10, 0xc6, 0xfa, 0x25, 0xd7, 0x50, 0x07 } \ +} +struct IVetoEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*AddVeto)( + IVetoEvent *pThis, + PRUnichar * reason + ); + + nsresult (*IsVetoed)( + IVetoEvent *pThis, + PRBool * result + ); + + nsresult (*GetVetos)( + IVetoEvent *pThis, + PRUint32 *resultSize, + PRUnichar *** result + ); + +}; + +struct IVetoEvent +{ + struct IVetoEvent_vtbl *vtbl; +}; +/* End of struct IVetoEvent Declaration */ + + +/* Start of struct IExtraDataCanChangeEvent Declaration */ +#define IEXTRADATACANCHANGEEVENT_IID_STR "245d88bd-800a-40f8-87a6-170d02249a55" +#define IEXTRADATACANCHANGEEVENT_IID { \ + 0x245d88bd, 0x800a, 0x40f8, \ + { 0x87, 0xa6, 0x17, 0x0d, 0x02, 0x24, 0x9a, 0x55 } \ +} +struct IExtraDataCanChangeEvent_vtbl +{ + struct IVetoEvent_vtbl ivetoevent; + + nsresult (*GetMachineId)(IExtraDataCanChangeEvent *pThis, PRUnichar * *machineId); + + nsresult (*GetKey)(IExtraDataCanChangeEvent *pThis, PRUnichar * *key); + + nsresult (*GetValue)(IExtraDataCanChangeEvent *pThis, PRUnichar * *value); + +}; + +struct IExtraDataCanChangeEvent +{ + struct IExtraDataCanChangeEvent_vtbl *vtbl; +}; +/* End of struct IExtraDataCanChangeEvent Declaration */ + + +/* Start of struct ICanShowWindowEvent Declaration */ +#define ICANSHOWWINDOWEVENT_IID_STR "adf292b0-92c9-4a77-9d35-e058b39fe0b9" +#define ICANSHOWWINDOWEVENT_IID { \ + 0xadf292b0, 0x92c9, 0x4a77, \ + { 0x9d, 0x35, 0xe0, 0x58, 0xb3, 0x9f, 0xe0, 0xb9 } \ +} +struct ICanShowWindowEvent_vtbl +{ + struct IVetoEvent_vtbl ivetoevent; + +}; + +struct ICanShowWindowEvent +{ + struct ICanShowWindowEvent_vtbl *vtbl; +}; +/* End of struct ICanShowWindowEvent Declaration */ + + +/* Start of struct IShowWindowEvent Declaration */ +#define ISHOWWINDOWEVENT_IID_STR "B0A0904D-2F05-4D28-855F-488F96BAD2B2" +#define ISHOWWINDOWEVENT_IID { \ + 0xB0A0904D, 0x2F05, 0x4D28, \ + { 0x85, 0x5F, 0x48, 0x8F, 0x96, 0xBA, 0xD2, 0xB2 } \ +} +struct IShowWindowEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetWinId)(IShowWindowEvent *pThis, PRInt64 *winId); + nsresult (*SetWinId)(IShowWindowEvent *pThis, PRInt64 winId); + +}; + +struct IShowWindowEvent +{ + struct IShowWindowEvent_vtbl *vtbl; +}; +/* End of struct IShowWindowEvent Declaration */ + + +/* Start of struct INATRedirectEvent Declaration */ +#define INATREDIRECTEVENT_IID_STR "24eef068-c380-4510-bc7c-19314a7352f1" +#define INATREDIRECTEVENT_IID { \ + 0x24eef068, 0xc380, 0x4510, \ + { 0xbc, 0x7c, 0x19, 0x31, 0x4a, 0x73, 0x52, 0xf1 } \ +} +struct INATRedirectEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetSlot)(INATRedirectEvent *pThis, PRUint32 *slot); + + nsresult (*GetRemove)(INATRedirectEvent *pThis, PRBool *remove); + + nsresult (*GetName)(INATRedirectEvent *pThis, PRUnichar * *name); + + nsresult (*GetProto)(INATRedirectEvent *pThis, PRUint32 *proto); + + nsresult (*GetHostIP)(INATRedirectEvent *pThis, PRUnichar * *hostIP); + + nsresult (*GetHostPort)(INATRedirectEvent *pThis, PRInt32 *hostPort); + + nsresult (*GetGuestIP)(INATRedirectEvent *pThis, PRUnichar * *guestIP); + + nsresult (*GetGuestPort)(INATRedirectEvent *pThis, PRInt32 *guestPort); + +}; + +struct INATRedirectEvent +{ + struct INATRedirectEvent_vtbl *vtbl; +}; +/* End of struct INATRedirectEvent Declaration */ + + +/* Start of struct IHostPCIDevicePlugEvent Declaration */ +#define IHOSTPCIDEVICEPLUGEVENT_IID_STR "a0bad6df-d612-47d3-89d4-db3992533948" +#define IHOSTPCIDEVICEPLUGEVENT_IID { \ + 0xa0bad6df, 0xd612, 0x47d3, \ + { 0x89, 0xd4, 0xdb, 0x39, 0x92, 0x53, 0x39, 0x48 } \ +} +struct IHostPCIDevicePlugEvent_vtbl +{ + struct IMachineEvent_vtbl imachineevent; + + nsresult (*GetPlugged)(IHostPCIDevicePlugEvent *pThis, PRBool *plugged); + + nsresult (*GetSuccess)(IHostPCIDevicePlugEvent *pThis, PRBool *success); + + nsresult (*GetAttachment)(IHostPCIDevicePlugEvent *pThis, IPCIDeviceAttachment * *attachment); + + nsresult (*GetMessage)(IHostPCIDevicePlugEvent *pThis, PRUnichar * *message); + +}; + +struct IHostPCIDevicePlugEvent +{ + struct IHostPCIDevicePlugEvent_vtbl *vtbl; +}; +/* End of struct IHostPCIDevicePlugEvent Declaration */ + + +/* Start of struct IVBoxSVCAvailabilityChangedEvent Declaration */ +#define IVBOXSVCAVAILABILITYCHANGEDEVENT_IID_STR "97c78fcd-d4fc-485f-8613-5af88bfcfcdc" +#define IVBOXSVCAVAILABILITYCHANGEDEVENT_IID { \ + 0x97c78fcd, 0xd4fc, 0x485f, \ + { 0x86, 0x13, 0x5a, 0xf8, 0x8b, 0xfc, 0xfc, 0xdc } \ +} +struct IVBoxSVCAvailabilityChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetAvailable)(IVBoxSVCAvailabilityChangedEvent *pThis, PRBool *available); + +}; + +struct IVBoxSVCAvailabilityChangedEvent +{ + struct IVBoxSVCAvailabilityChangedEvent_vtbl *vtbl; +}; +/* End of struct IVBoxSVCAvailabilityChangedEvent Declaration */ + + +/* Start of struct IBandwidthGroupChangedEvent Declaration */ +#define IBANDWIDTHGROUPCHANGEDEVENT_IID_STR "334df94a-7556-4cbc-8c04-043096b02d82" +#define IBANDWIDTHGROUPCHANGEDEVENT_IID { \ + 0x334df94a, 0x7556, 0x4cbc, \ + { 0x8c, 0x04, 0x04, 0x30, 0x96, 0xb0, 0x2d, 0x82 } \ +} +struct IBandwidthGroupChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetBandwidthGroup)(IBandwidthGroupChangedEvent *pThis, IBandwidthGroup * *bandwidthGroup); + +}; + +struct IBandwidthGroupChangedEvent +{ + struct IBandwidthGroupChangedEvent_vtbl *vtbl; +}; +/* End of struct IBandwidthGroupChangedEvent Declaration */ + + +/* Start of struct IGuestMonitorChangedEvent Declaration */ +#define IGUESTMONITORCHANGEDEVENT_IID_STR "0f7b8a22-c71f-4a36-8e5f-a77d01d76090" +#define IGUESTMONITORCHANGEDEVENT_IID { \ + 0x0f7b8a22, 0xc71f, 0x4a36, \ + { 0x8e, 0x5f, 0xa7, 0x7d, 0x01, 0xd7, 0x60, 0x90 } \ +} +struct IGuestMonitorChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetChangeType)(IGuestMonitorChangedEvent *pThis, PRUint32 *changeType); + + nsresult (*GetScreenId)(IGuestMonitorChangedEvent *pThis, PRUint32 *screenId); + + nsresult (*GetOriginX)(IGuestMonitorChangedEvent *pThis, PRUint32 *originX); + + nsresult (*GetOriginY)(IGuestMonitorChangedEvent *pThis, PRUint32 *originY); + + nsresult (*GetWidth)(IGuestMonitorChangedEvent *pThis, PRUint32 *width); + + nsresult (*GetHeight)(IGuestMonitorChangedEvent *pThis, PRUint32 *height); + +}; + +struct IGuestMonitorChangedEvent +{ + struct IGuestMonitorChangedEvent_vtbl *vtbl; +}; +/* End of struct IGuestMonitorChangedEvent Declaration */ + + +/* Start of struct IStorageDeviceChangedEvent Declaration */ +#define ISTORAGEDEVICECHANGEDEVENT_IID_STR "8a5c2dce-e341-49d4-afce-c95979f7d70c" +#define ISTORAGEDEVICECHANGEDEVENT_IID { \ + 0x8a5c2dce, 0xe341, 0x49d4, \ + { 0xaf, 0xce, 0xc9, 0x59, 0x79, 0xf7, 0xd7, 0x0c } \ +} +struct IStorageDeviceChangedEvent_vtbl +{ + struct IEvent_vtbl ievent; + + nsresult (*GetStorageDevice)(IStorageDeviceChangedEvent *pThis, IMediumAttachment * *storageDevice); + + nsresult (*GetRemoved)(IStorageDeviceChangedEvent *pThis, PRBool *removed); + +}; + +struct IStorageDeviceChangedEvent +{ + struct IStorageDeviceChangedEvent_vtbl *vtbl; +}; +/* End of struct IStorageDeviceChangedEvent Declaration */ + + + +#define NS_VIRTUALBOX_CID { \ + 0xB1A7A4F2, 0x47B9, 0x4A1E, \ + { 0x82, 0xB2, 0x07, 0xCC, 0xD5, 0x32, 0x3C, 0x3F } \ +} +#define NS_VIRTUALBOX_CONTRACTID "@virtualbox.org/VirtualBox;1" +/* for compatibility with Win32 */ +#define CLSID_VirtualBox (nsCID) NS_VIRTUALBOX_CID + + + +#define NS_VIRTUALBOXCLIENT_CID { \ + 0xdd3fc71d, 0x26c0, 0x4fe1, \ + { 0xbf, 0x6f, 0x67, 0xf6, 0x33, 0x26, 0x5b, 0xba } \ +} +#define NS_VIRTUALBOXCLIENT_CONTRACTID "@virtualbox.org/VirtualBoxClient;1" +/* for compatibility with Win32 */ +#define CLSID_VirtualBoxClient (nsCID) NS_VIRTUALBOXCLIENT_CID + + + +#define NS_SESSION_CID { \ + 0x3C02F46D, 0xC9D2, 0x4F11, \ + { 0xA3, 0x84, 0x53, 0xF0, 0xCF, 0x91, 0x72, 0x14 } \ +} +#define NS_SESSION_CONTRACTID "@virtualbox.org/Session;1" +/* for compatibility with Win32 */ +#define CLSID_Session (nsCID) NS_SESSION_CID + + + +#endif /* !__cplusplus */ + +#ifdef IN_VBOXXPCOMC +# define VBOXXPCOMC_DECL(type) PR_EXPORT(type) +#else +# define VBOXXPCOMC_DECL(type) PR_IMPORT(type) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Function table for dynamic linking. + * Use VBoxGetFunctions() to obtain the pointer to it. + */ +typedef struct VBOXXPCOMC +{ + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + /** Gets the VirtualBox version, major * 1000000 + minor * 1000 + patch. */ + unsigned int (*pfnGetVersion)(void); + + /** Gets the VirtualBox API version, major * 1000 + minor, e.g. 4003. */ + unsigned int (*pfnGetAPIVersion)(void); + + /** + * New and preferred way to initialize the C bindings for an API client. + * + * This way is much more flexible, as it can easily handle multiple + * sessions (important with more complicated API clients, including + * multithreaded ones), and even VBoxSVC crashes can be detected and + * processed appropriately by listening for events from the associated + * event source in VirtualBoxClient. It is completely up to the client + * to decide what to do (terminate or continue after getting new + * object references to server-side objects). Must be called in the + * primary thread of the client, later API use can be done in any + * thread. + * + * Note that the returned reference is owned by the caller, and thus it's + * the caller's responsibility to handle the reference count appropriately. + * + * @param pszVirtualBoxClientIID pass IVIRTUALBOXCLIENT_IID_STR + * @param ppVirtualBoxClient output parameter for VirtualBoxClient + * reference, handled as usual with XPCOM. + * @returns XPCOM error code + */ + nsresult (*pfnClientInitialize)(const char *pszVirtualBoxClientIID, + IVirtualBoxClient **ppVirtualBoxClient); + /** + * Uninitialize the C bindings for an API client. + * + * Should be called when the API client is about to terminate and does + * not want to use the C bindings any more. It will invalidate all + * object references. It is possible, however, to change one's mind, + * and call pfnClientInitialize again to continue using the API, as long + * as none of the object references from before the re-initialization + * are used. Must be called from the primary thread of the client. + */ + void (*pfnClientUninitialize)(void); + + /** + * Deprecated way to initialize the C bindings and getting important + * object references. Kept for backwards compatibility. + * + * If any returned reference is NULL then the initialization failed. + * Note that the returned references are owned by the C bindings. The + * number of calls to Release in the client code must match the number + * of calls to AddRef, and additionally at no point in time there can + * be more Release calls than AddRef calls. + * + * @param pszVirtualBoxIID pass IVIRTUALBOX_IID_STR + * @param ppVirtualBox output parameter for VirtualBox reference, + * owned by C bindings + * @param pszSessionIID pass ISESSION_IID_STR + * @param ppSession output parameter for Session reference, + * owned by C bindings + */ + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + /** + * Deprecated way to uninitialize the C bindings for an API client. + * Kept for backwards compatibility and must be used if the C bindings + * were initialized using pfnComInitialize. */ + void (*pfnComUninitialize)(void); + + /** + * Free memory managed by XPCOM. + * + * @param pv pointer to memory block to be freed + */ + void (*pfnComUnallocMem)(void *pv); + + /** + * Convert string from UTF-16 encoding to UTF-8 encoding. + * + * @param pwszString input string + * @param ppszString output string + * @returns IPRT status code + */ + int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString); + /** + * Convert string from UTF-8 encoding to UTF-16 encoding. + * + * @param pszString input string + * @param ppwszString output string + * @returns IPRT status code + */ + int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString); + /** + * Free memory returned by pfnUtf16ToUtf8. Do not use for anything else. + * + * @param pszString string to be freed. + */ + void (*pfnUtf8Free)(char *pszString); + /** + * Free memory returned by pfnUtf8ToUtf16. Do not use for anything else. + * + * @param pwszString string to be freed. + */ + void (*pfnUtf16Free)(PRUnichar *pwszString); + + /** + * Get main XPCOM event queue. + * + * @param ppEventQueue output parameter for nsIEventQueue reference, + * owned by C bindings. + */ + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); + + /** + * Get current XPCOM exception. + * + * @param ppException output parameter for nsIException reference, + * may be @c NULL if no exception object has been created by + * a previous XPCOM call. + * @returns XPCOM error code + */ + nsresult (*pfnGetException)(nsIException **ppException); + /** + * Clears current XPCOM exception. + * + * @returns XPCOM error code + */ + nsresult (*pfnClearException)(void); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; +} VBOXXPCOMC; +/** Pointer to a const VBoxXPCOMC function table. */ +typedef VBOXXPCOMC const *PCVBOXXPCOM; + +/** The current interface version. + * For use with VBoxGetXPCOMCFunctions and to be found in + * VBOXXPCOMC::uVersion. */ +#define VBOX_XPCOMC_VERSION 0x00030000U + +VBOXXPCOMC_DECL(PCVBOXXPCOM) VBoxGetXPCOMCFunctions(unsigned uVersion); +/** Typedef for VBoxGetXPCOMCFunctions. */ +typedef PCVBOXXPCOM (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion); + +/** The symbol name of VBoxGetXPCOMCFunctions. */ +#if defined(__OS2__) +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "_VBoxGetXPCOMCFunctions" +#else +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "VBoxGetXPCOMCFunctions" +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* !___VirtualBox_CXPCOM_h */ diff --git a/src/VBox/Main/cbinding/VBoxXPCOMC.cpp b/src/VBox/Main/cbinding/VBoxXPCOMC.cpp deleted file mode 100644 index 63c6ab4f..00000000 --- a/src/VBox/Main/cbinding/VBoxXPCOMC.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* $Id: VBoxXPCOMC.cpp $ */ -/** @file VBoxXPCOMC.cpp - * Utility functions to use with the C binding for XPCOM. - */ - -/* - * Copyright (C) 2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -#define LOG_GROUP LOG_GROUP_MAIN -#include -#include -#include - -#include -#include -#include - -#include "VBoxCAPI.h" -#include "VBox/com/com.h" -#include "VBox/version.h" - -using namespace std; - -static ISession *Session = NULL; -static IVirtualBox *Ivirtualbox = NULL; -static nsIComponentManager *manager = NULL; -static nsIEventQueue *eventQ = NULL; - -static void VBoxComUninitialize(void); - -static int -VBoxUtf16ToUtf8(const PRUnichar *pwszString, char **ppszString) -{ - return RTUtf16ToUtf8(pwszString, ppszString); -} - -static int -VBoxUtf8ToUtf16(const char *pszString, PRUnichar **ppwszString) -{ - return RTStrToUtf16(pszString, ppwszString); -} - -static void -VBoxUtf16Free(PRUnichar *pwszString) -{ - RTUtf16Free(pwszString); -} - -static void -VBoxUtf8Free(char *pszString) -{ - RTStrFree(pszString); -} - -static void -VBoxComUnallocMem(void *ptr) -{ - if (ptr) - { - nsMemory::Free(ptr); - } -} - -static void -VBoxComInitialize(const char *pszVirtualBoxIID, IVirtualBox **ppVirtualBox, - const char *pszSessionIID, ISession **ppSession) -{ - nsresult rc; - nsID virtualBoxIID; - nsID sessionIID; - - *ppSession = NULL; - *ppVirtualBox = NULL; - - /* convert the string representation of UUID to nsIID type */ - if (!(virtualBoxIID.Parse(pszVirtualBoxIID) && sessionIID.Parse(pszSessionIID))) - return; - - rc = com::Initialize(); - if (NS_FAILED(rc)) - { - Log(("Cbinding: XPCOM could not be initialized! rc=%Rhrc\n", rc)); - VBoxComUninitialize(); - return; - } - - rc = NS_GetComponentManager (&manager); - if (NS_FAILED(rc)) - { - Log(("Cbinding: Could not get component manager! rc=%Rhrc\n", rc)); - VBoxComUninitialize(); - return; - } - - rc = NS_GetMainEventQ (&eventQ); - if (NS_FAILED(rc)) - { - Log(("Cbinding: Could not get xpcom event queue! rc=%Rhrc\n", rc)); - VBoxComUninitialize(); - return; - } - - rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID, - nsnull, - virtualBoxIID, - (void **)ppVirtualBox); - if (NS_FAILED(rc)) - { - Log(("Cbinding: Could not instantiate VirtualBox object! rc=%Rhrc\n",rc)); - VBoxComUninitialize(); - return; - } - - Log(("Cbinding: IVirtualBox object created.\n")); - - rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID, - nsnull, - sessionIID, - (void **)ppSession); - if (NS_FAILED(rc)) - { - Log(("Cbinding: Could not instantiate Session object! rc=%Rhrc\n",rc)); - VBoxComUninitialize(); - return; - } - - Log(("Cbinding: ISession object created.\n")); - - /* Store ppSession & ppVirtualBox so that VBoxComUninitialize - * can later take care of them while cleanup - */ - Session = *ppSession; - Ivirtualbox = *ppVirtualBox; - -} - -static void -VBoxComInitializeV1(IVirtualBox **ppVirtualBox, ISession **ppSession) -{ - /* stub that always fails. */ - *ppVirtualBox = NULL; - *ppSession = NULL; -} - -static void -VBoxComUninitialize(void) -{ - if (Session) - NS_RELEASE(Session); // decrement refcount - if (Ivirtualbox) - NS_RELEASE(Ivirtualbox); // decrement refcount - if (eventQ) - NS_RELEASE(eventQ); // decrement refcount - if (manager) - NS_RELEASE(manager); // decrement refcount - com::Shutdown(); - Log(("Cbinding: Cleaned up the created IVirtualBox and ISession Objects.\n")); -} - -static void -VBoxGetEventQueue(nsIEventQueue **eventQueue) -{ - *eventQueue = eventQ; -} - -static uint32_t -VBoxVersion(void) -{ - uint32_t version = 0; - - version = (VBOX_VERSION_MAJOR * 1000 * 1000) + (VBOX_VERSION_MINOR * 1000) + (VBOX_VERSION_BUILD); - - return version; -} - -VBOXXPCOMC_DECL(PCVBOXXPCOM) -VBoxGetXPCOMCFunctions(unsigned uVersion) -{ - /* - * The current interface version. - */ - static const VBOXXPCOMC s_Functions = - { - sizeof(VBOXXPCOMC), - VBOX_XPCOMC_VERSION, - - VBoxVersion, - - VBoxComInitialize, - VBoxComUninitialize, - - VBoxComUnallocMem, - VBoxUtf16Free, - VBoxUtf8Free, - - VBoxUtf16ToUtf8, - VBoxUtf8ToUtf16, - - VBoxGetEventQueue, - - VBOX_XPCOMC_VERSION - }; - - if ((uVersion & 0xffff0000U) == (VBOX_XPCOMC_VERSION & 0xffff0000U)) - return &s_Functions; - - /* - * Legacy interface version 1.0. - */ - static const struct VBOXXPCOMCV1 - { - /** The size of the structure. */ - unsigned cb; - /** The structure version. */ - unsigned uVersion; - - unsigned int (*pfnGetVersion)(void); - - void (*pfnComInitialize)(IVirtualBox **virtualBox, ISession **session); - void (*pfnComUninitialize)(void); - - void (*pfnComUnallocMem)(void *pv); - void (*pfnUtf16Free)(PRUnichar *pwszString); - void (*pfnUtf8Free)(char *pszString); - - int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString); - int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString); - - /** Tail version, same as uVersion. */ - unsigned uEndVersion; - } s_Functions_v1_0 = - { - sizeof(s_Functions_v1_0), - 0x00010000U, - - VBoxVersion, - - VBoxComInitializeV1, - VBoxComUninitialize, - - VBoxComUnallocMem, - VBoxUtf16Free, - VBoxUtf8Free, - - VBoxUtf16ToUtf8, - VBoxUtf8ToUtf16, - - 0x00010000U - }; - - if ((uVersion & 0xffff0000U) == 0x00010000U) - return (PCVBOXXPCOM)&s_Functions_v1_0; - - /* - * Unsupported interface version. - */ - return NULL; -} - -/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/VBoxXPCOMCGlue.c b/src/VBox/Main/cbinding/VBoxXPCOMCGlue.c deleted file mode 100644 index 3484ad65..00000000 --- a/src/VBox/Main/cbinding/VBoxXPCOMCGlue.c +++ /dev/null @@ -1,242 +0,0 @@ -/* $Revision: 66985 $ */ -/** @file - * Glue code for dynamically linking to VBoxXPCOMC. - */ - -/* - * Copyright (C) 2008-2010 Oracle Corporation - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include "VBoxXPCOMCGlue.h" - - -/******************************************************************************* -* Defined Constants And Macros * -*******************************************************************************/ -#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__) -# define DYNLIB_NAME "VBoxXPCOMC.so" -#elif defined(__APPLE__) -# define DYNLIB_NAME "VBoxXPCOMC.dylib" -#elif defined(_MSC_VER) || defined(__OS2__) -# define DYNLIB_NAME "VBoxXPCOMC.dll" -#else -# error "Port me" -#endif - - -/******************************************************************************* -* Global Variables * -*******************************************************************************/ -/** The dlopen handle for VBoxXPCOMC. */ -void *g_hVBoxXPCOMC = NULL; -/** The last load error. */ -char g_szVBoxErrMsg[256]; -/** Pointer to the VBoxXPCOMC function table. */ -PCVBOXXPCOM g_pVBoxFuncs = NULL; -/** Pointer to VBoxGetXPCOMCFunctions for the loaded VBoxXPCOMC so/dylib/dll. */ -PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL; - - -/** - * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub. - * - * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty. - * @param pszFormat The format string. - * @param ... The arguments. - */ -static void setErrMsg(int fAlways, const char *pszFormat, ...) -{ - if ( fAlways - || !g_szVBoxErrMsg[0]) - { - va_list va; - va_start(va, pszFormat); - vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va); - va_end(va); - } -} - - -/** - * Try load VBoxXPCOMC.so/dylib/dll from the specified location and resolve all - * the symbols we need. - * - * @returns 0 on success, -1 on failure. - * @param pszHome The director where to try load VBoxXPCOMC from. Can - * be NULL. - * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not - * (boolean). - */ -static int tryLoadOne(const char *pszHome, int fSetAppHome) -{ - size_t cchHome = pszHome ? strlen(pszHome) : 0; - size_t cbBufNeeded; - char szName[4096]; - int rc = -1; - - /* - * Construct the full name. - */ - cbBufNeeded = cchHome + sizeof("/" DYNLIB_NAME); - if (cbBufNeeded > sizeof(szName)) - { - setErrMsg(1, "path buffer too small: %u bytes needed", - (unsigned)cbBufNeeded); - return -1; - } - if (cchHome) - { - memcpy(szName, pszHome, cchHome); - szName[cchHome] = '/'; - cchHome++; - } - memcpy(&szName[cchHome], DYNLIB_NAME, sizeof(DYNLIB_NAME)); - - /* - * Try load it by that name, setting the VBOX_APP_HOME first (for now). - * Then resolve and call the function table getter. - */ - if (fSetAppHome) - { - if (pszHome) - setenv("VBOX_APP_HOME", pszHome, 1 /* always override */); - else - unsetenv("VBOX_APP_HOME"); - } - g_hVBoxXPCOMC = dlopen(szName, RTLD_NOW | RTLD_LOCAL); - if (g_hVBoxXPCOMC) - { - PFNVBOXGETXPCOMCFUNCTIONS pfnGetFunctions; - pfnGetFunctions = (PFNVBOXGETXPCOMCFUNCTIONS)(uintptr_t) - dlsym(g_hVBoxXPCOMC, VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME); - if (pfnGetFunctions) - { - g_pVBoxFuncs = pfnGetFunctions(VBOX_XPCOMC_VERSION); - if (g_pVBoxFuncs) - { - g_pfnGetFunctions = pfnGetFunctions; - return 0; - } - - /* bail out */ - setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", - szName, VBOX_XPCOMC_VERSION); - } - else - setErrMsg(1, "dlsym(%.80s/%.32s): %.128s", - szName, VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME, dlerror()); - dlclose(g_hVBoxXPCOMC); - g_hVBoxXPCOMC = NULL; - } - else - setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror()); - return rc; -} - - -/** - * Tries to locate and load VBoxXPCOMC.so/dylib/dll, resolving all the related - * function pointers. - * - * @returns 0 on success, -1 on failure. - * - * @remark This should be considered moved into a separate glue library since - * its its going to be pretty much the same for any user of VBoxXPCOMC - * and it will just cause trouble to have duplicate versions of this - * source code all around the place. - */ -int VBoxCGlueInit(void) -{ - /* - * If the user specifies the location, try only that. - */ - const char *pszHome = getenv("VBOX_APP_HOME"); - if (pszHome) - return tryLoadOne(pszHome, 0); - - /* - * Try the known standard locations. - */ - g_szVBoxErrMsg[0] = '\0'; -#if defined(__gnu__linux__) || defined(__linux__) - if (tryLoadOne("/opt/VirtualBox", 1) == 0) - return 0; - if (tryLoadOne("/usr/lib/virtualbox", 1) == 0) - return 0; -#elif defined(__sun__) - if (tryLoadOne("/opt/VirtualBox/amd64", 1) == 0) - return 0; - if (tryLoadOne("/opt/VirtualBox/i386", 1) == 0) - return 0; -#elif defined(__APPLE__) - if (tryLoadOne("/Application/VirtualBox.app/Contents/MacOS", 1) == 0) - return 0; -#elif defined(__FreeBSD__) - if (tryLoadOne("/usr/local/lib/virtualbox", 1) == 0) - return 0; -#elif defined(__OS2__) - if (tryLoadOne("C:/Apps/VirtualBox", 1) == 0) - return 0; -#else -# error "port me" -#endif - - /* - * Finally try the dynamic linker search path. - */ - if (tryLoadOne(NULL, 1) == 0) - return 0; - - /* No luck, return failure. */ - return -1; -} - - -/** - * Terminate the C glue library. - */ -void VBoxCGlueTerm(void) -{ - if (g_hVBoxXPCOMC) - { -#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */ - dlclose(g_hVBoxXPCOMC); -#endif - g_hVBoxXPCOMC = NULL; - } - g_pVBoxFuncs = NULL; - g_pfnGetFunctions = NULL; - memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); -} - diff --git a/src/VBox/Main/cbinding/VBoxXPCOMCGlue.h.in b/src/VBox/Main/cbinding/VBoxXPCOMCGlue.h.in deleted file mode 100644 index 7a1e9cc1..00000000 --- a/src/VBox/Main/cbinding/VBoxXPCOMCGlue.h.in +++ /dev/null @@ -1,59 +0,0 @@ -/* $Revision: 75934 $ */ -/** @file VBoxXPCOMCGlue.h - * Glue for dynamically linking with VBoxXPCOMC. - */ - -/* - * Copyright (C) 2008-2012 Oracle Corporation - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef ___VBoxXPCOMC_cglue_h -#define ___VBoxXPCOMC_cglue_h - -#include "VBoxCAPI_v@VBOX_API_VERSION@.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** The dlopen handle for VBoxXPCOMC. */ -extern void *g_hVBoxXPCOMC; -/** The last load error. */ -extern char g_szVBoxErrMsg[256]; -/** Pointer to the VBoxXPCOMC function table. */ -extern PCVBOXXPCOM g_pVBoxFuncs; -/** Pointer to VBoxGetXPCOMCFunctions for the loaded VBoxXPCOMC so/dylib/dll. */ -extern PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions; - - -int VBoxCGlueInit(void); -void VBoxCGlueTerm(void); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/VBox/Main/cbinding/capiidl.xsl b/src/VBox/Main/cbinding/capiidl.xsl new file mode 100644 index 00000000..7c236374 --- /dev/null +++ b/src/VBox/Main/cbinding/capiidl.xsl @@ -0,0 +1,2670 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /* + * DO NOT EDIT! This is a generated file. + * + * Header file which provides C declarations for VirtualBox Main API + * (COM interfaces), generated from XIDL (XML interface definition). + * On Windows (which uses COM instead of XPCOM) the native C support + * is used, and most of this file is not used. + * + * Source : src/VBox/Main/idl/VirtualBox.xidl + * Generator : src/VBox/Main/cbinding/capiidl.xsl + * + * This file contains portions from the following Mozilla XPCOM files: + * xpcom/include/xpcom/nsID.h + * xpcom/include/nsIException.h + * xpcom/include/nsprpub/prtypes.h + * xpcom/include/xpcom/nsISupportsBase.h + * + * These files were originally triple-licensed (MPL/GPL2/LGPL2.1). Oracle + * elects to distribute this derived work under the LGPL2.1 only. + */ + +/* + * Copyright (C) 2008-2014 Oracle Corporation + * + * This file is part of a free software library; you can redistribute + * it and/or modify it under the terms of the GNU Lesser General + * Public License version 2.1 as published by the Free Software + * Foundation and shipped in the "COPYING" file with this library. + * The library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY of any kind. + * + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if + * any license choice other than GPL or LGPL is available it will + * apply instead, Oracle elects to use only the Lesser General Public + * License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the + * language indicating that LGPLv2 or any later version may be used, + * or where a choice of which version of the LGPL is applied is + * otherwise unspecified. + */ + +#ifndef ___VirtualBox_CAPI_h +#define ___VirtualBox_CAPI_h + +#ifdef _WIN32 +# undef COBJMACROS +# define COBJMACROS +# include "Windows.h" +#endif /* _WIN32 */ + +#ifdef WIN32 +# ifdef IN_VBOXCAPI +# define VBOXCAPI_DECL(type) extern __declspec(dllexport) type +# else /* !IN_VBOXCAPI */ +# define VBOXCAPI_DECL(type) __declspec(dllimport) type +# endif /* !IN_VBOXCAPI */ +#endif /* WIN32 */ + +#ifdef __cplusplus +/* The C++ treatment in this file is not meant for SDK users, it only exists + * so that this file can be used to produce the VBoxCAPI shared library which + * has to use C++ as it does all the conversion magic. */ +# ifdef IN_VBOXCAPI +# include "VBox/com/VirtualBox.h" +# ifndef WIN32 +# include "nsIEventQueue.h" +# endif /* !WIN32 */ +# else /* !IN_VBOXCAPI */ +# error Do not include this header file from C++ code +# endif /* !IN_VBOXCAPI */ +#endif /* __cplusplus */ + +#ifdef __GNUC__ +# define VBOX_EXTERN_CONST(type, name) extern const type name __attribute__((nocommon)) +#else /* !__GNUC__ */ +# define VBOX_EXTERN_CONST(type, name) extern const type name +#endif /* !__GNUC__ */ + +/* Treat WIN32 completely separately, as on Windows VirtualBox uses COM, not + * XPCOM like on all other platforms. While the code below would also compile + * on Windows, we need to switch to the native C support provided by the header + * files produced by the COM IDL compiler. */ +#ifdef WIN32 +# include "ObjBase.h" +# include "oaidl.h" +# include "VirtualBox.h" + +#ifndef __cplusplus +/* Skip this in the C++ case as there's already a definition for CBSTR. */ +typedef const BSTR CBSTR; +#endif /* !__cplusplus */ + +#define VBOX_WINAPI WINAPI + +#define ComSafeArrayAsInParam(f) (f) +#define ComSafeArrayAsOutParam(f) (&(f)) +#define ComSafeArrayAsOutIfaceParam(f,t) (&(f)) + +#else /* !WIN32 */ + +#include <stddef.h> +#include "wchar.h" + +#ifdef IN_VBOXCAPI +# define VBOXCAPI_DECL(type) PR_EXPORT(type) +#else /* !IN_VBOXCAPI */ +# define VBOXCAPI_DECL(type) PR_IMPORT(type) +#endif /* !IN_VBOXCAPI */ + +#ifndef __cplusplus + +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define PR_EXPORT(__type) __attribute__((visibility("default"))) extern __type +# define PR_EXPORT_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT(__type) __attribute__((visibility("default"))) __type +# define PR_EXTERN_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT_DATA(__type) __attribute__((visibility("default"))) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# else +# define PR_EXPORT(__type) extern __type +# define PR_EXPORT_DATA(__type) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) extern __type +# define PR_IMPLEMENT(__type) __type +# define PR_EXTERN_DATA(__type) extern __type +# define PR_IMPLEMENT_DATA(__type) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# endif +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +typedef unsigned char PRUint8; +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +#define PR_TRUE 1 +#define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +typedef PRUnichar *BSTR; +typedef const PRUnichar *CBSTR; +#endif + +typedef long PRWord; +typedef unsigned long PRUword; + +#define nsnull 0 +typedef PRUint32 nsresult; + +#if defined(__GNUC__) && (__GNUC__ > 2) +#define NS_LIKELY(x) (__builtin_expect((x), 1)) +#define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define NS_LIKELY(x) (x) +#define NS_UNLIKELY(x) (x) +#endif + +#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_IntervalNow VBoxNsprPR_IntervalNow +# define PR_TicksPerSecond VBoxNsprPR_TicksPerSecond +# define PR_SecondsToInterval VBoxNsprPR_SecondsToInterval +# define PR_MillisecondsToInterval VBoxNsprPR_MillisecondsToInterval +# define PR_MicrosecondsToInterval VBoxNsprPR_MicrosecondsToInterval +# define PR_IntervalToSeconds VBoxNsprPR_IntervalToSeconds +# define PR_IntervalToMilliseconds VBoxNsprPR_IntervalToMilliseconds +# define PR_IntervalToMicroseconds VBoxNsprPR_IntervalToMicroseconds +# define PR_EnterMonitor VBoxNsprPR_EnterMonitor +# define PR_ExitMonitor VBoxNsprPR_ExitMonitor +# define PR_Notify VBoxNsprPR_Notify +# define PR_NotifyAll VBoxNsprPR_NotifyAll +# define PR_Wait VBoxNsprPR_Wait +# define PR_NewMonitor VBoxNsprPR_NewMonitor +# define PR_DestroyMonitor VBoxNsprPR_DestroyMonitor +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef PRUint32 PRIntervalTime; + +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +NSPR_API(PRIntervalTime) PR_IntervalNow(void); +NSPR_API(PRUint32) PR_TicksPerSecond(void); +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +typedef struct PRMonitor PRMonitor; + +NSPR_API(PRMonitor*) PR_NewMonitor(void); +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_CreateThread VBoxNsprPR_CreateThread +# define PR_JoinThread VBoxNsprPR_JoinThread +# define PR_Sleep VBoxNsprPR_Sleep +# define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread +# define PR_GetThreadState VBoxNsprPR_GetThreadState +# define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate +# define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate +# define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex +# define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority +# define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority +# define PR_Interrupt VBoxNsprPR_Interrupt +# define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt +# define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt +# define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt +# define PR_GetThreadScope VBoxNsprPR_GetThreadScope +# define PR_GetThreadType VBoxNsprPR_GetThreadType +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); +NSPR_API(void) PR_ClearInterrupt(void); +NSPR_API(void) PR_BlockInterrupt(void); +NSPR_API(void) PR_UnblockInterrupt(void); +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_DestroyLock VBoxNsprPR_DestroyLock +# define PR_Lock VBoxNsprPR_Lock +# define PR_NewLock VBoxNsprPR_NewLock +# define PR_Unlock VBoxNsprPR_Unlock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRLock PRLock; + +NSPR_API(PRLock*) PR_NewLock(void); +NSPR_API(void) PR_DestroyLock(PRLock *lock); +NSPR_API(void) PR_Lock(PRLock *lock); +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_NewCondVar VBoxNsprPR_NewCondVar +# define PR_DestroyCondVar VBoxNsprPR_DestroyCondVar +# define PR_WaitCondVar VBoxNsprPR_WaitCondVar +# define PR_NotifyCondVar VBoxNsprPR_NotifyCondVar +# define PR_NotifyAllCondVar VBoxNsprPR_NotifyAllCondVar +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRCondVar PRCondVar; + +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +typedef struct PRCListStr PRCList; + +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PL_DestroyEvent VBoxNsplPL_DestroyEvent +# define PL_HandleEvent VBoxNsplPL_HandleEvent +# define PL_InitEvent VBoxNsplPL_InitEvent +# define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue +# define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue +# define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue +# define PL_DequeueEvent VBoxNsplPL_DequeueEvent +# define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue +# define PL_EventAvailable VBoxNsplPL_EventAvailable +# define PL_EventLoop VBoxNsplPL_EventLoop +# define PL_GetEvent VBoxNsplPL_GetEvent +# define PL_GetEventOwner VBoxNsplPL_GetEventOwner +# define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor +# define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD +# define PL_MapEvents VBoxNsplPL_MapEvents +# define PL_PostEvent VBoxNsplPL_PostEvent +# define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent +# define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID +# define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents +# define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc +# define PL_RevokeEvents VBoxNsplPL_RevokeEvents +# define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc +# define PL_WaitForEvent VBoxNsplPL_WaitForEvent +# define PL_IsQueueNative VBoxNsplPL_IsQueueNative +# define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread +# define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PLEvent PLEvent; +typedef struct PLEventQueue PLEventQueue; + +PR_EXTERN(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread); +PR_EXTERN(PLEventQueue *) + PL_CreateNativeEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(PLEventQueue *) + PL_CreateMonitoredEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(void) +PL_DestroyEventQueue(PLEventQueue* self); +PR_EXTERN(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self); + +#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ + PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) + +#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ + PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) + +PR_EXTERN(PRStatus) PL_PostEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(void*) PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(PLEvent*) PL_GetEvent(PLEventQueue* self); +PR_EXTERN(PRBool) PL_EventAvailable(PLEventQueue* self); + +typedef void (PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); + +PR_EXTERN(void) PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); +PR_EXTERN(void) PL_RevokeEvents(PLEventQueue* self, void* owner); +PR_EXTERN(void) PL_ProcessPendingEvents(PLEventQueue* self); +PR_EXTERN(PLEvent*) PL_WaitForEvent(PLEventQueue* self); +PR_EXTERN(void) PL_EventLoop(PLEventQueue* self); +PR_EXTERN(PRInt32) PL_GetEventQueueSelectFD(PLEventQueue* self); +PR_EXTERN(PRBool) PL_IsQueueOnCurrentThread( PLEventQueue *queue ); +PR_EXTERN(PRBool) PL_IsQueueNative(PLEventQueue *queue); + +typedef void* (PR_CALLBACK *PLHandleEventProc)(PLEvent* self); +typedef void (PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); +PR_EXTERN(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor); +PR_EXTERN(void*) PL_GetEventOwner(PLEvent* self); +PR_EXTERN(void) PL_HandleEvent(PLEvent* self); +PR_EXTERN(void) PL_DestroyEvent(PLEvent* self); +PR_EXTERN(void) PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); +PR_EXTERN(void) PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); + +struct PLEvent { + PRCList link; + PLHandleEventProc handler; + PLDestroyEventProc destructor; + void* owner; + void* synchronousResult; + PRLock* lock; + PRCondVar* condVar; + PRBool handled; +#ifdef PL_POST_TIMINGS + PRIntervalTime postTime; +#endif +#ifdef XP_UNIX + unsigned long id; +#endif /* XP_UNIX */ + /* other fields follow... */ +}; + +#if defined(XP_WIN) || defined(XP_OS2) + +PR_EXTERN(HWND) + PL_GetNativeEventReceiverWindow( + PLEventQueue *eqp + ); +#endif /* XP_WIN || XP_OS2 */ + +#ifdef XP_UNIX + +PR_EXTERN(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); + +typedef unsigned long (PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); + +PR_EXTERN(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure); +PR_EXTERN(void) PL_UnregisterEventIDFunc(PLEventQueue *aSelf); + +#endif /* XP_UNIX */ + +/* Standard "it worked" return value */ +#define NS_OK 0 + +#define NS_ERROR_BASE ((nsresult) 0xC1F30000) + +/* Returned when an instance is not initialized */ +#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + +/* Returned when an instance is already initialized */ +#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) + +/* Returned by a not implemented function */ +#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) + +/* Returned when a given interface is not supported. */ +#define NS_NOINTERFACE ((nsresult) 0x80004002L) +#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + +#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) +#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER + +/* Returned when a function aborts */ +#define NS_ERROR_ABORT ((nsresult) 0x80004004L) + +/* Returned when a function fails */ +#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) + +/* Returned when an unexpected error occurs */ +#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) + +/* Returned when a memory allocation fails */ +#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) + +/* Returned when an illegal value is passed */ +#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) +#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE + +/* Returned when a class doesn't allow aggregation */ +#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) + +/* Returned when an operation can't complete due to an unavailable resource */ +#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) + +/* Returned when a class is not registered */ +#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) + +/* Returned when a class cannot be registered, but may be tried again later */ +#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) + +/* Returned when a dynamically loaded factory couldn't be found */ +#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) + +/* Returned when a factory doesn't support signatures */ +#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ + (NS_ERROR_BASE + 0x101) + +/* Returned when a factory already is registered */ +#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; +typedef nsID nsCID; + +#endif /* __cplusplus */ + +#define VBOX_WINAPI + +/* Various COM types defined by their XPCOM equivalent */ +typedef PRInt64 LONG64; +typedef PRInt32 LONG; +typedef PRInt32 DWORD; +typedef PRInt16 SHORT; +typedef PRUint64 ULONG64; +typedef PRUint32 ULONG; +typedef PRUint16 USHORT; + +typedef PRBool BOOL; + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define HRESULT nsresult +#define SUCCEEDED NS_SUCCEEDED +#define FAILED NS_FAILED + +/* OLE error codes */ +#define S_OK ((nsresult)NS_OK) +#define E_UNEXPECTED NS_ERROR_UNEXPECTED +#define E_NOTIMPL NS_ERROR_NOT_IMPLEMENTED +#define E_OUTOFMEMORY NS_ERROR_OUT_OF_MEMORY +#define E_INVALIDARG NS_ERROR_INVALID_ARG +#define E_NOINTERFACE NS_ERROR_NO_INTERFACE +#define E_POINTER NS_ERROR_NULL_POINTER +#define E_ABORT NS_ERROR_ABORT +#define E_FAIL NS_ERROR_FAILURE +/* Note: a better analog for E_ACCESSDENIED would probably be + * NS_ERROR_NOT_AVAILABLE, but we want binary compatibility for now. */ +#define E_ACCESSDENIED ((nsresult)0x80070005L) + +/* Basic vartype for COM compatibility. */ +typedef enum VARTYPE +{ + VT_I2 = 2, + VT_I4 = 3, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_BOOL = 11, + VT_UNKNOWN = 13, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_HRESULT = 25 +} VARTYPE; + +/* Basic safearray type for COM compatibility. */ +typedef struct SAFEARRAY +{ + void *pv; + ULONG c; +} SAFEARRAY; + +#define ComSafeArrayAsInParam(f) ((f)->c), ((f)->pv) +#define ComSafeArrayAsOutParam(f) (&((f)->c)), (&((f)->pv)) +#define ComSafeArrayAsOutIfaceParam(f,t) (&((f)->c)), (t**)(&((f)->pv)) + +/* Glossing over differences between COM and XPCOM */ +#define IErrorInfo nsIException +#define IUnknown nsISupports +#define IDispatch nsISupports + +/* Make things as COM compatible as possible */ +#define interface struct +#ifdef CONST_VTABLE +# define CONST_VTBL const +#else /* !CONST_VTABLE */ +# define CONST_VTBL +#endif /* !CONST_VTABLE */ + +#ifndef __cplusplus + +/** @todo this first batch of forward declarations (and the corresponding ones + * generated for each interface) are 100% redundant, remove eventually. */ +interface nsISupports; /* forward declaration */ +interface nsIException; /* forward declaration */ +interface nsIStackFrame; /* forward declaration */ +interface nsIEventTarget;/* forward declaration */ +interface nsIEventQueue; /* forward declaration */ + +typedef interface nsISupports nsISupports; /* forward declaration */ +typedef interface nsIException nsIException; /* forward declaration */ +typedef interface nsIStackFrame nsIStackFrame; /* forward declaration */ +typedef interface nsIEventTarget nsIEventTarget;/* forward declaration */ +typedef interface nsIEventQueue nsIEventQueue; /* forward declaration */ + +/* starting interface: nsISupports */ +#define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" + +#define NS_ISUPPORTS_IID \ + { 0x00000000, 0x0000, 0x0000, \ + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } + +/** + * Reference count values + * + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * The following ifdef exists to maintain binary compatibility with + * IUnknown. + */ +#if defined(XP_WIN) && PR_BYTES_PER_LONG == 4 +typedef unsigned long nsrefcnt; +#else +typedef PRUint32 nsrefcnt; +#endif + +/** + * Basic component object model interface. Objects which implement + * this interface support runtime interface discovery (QueryInterface) + * and a reference counted memory model (AddRef/Release). This is + * modelled after the win32 IUnknown API. + */ +#ifndef VBOX_WITH_GLUE +struct nsISupports_vtbl +{ + nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsISupports *pThis); + nsrefcnt (*Release)(nsISupports *pThis); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsISupportsVtbl +{ + nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsISupports *pThis); + nsrefcnt (*Release)(nsISupports *pThis); +}; +#define nsISupports_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsISupports_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsISupports_Release(p) ((p)->lpVtbl->Release(p)) +#define IUnknown_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IUnknown_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IUnknown_Release(p) ((p)->lpVtbl->Release(p)) +#define IDispatch_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IDispatch_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IDispatch_Release(p) ((p)->lpVtbl->Release(p)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsISupports +{ +#ifndef VBOX_WITH_GLUE + struct nsISupports_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsISupportsVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIException */ +#define NS_IEXCEPTION_IID_STR "f3a8d3b4-c424-4edc-8bf6-8974c983ba78" + +#define NS_IEXCEPTION_IID \ + {0xf3a8d3b4, 0xc424, 0x4edc, \ + { 0x8b, 0xf6, 0x89, 0x74, 0xc9, 0x83, 0xba, 0x78 }} + +#ifndef VBOX_WITH_GLUE +struct nsIException_vtbl +{ + /* Methods from the interface nsISupports */ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); + nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); + nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); + nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); + nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); + nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); + nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); + nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); + nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); + nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIExceptionVtbl +{ + nsresult (*QueryInterface)(nsIException *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIException *pThis); + nsrefcnt (*Release)(nsIException *pThis); + + nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); + nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); + nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); + nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); + nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); + nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); + nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); + nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); + nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); + nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); +}; +#define nsIException_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIException_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIException_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIException_get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define nsIException_GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define nsIException_get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define nsIException_GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define nsIException_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIException_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIException_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIException_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIException_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIException_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIException_get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define nsIException_GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define nsIException_get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define nsIException_GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define nsIException_get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define nsIException_GetData(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define nsIException_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#define IErrorInfo_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IErrorInfo_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IErrorInfo_Release(p) ((p)->lpVtbl->Release(p)) +#define IErrorInfo_get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define IErrorInfo_GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define IErrorInfo_get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define IErrorInfo_GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define IErrorInfo_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define IErrorInfo_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define IErrorInfo_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define IErrorInfo_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define IErrorInfo_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define IErrorInfo_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define IErrorInfo_get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define IErrorInfo_GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define IErrorInfo_get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define IErrorInfo_GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define IErrorInfo_get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define IErrorInfo_GetData(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define IErrorInfo_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIException +{ +#ifndef VBOX_WITH_GLUE + struct nsIException_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIExceptionVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIStackFrame */ +#define NS_ISTACKFRAME_IID_STR "91d82105-7c62-4f8b-9779-154277c0ee90" + +#define NS_ISTACKFRAME_IID \ + {0x91d82105, 0x7c62, 0x4f8b, \ + { 0x97, 0x79, 0x15, 0x42, 0x77, 0xc0, 0xee, 0x90 }} + +#ifndef VBOX_WITH_GLUE +struct nsIStackFrame_vtbl +{ + /* Methods from the interface nsISupports */ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); + nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); + nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); + nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); + nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); + nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); + nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); + nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIStackFrameVtbl +{ + nsresult (*QueryInterface)(nsIStackFrame *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIStackFrame *pThis); + nsrefcnt (*Release)(nsIStackFrame *pThis); + + nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); + nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); + nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); + nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); + nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); + nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); + nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); + nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); +}; +#define nsIStackFrame_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIStackFrame_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIStackFrame_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIStackFrame_get_Language(p, aLanguage) ((p)->lpVtbl->GetLanguge(p, aLanguage)) +#define nsIStackFrame_GetLanguage(p, aLanguage) ((p)->lpVtbl->GetLanguge(p, aLanguage)) +#define nsIStackFrame_get_LanguageName(p, aLanguageName) ((p)->lpVtbl->GetLanguageName(p, aLanguageName)) +#define nsIStackFrame_GetLanguageName(p, aLanguageName) ((p)->lpVtbl->GetLanguageName(p, aLanguageName)) +#define nsIStackFrame_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIStackFrame_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIStackFrame_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIStackFrame_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIStackFrame_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIStackFrame_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIStackFrame_get_SourceLine(p, aSourceLine) ((p)->lpVtbl->GetSourceLine(p, aSourceLine)) +#define nsIStackFrame_GetSourceLine(p, aSourceLine) ((p)->lpVtbl->GetSourceLine(p, aSourceLine)) +#define nsIStackFrame_get_Caller(p, aCaller) ((p)->lpVtbl->GetCaller(p, aCaller)) +#define nsIStackFrame_GetCaller(p, aCaller) ((p)->lpVtbl->GetCaller(p, aCaller)) +#define nsIStackFrame_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIStackFrame +{ +#ifndef VBOX_WITH_GLUE + struct nsIStackFrame_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIStackFrameVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIEventTarget */ +#define NS_IEVENTTARGET_IID_STR "ea99ad5b-cc67-4efb-97c9-2ef620a59f2a" + +#define NS_IEVENTTARGET_IID \ + {0xea99ad5b, 0xcc67, 0x4efb, \ + { 0x97, 0xc9, 0x2e, 0xf6, 0x20, 0xa5, 0x9f, 0x2a }} + +#ifndef VBOX_WITH_GLUE +struct nsIEventTarget_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIEventTargetVtbl +{ + nsresult (*QueryInterface)(nsIEventTarget *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIEventTarget *pThis); + nsrefcnt (*Release)(nsIEventTarget *pThis); + + nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); +}; +#define nsIEventTarget_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIEventTarget_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIEventTarget_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIEventTarget_PostEvent(p, aEvent) ((p)->lpVtbl->PostEvent(p, aEvent)) +#define nsIEventTarget_IsOnCurrentThread(p, retval) ((p)->lpVtbl->IsOnCurrentThread(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIEventTarget +{ +#ifndef VBOX_WITH_GLUE + struct nsIEventTarget_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIEventTargetVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIEventQueue */ +#define NS_IEVENTQUEUE_IID_STR "176afb41-00a4-11d3-9f2a-00400553eef0" + +#define NS_IEVENTQUEUE_IID \ + {0x176afb41, 0x00a4, 0x11d3, \ + { 0x9f, 0x2a, 0x00, 0x40, 0x05, 0x53, 0xee, 0xf0 }} + +#ifndef VBOX_WITH_GLUE +struct nsIEventQueue_vtbl +{ + struct nsIEventTarget_vtbl nsieventtarget; + + nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); + nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); + nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); + nsresult (*EventLoop)(nsIEventQueue *pThis); + nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); + nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); + nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); + nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); + nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); + nsresult (*EnterMonitor)(nsIEventQueue *pThis); + nsresult (*ExitMonitor)(nsIEventQueue *pThis); + nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); + nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); + nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIEventQueueVtbl +{ + nsresult (*QueryInterface)(nsIEventQueue *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIEventQueue *pThis); + nsrefcnt (*Release)(nsIEventQueue *pThis); + + nsresult (*PostEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventQueue *pThis, PRBool *_retval); + + nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); + nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); + nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); + nsresult (*EventLoop)(nsIEventQueue *pThis); + nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); + nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); + nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); + nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); + nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); + nsresult (*EnterMonitor)(nsIEventQueue *pThis); + nsresult (*ExitMonitor)(nsIEventQueue *pThis); + nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); + nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); + nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); +}; +#define nsIEventQueue_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIEventQueue_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIEventQueue_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIEventQueue_PostEvent(p, aEvent) ((p)->lpVtbl->PostEvent(p, aEvent)) +#define nsIEventQueue_IsOnCurrentThread(p, retval) ((p)->lpVtbl->IsOnCurrentThread(p, retval)) +#define nsIEventQueue_InitEvent(p, aEvent, owner, handler, destructor) ((p)->lpVtbl->InitEvent(p, aEvent, owner, handler, destructor)) +#define nsIEventQueue_PostSynchronousEvent(p, aEvent, aResult) ((p)->lpVtbl->PostSynchronousEvent(p, aEvent, aResult)) +#define nsIEventQueue_ProcessPendingEvents(p) ((p)->lpVtbl->ProcessPendingEvents(p)) +#define nsIEventQueue_EventLoop(p) ((p)->lpVtbl->EventLoop(p)) +#define nsIEventQueue_EventAvailable(p, aResult) ((p)->lpVtbl->EventAvailable(p, aResult)) +#define nsIEventQueue_get_Event(p, aEvent) ((p)->lpVtbl->GetEvent(p, aEvent)) +#define nsIEventQueue_GetEvent(p, aEvent) ((p)->lpVtbl->GetEvent(p, aEvent)) +#define nsIEventQueue_HandleEvent(p, aEvent) ((p)->lpVtbl->HandleEvent(p, aEvent)) +#define nsIEventQueue_WaitForEvent(p, aEvent) ((p)->lpVtbl->WaitForEvent(p, aEvent)) +#define nsIEventQueue_GetEventQueueSelectFD(p) ((p)->lpVtbl->GetEventQueueSelectFD(p)) +#define nsIEventQueue_Init(p, aNative) ((p)->lpVtbl->Init(p, aNative)) +#define nsIEventQueue_InitFromPLQueue(p, aQueue) ((p)->lpVtbl->InitFromPLQueue(p, aQueue)) +#define nsIEventQueue_EnterMonitor(p) ((p)->lpVtbl->EnterMonitor(p)) +#define nsIEventQueue_ExitMonitor(p) ((p)->lpVtbl->ExitMonitor(p)) +#define nsIEventQueue_RevokeEvents(p, owner) ((p)->lpVtbl->RevokeEvents(p, owner)) +#define nsIEventQueue_GetPLEventQueue(p, retval) ((p)->lpVtbl->GetPLEventQueue(p, retval)) +#define nsIEventQueue_IsQueueNative(p, retval) ((p)->lpVtbl->IsQueueNative(p, retval)) +#define nsIEventQueue_StopAcceptingEvents(p) ((p)->lpVtbl->StopAcceptingEvents(p)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIEventQueue +{ +#ifndef VBOX_WITH_GLUE + struct nsIEventQueue_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIEventQueueVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + + + + + +#endif /* __cplusplus */ + +#endif /* !WIN32 */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** + * Function table for dynamic linking. + * Use VBoxGetCAPIFunctions() to obtain the pointer to it. + */ +typedef struct VBOXCAPI +{ + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + /** Gets the VirtualBox version, major * 1000000 + minor * 1000 + patch. */ + unsigned int (*pfnGetVersion)(void); + + /** Gets the VirtualBox API version, major * 1000 + minor, e.g. 4003. */ + unsigned int (*pfnGetAPIVersion)(void); + + /** + * New and preferred way to initialize the C bindings for an API client. + * + * This way is much more flexible, as it can easily handle multiple + * sessions (important with more complicated API clients, including + * multithreaded ones), and even VBoxSVC crashes can be detected and + * processed appropriately by listening for events from the associated + * event source in VirtualBoxClient. It is completely up to the client + * to decide what to do (terminate or continue after getting new + * object references to server-side objects). Must be called in the + * primary thread of the client, later API use can be done in any + * thread. + * + * Note that the returned reference is owned by the caller, and thus it's + * the caller's responsibility to handle the reference count appropriately. + * + * @param pszVirtualBoxClientIID pass IVIRTUALBOXCLIENT_IID_STR + * @param ppVirtualBoxClient output parameter for VirtualBoxClient + * reference, handled as usual with COM/XPCOM. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientInitialize)(const char *pszVirtualBoxClientIID, + IVirtualBoxClient **ppVirtualBoxClient); + /** + * Initialize the use of the C bindings in a non-primary thread. + * + * Must be called on any newly created thread which wants to use the + * VirtualBox API. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientThreadInitialize)(void); + /** + * Uninitialize the use of the C bindings in a non-primary thread. + * + * Should be called before terminating the thread which initialized the + * C bindings using pfnClientThreadInitialize. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientThreadUninitialize)(void); + /** + * Uninitialize the C bindings for an API client. + * + * Should be called when the API client is about to terminate and does + * not want to use the C bindings any more. It will invalidate all + * object references. It is possible, however, to change one's mind, + * and call pfnClientInitialize again to continue using the API, as long + * as none of the object references from before the re-initialization + * are used. Must be called from the primary thread of the client. + */ + void (*pfnClientUninitialize)(void); + + /** + * Deprecated way to initialize the C bindings and getting important + * object references. Kept for backwards compatibility. + * + * If any returned reference is NULL then the initialization failed. + * Note that the returned references are owned by the C bindings. The + * number of calls to Release in the client code must match the number + * of calls to AddRef, and additionally at no point in time there can + * be more Release calls than AddRef calls. + * + * @param pszVirtualBoxIID pass IVIRTUALBOX_IID_STR + * @param ppVirtualBox output parameter for VirtualBox reference, + * owned by C bindings + * @param pszSessionIID pass ISESSION_IID_STR + * @param ppSession output parameter for Session reference, + * owned by C bindings + */ + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + /** + * Deprecated way to uninitialize the C bindings for an API client. + * Kept for backwards compatibility and must be used if the C bindings + * were initialized using pfnComInitialize. */ + void (*pfnComUninitialize)(void); + + /** + * Free string managed by COM/XPCOM. + * + * @param pwsz pointer to string to be freed + */ + void (*pfnComUnallocString)(BSTR pwsz); +#ifndef WIN32 + /** Legacy function, was always for freeing strings only. */ +#define pfnComUnallocMem(pv) pfnComUnallocString((BSTR)(pv)) +#endif /* !WIN32 */ + + /** + * Convert string from UTF-16 encoding to UTF-8 encoding. + * + * @param pwszString input string + * @param ppszString output string + * @returns IPRT status code + */ + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + /** + * Convert string from UTF-8 encoding to UTF-16 encoding. + * + * @param pszString input string + * @param ppwszString output string + * @returns IPRT status code + */ + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + /** + * Free memory returned by pfnUtf16ToUtf8. Do not use for anything else. + * + * @param pszString string to be freed. + */ + void (*pfnUtf8Free)(char *pszString); + /** + * Free memory returned by pfnUtf8ToUtf16. Do not use for anything else. + * + * @param pwszString string to be freed. + */ + void (*pfnUtf16Free)(BSTR pwszString); + + /** + * Create a safearray (used for passing arrays to COM/XPCOM) + * + * Must be freed by pfnSafeArrayDestroy. + * + * @param vt variant type, defines the size of the elements + * @param lLbound lower bound of the index, should be 0 + * @param cElements number of elements + * @returns pointer to safearray + */ + SAFEARRAY *(*pfnSafeArrayCreateVector)(VARTYPE vt, LONG lLbound, ULONG cElements); + /** + * Pre-allocate a safearray to be used by an out safearray parameter + * + * Must be freed by pfnSafeArrayDestroy. + * + * @returns pointer to safearray (system dependent, may be NULL if + * there is no need to pre-allocate a safearray) + */ + SAFEARRAY *(*pfnSafeArrayOutParamAlloc)(void); + /** + * Copy a C array into a safearray (for passing as an input parameter) + * + * @param psa pointer to already created safearray. + * @param pv pointer to memory block to copy into safearray. + * @param cb number of bytes to copy. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyInParamHelper)(SAFEARRAY *psa, const void *pv, ULONG cb); + /** + * Copy a safearray into a C array (for getting an output parameter) + * + * @param ppv output pointer to newly created array, which has to + * be freed with free(). + * @param pcb number of bytes in the output buffer. + * @param vt variant type, defines the size of the elements + * @param psa pointer to safearray for getting the data + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyOutParamHelper)(void **ppv, ULONG *pcb, VARTYPE vt, SAFEARRAY *psa); + /** + * Copy a safearray into a C array (special variant for interface pointers) + * + * @param ppaObj output pointer to newly created array, which has + * to be freed with free(). Note that it's the caller's + * responsibility to call Release() on each non-NULL interface + * pointer before freeing. + * @param pcObj number of pointers in the output buffer. + * @param psa pointer to safearray for getting the data + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyOutIfaceParamHelper)(IUnknown ***ppaObj, ULONG *pcObj, SAFEARRAY *psa); + /** + * Free a safearray + * + * @param psa pointer to safearray for getting the data + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayDestroy)(SAFEARRAY *psa); + +#ifndef WIN32 + /** + * Get XPCOM event queue. Deprecated! + * + * @param ppEventQueue output parameter for nsIEventQueue reference, + * owned by C bindings. + */ + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* !WIN32 */ + + /** + * Get current COM/XPCOM exception. + * + * @param ppException output parameter for exception info reference, + * may be @c NULL if no exception object has been created by + * a previous COM/XPCOM call. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnGetException)(IErrorInfo **ppException); + /** + * Clears current COM/XPCOM exception. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClearException)(void); + + /** + * Process the event queue for a given amount of time. + * + * Must be called on the primary thread. Typical timeouts are from 200 to + * 5000 msecs, to allow for checking a volatile variable if the event queue + * processing should be terminated (, + * or 0 if only the pending events should be processed, without waiting. + * + * @param iTimeoutMS how long to process the event queue, -1 means + * infinitely long + * @returns status code + * @retval 0 if at least one event has been processed + * @retval 1 if any signal interrupted the native system call (or returned + * otherwise) + * @retval 2 if the event queue was explicitly interrupted + * @retval 3 if the timeout expired + * @retval 4 if the function was called from the wrong thread + * @retval 5 for all other (unexpected) errors + */ + int (*pfnProcessEventQueue)(LONG64 iTimeoutMS); + /** + * Interrupt event queue processing. + * + * Can be called on any thread. Note that this function is not async-signal + * safe, so never use it in such a context, instead use a volatile global + * variable and a sensible timeout. + * @returns 0 if successful, 1 otherwise. + */ + int (*pfnInterruptEventQueueProcessing)(void); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; +} VBOXCAPI; +/** Pointer to a const VBOXCAPI function table. */ +typedef VBOXCAPI const *PCVBOXCAPI; +#ifndef WIN32 +/** Backwards compatibility: Pointer to a const VBOXCAPI function table. + * Use PCVBOXCAPI instead. */ +typedef VBOXCAPI const *PCVBOXXPCOM; +#endif /* !WIN32 */ + +#ifndef WIN32 +/** Backwards compatibility: make sure old code using VBOXXPCOMC still compiles. + * Use VBOXCAPI instead. */ +#define VBOXXPCOMC VBOXCAPI +#endif /* !WIN32 */ + +/** The current interface version. + * For use with VBoxGetCAPIFunctions and to be found in VBOXCAPI::uVersion. */ +#define VBOX_CAPI_VERSION 0x00040000U + +#ifndef WIN32 +/** Backwards compatibility: The current interface version. + * Use VBOX_CAPI_VERSION instead. */ +#define VBOX_XPCOMC_VERSION VBOX_CAPI_VERSION +#endif /* !WIN32 */ + +/** VBoxGetCAPIFunctions. */ +VBOXCAPI_DECL(PCVBOXCAPI) VBoxGetCAPIFunctions(unsigned uVersion); +#ifndef WIN32 +/** Backwards compatibility: VBoxGetXPCOMCFunctions. + * Use VBoxGetCAPIFunctions instead. */ +VBOXCAPI_DECL(PCVBOXCAPI) VBoxGetXPCOMCFunctions(unsigned uVersion); +#endif /* !WIN32 */ + +/** Typedef for VBoxGetCAPIFunctions. */ +typedef PCVBOXCAPI (*PFNVBOXGETCAPIFUNCTIONS)(unsigned uVersion); +#ifndef WIN32 +/** Backwards compatibility: Typedef for VBoxGetXPCOMCFunctions. + * Use PFNVBOXGETCAPIFUNCTIONS instead. */ +typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion); +#endif /* !WIN32 */ + +/** The symbol name of VBoxGetCAPIFunctions. */ +#ifdef __OS2__ +# define VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME "_VBoxGetCAPIFunctions" +#else /* !__OS2__ */ +# define VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME "VBoxGetCAPIFunctions" +#endif /* !__OS2__ */ +#ifndef WIN32 +/** Backwards compatibility: The symbol name of VBoxGetXPCOMCFunctions. + * Use VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME instead. */ +# ifdef __OS2__ +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "_VBoxGetXPCOMCFunctions" +# else /* !__OS2__ */ +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "VBoxGetXPCOMCFunctions" +# endif /* !__OS2__ */ +#endif /* !WIN32 */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !___VirtualBox_CAPI_h */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + interface + + ; + + + + + + + + typedef interface + + + + ; + + + + + + + + + + + + #define + + _QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) + #define + + _AddRef(p) ((p)->lpVtbl->AddRef(p)) + #define + + _Release(p) ((p)->lpVtbl->Release(p)) + + + #define + + _QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) + #define + + _AddRef(p) ((p)->lpVtbl->AddRef(p)) + #define + + _Release(p) ((p)->lpVtbl->Release(p)) + #define + + _get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) + #define + + _GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) + #define + + _get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) + #define + + _GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) + #define + + _get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) + #define + + _GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) + #define + + _get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) + #define + + _GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) + #define + + _get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) + #define + + _GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) + #define + + _get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) + #define + + _GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) + #define + + _get_Location(p, aLocation) ((p)->lpVtbl->GetLocation(p, aLocation)) + #define + + _GetLocation(p, aLocation) ((p)->lpVtbl->GetLocation(p, aLocation)) + #define + + _get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) + #define + + _GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) + #define + + _get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData)) + #define + + _GetData(p, aData) ((p)->lpVtbl->GetData(p, aData)) + #define + + _ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) + + + + + + + + + + + + + + + + + + + + + + + + + + nsresult (*QueryInterface)( + + *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)( + + *pThis); + nsrefcnt (*Release)( + + *pThis); + + + nsresult (*QueryInterface)( + + *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)( + + *pThis); + nsrefcnt (*Release)( + + *pThis); + nsresult (*GetMessage)( + + *pThis, PRUnichar * *aMessage); + nsresult (*GetResult)( + + *pThis, nsresult *aResult); + nsresult (*GetName)( + + *pThis, PRUnichar * *aName); + nsresult (*GetFilename)( + + *pThis, PRUnichar * *aFilename); + nsresult (*GetLineNumber)( + + *pThis, PRUint32 *aLineNumber); + nsresult (*GetColumnNumber)( + + *pThis, PRUint32 *aColumnNumber); + nsresult (*GetLocation)( + + *pThis, nsIStackFrame * *aLocation); + nsresult (*GetInner)( + + *pThis, nsIException * *aInner); + nsresult (*GetData)( + + *pThis, nsISupports * *aData); + nsresult (*ToString)( + + *pThis, PRUnichar **_retval); + + + + + + + + + + + + + + + + + + + + + + /* Start of struct + + declaration */ + #define + + + + + + #define + + + + _IID { \ + 0x + , 0x + , 0x + , \ + { 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + } \ } + /* COM compatibility */ + VBOX_EXTERN_CONST(nsIID, IID_ + + ); + #ifndef VBOX_WITH_GLUE + struct + + _vtbl { + + + struct nsISupports_vtbl nsisupports; + struct nsIException_vtbl nsiexception; + + struct + + _vtbl + + + + ; + + + + + + + + + }; + #else /* VBOX_WITH_GLUE */ + struct + + Vtbl { + + + + }; + + + + + #endif /* VBOX_WITH_GLUE */ + + interface + + { + #ifndef VBOX_WITH_GLUE + struct + + _vtbl *vtbl; + #else /* VBOX_WITH_GLUE */ + CONST_VTBL struct + + Vtbl *lpVtbl; + #endif /* VBOX_WITH_GLUE */ + }; + /* End of struct + + declaration */ + + + + + + + + + + + + + nsresult (*Get + + + + )( + + *pThis, + + PRUint32 * + + Size, + + + ** + + ); + + + nsresult (*Set + + + + )( + + *pThis, + + PRUint32 + + Size, + + + * + + ); + + + + + + + nsresult (*Get + + + + )( + + *pThis, + + * + + ); + + + + + + nsresult (*Get + + + + )( + + *pThis, + + * + + ); + nsresult (*Set + + + + )( + + *pThis, + + + + ); + + + + + + + + + + + + #define + + + + + (p, a + + + + ) ((p)->lpVtbl->Get + + + + (p, a + + + + )) + + + #define + + + + + (p, a + + + + ) ((p)->lpVtbl->Get + + + + (p, a + + + + )) + + + + #define + + + + + (p, a + + + + ) ((p)->lpVtbl->Set + + + + (p, a + + + + )) + + + #define + + + + + (p, a + + + + ) ((p)->lpVtbl->Set + + + + (p, a + + + + )) + + + + + + + + + + + + nsresult (* + + + + + )( + + + *pThis, + + + + , + + + + ); + + + )( + + *pThis ); + + + + + + + + #define + + + + + (p + + , a + + + + + ) ((p)->lpVtbl-> + + + + (p + + , a + + + + + )) + + + + + + + + + + + + + + #define NS_ + + + + _CID { \ + 0x + , 0x + , 0x + , \ + { 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + } \ } + #define NS_ + + + + + _CONTRACTID "@ + + / + + ;1" + + /* COM compatibility */ + VBOX_EXTERN_CONST(nsCID, CLSID_ + + ); + + + + + + + /* Start of enum + + declaration */ + #define + + + + + + #define + + + + _IID { \ + 0x + , 0x + , 0x + , \ + { 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + } \ } + enum + + { + + + + + _ + = + + , + + + + }; + /* End of enum + + declaration */ +#define + + + + + + + + + + + + + PRUint32 + + Size, + + + PRUint32 * + + Size, + + + PRUint32 * + + Size, + + + PRUint32 + + Size, + + + + + + + + * + + + + ** + + + + ** + + + + * + + + + + + + + + + + + + + + * + + + + * + + + + + + + + + + + + + + + PRUint32 + + * + + a + + + + Size, + + + + * + + + * + + a + + + + + + + + + + + + + + + + + + + booleanPtr + octetPtr + shortPtr + ushortPtr + longPtr + llongPtr + ulongPtr + ullongPtr + + + + attribute 'mod= + + ' cannot be used with type + + + + + + + + + + wstring + + + + attribute 'mod= + + ' cannot be used with type + + + + + + + + + + of attribute 'mod' is invalid! + + + + + + + + + nsresult + boolean + octet + short + unsigned short + long + long long + unsigned long + unsigned long long + char + wchar + string + wstring + + + + + + + nsIDPtr + + + + + : Non-readonly uuid attributes are not supported! + + + + + + + + nsIDRef + + + nsIDPtr + + + + + + + nsISupports + + + + + PRUint32 + + + + + + + + + Unknown parameter type: + + + + + + + + + + + + + + + + + + + + + + + PRBool * + PRUint8 * + PRInt16 * + PRUint16 * + PRInt32 * + PRInt64 * + PRUint32 * + PRUint64 * + + + + attribute 'mod= + + ' cannot be used with type + + + + + + + + + + PRUnichar * + + + + attribute 'mod= + + ' cannot be used with type + + + + + + + + + + + + nsresult + PRBool + PRUint8 + PRInt16 + PRUint16 + PRInt32 + PRInt64 + PRUint32 + PRUint64 + char + PRUnichar + + char * + PRUnichar * + + + + + + + nsID * + + + + + + + const nsID * + + + nsID * + + + + + + + nsISupports * + + + + + PRUint32 + + + + + * + + + + + + + + + + + diff --git a/src/VBox/Main/cbinding/makefile.tstCAPIGlue b/src/VBox/Main/cbinding/makefile.tstCAPIGlue new file mode 100644 index 00000000..057395a1 --- /dev/null +++ b/src/VBox/Main/cbinding/makefile.tstCAPIGlue @@ -0,0 +1,50 @@ +# $Revision: 91907 $ +## @file makefile.tstCAPIGlue +# Makefile for sample program illustrating use of C binding for COM/XPCOM. +# + +# +# Copyright (C) 2009-2014 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +PATH_SDK = ../../.. +CAPI_INC = -I$(PATH_SDK)/bindings/c/include +ifeq ($(BUILD_PLATFORM),win) +PLATFORM_INC = -I$(PATH_SDK)/bindings/mscom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/mscom/lib +else +PLATFORM_INC = -I$(PATH_SDK)/bindings/xpcom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/xpcom/lib +endif +GLUE_DIR = $(PATH_SDK)/bindings/c/glue +GLUE_INC = -I$(GLUE_DIR) + +CC = gcc +CFLAGS = -g -Wall + +.PHONY: all +all: tstCAPIGlue + +.PHONY: clean +clean: + rm -f tstCAPIGlue.o VBoxCAPIGlue.o VirtualBox_i.o tstCAPIGlue + +tstCAPIGlue: tstCAPIGlue.o VBoxCAPIGlue.o VirtualBox_i.o + $(CC) -o $@ $^ -ldl -lpthread + +tstCAPIGlue.o: tstCAPIGlue.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +VBoxCAPIGlue.o: $(GLUE_DIR)/VBoxCAPIGlue.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +VirtualBox_i.o: $(PLATFORM_LIB)/VirtualBox_i.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< diff --git a/src/VBox/Main/cbinding/makefile.tstXPCOMCGlue b/src/VBox/Main/cbinding/makefile.tstXPCOMCGlue deleted file mode 100644 index 07838aba..00000000 --- a/src/VBox/Main/cbinding/makefile.tstXPCOMCGlue +++ /dev/null @@ -1,45 +0,0 @@ -# $Revision: 60692 $ -## @file makefile.tstLinuxC -# Makefile for sample program illustrating use of C binding for XPCOM. -# - -# -# Copyright (C) 2009 Oracle Corporation -# -# This file is part of VirtualBox Open Source Edition (OSE), as -# available from http://www.virtualbox.org. This file is free software; -# you can redistribute it and/or modify it under the terms of the GNU -# General Public License (GPL) as published by the Free Software -# Foundation, in version 2 as it comes in the "COPYING" file of the -# VirtualBox OSE distribution. VirtualBox OSE is distributed in the -# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -# - -INCS_XPCOM = -I../../include -GLUE_DIR = .. -GLUE_INC = -I.. - -CC = gcc -CFLAGS = -g -Wall - -.PHONY: all -all: tstXPCOMCGlue tstXPCOMCCall - -.PHONY: clean -clean: - rm -f tstXPCOMCGlue.o tstXPCOMCGlue VBoxXPCOMCGlue.o tstXPCOMCCall.o tstXPCOMCCall - -tstXPCOMCGlue: tstXPCOMCGlue.o VBoxXPCOMCGlue.o - $(CC) -o $@ $^ -ldl - -tstXPCOMCGlue.o: tstXPCOMCGlue.c - $(CC) $(CFLAGS) $(INCS_XPCOM) $(GLUE_INC) -o $@ -c $< - -tstXPCOMCCall: tstXPCOMCCall.o VBoxXPCOMCGlue.o - $(CC) -o $@ $^ -ldl -lpthread - -tstXPCOMCCall.o: tstXPCOMCCall.c - $(CC) $(CFLAGS) $(INCS_XPCOM) $(GLUE_INC) -o $@ -c $< - -VBoxXPCOMCGlue.o: $(GLUE_DIR)/VBoxXPCOMCGlue.c - $(CC) $(CFLAGS) $(INCS_XPCOM) $(GLUE_INC) -o $@ -c $< diff --git a/src/VBox/Main/cbinding/tstCAPIGlue.c b/src/VBox/Main/cbinding/tstCAPIGlue.c new file mode 100644 index 00000000..5715a6f0 --- /dev/null +++ b/src/VBox/Main/cbinding/tstCAPIGlue.c @@ -0,0 +1,1112 @@ +/* $Revision: 91907 $ */ +/** @file tstCAPIGlue.c + * Demonstrator program to illustrate use of C bindings of Main API. + * + * It has sample code showing how to retrieve all available error information, + * and how to handle active (event delivery through callbacks) or passive + * (event delivery through a polling mechanism) event listeners. + */ + +/* + * Copyright (C) 2009-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "VBoxCAPIGlue.h" +#include +#include +#include +#ifndef WIN32 +# include +# include +# include +#endif + +/** + * Select between active event listener (defined) and passive event listener + * (undefined). The active event listener case needs much more code, and + * additionally requires a lot more platform dependent code. + */ +#undef USE_ACTIVE_EVENT_LISTENER + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Set by Ctrl+C handler. */ +static volatile int g_fStop = 0; + +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 +/** The COM type information for IEventListener, for implementing IDispatch. */ +static ITypeInfo *g_pTInfoIEventListener = NULL; +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + +static const char *GetStateName(MachineState_T machineState) +{ + switch (machineState) + { + case MachineState_Null: return ""; + case MachineState_PoweredOff: return "PoweredOff"; + case MachineState_Saved: return "Saved"; + case MachineState_Teleported: return "Teleported"; + case MachineState_Aborted: return "Aborted"; + case MachineState_Running: return "Running"; + case MachineState_Paused: return "Paused"; + case MachineState_Stuck: return "Stuck"; + case MachineState_Teleporting: return "Teleporting"; + case MachineState_LiveSnapshotting: return "LiveSnapshotting"; + case MachineState_Starting: return "Starting"; + case MachineState_Stopping: return "Stopping"; + case MachineState_Saving: return "Saving"; + case MachineState_Restoring: return "Restoring"; + case MachineState_TeleportingPausedVM: return "TeleportingPausedVM"; + case MachineState_TeleportingIn: return "TeleportingIn"; + case MachineState_FaultTolerantSyncing: return "FaultTolerantSyncing"; + case MachineState_DeletingSnapshotOnline: return "DeletingSnapshotOnline"; + case MachineState_DeletingSnapshotPaused: return "DeletingSnapshotPaused"; + case MachineState_RestoringSnapshot: return "RestoringSnapshot"; + case MachineState_DeletingSnapshot: return "DeletingSnapshot"; + case MachineState_SettingUp: return "SettingUp"; + default: return "no idea"; + } +} + +/** + * Ctrl+C handler, terminate event listener. + * + * Remember that most function calls are not allowed in this context (including + * printf!), so make sure that this does as little as possible. + * + * @param iInfo Platform dependent detail info (ignored). + */ +static BOOL VBOX_WINAPI ctrlCHandler(DWORD iInfo) +{ + (void)iInfo; + g_fStop = 1; + return TRUE; +} + +/** + * Sample event processing function, dumping some event information. + * Shared between active and passive event demo, to highlight that this part + * is identical between the two. + */ +static HRESULT EventListenerDemoProcessEvent(IEvent *event) +{ + VBoxEventType_T evType; + HRESULT rc; + + if (!event) + { + printf("event null\n"); + return S_OK; + } + + evType = VBoxEventType_Invalid; + rc = IEvent_get_Type(event, &evType); + if (FAILED(rc)) + { + printf("cannot get event type, rc=%#x\n", rc); + return S_OK; + } + + switch (evType) + { + case VBoxEventType_OnMousePointerShapeChanged: + printf("OnMousePointerShapeChanged\n"); + break; + + case VBoxEventType_OnMouseCapabilityChanged: + printf("OnMouseCapabilityChanged\n"); + break; + + case VBoxEventType_OnKeyboardLedsChanged: + printf("OnMouseCapabilityChanged\n"); + break; + + case VBoxEventType_OnStateChanged: + { + IStateChangedEvent *ev = NULL; + enum MachineState state; + rc = IEvent_QueryInterface(event, &IID_IStateChangedEvent, (void **)&ev); + if (FAILED(rc)) + { + printf("cannot get StateChangedEvent interface, rc=%#x\n", rc); + return S_OK; + } + if (!ev) + { + printf("StateChangedEvent reference null\n"); + return S_OK; + } + rc = IStateChangedEvent_get_State(ev, &state); + if (FAILED(rc)) + printf("warning: cannot get state, rc=%#x\n", rc); + IStateChangedEvent_Release(ev); + printf("OnStateChanged: %s\n", GetStateName(state)); + + fflush(stdout); + if ( state == MachineState_PoweredOff + || state == MachineState_Saved + || state == MachineState_Teleported + || state == MachineState_Aborted + ) + g_fStop = 1; + break; + } + + case VBoxEventType_OnAdditionsStateChanged: + printf("OnAdditionsStateChanged\n"); + break; + + case VBoxEventType_OnNetworkAdapterChanged: + printf("OnNetworkAdapterChanged\n"); + break; + + case VBoxEventType_OnSerialPortChanged: + printf("OnSerialPortChanged\n"); + break; + + case VBoxEventType_OnParallelPortChanged: + printf("OnParallelPortChanged\n"); + break; + + case VBoxEventType_OnStorageControllerChanged: + printf("OnStorageControllerChanged\n"); + break; + + case VBoxEventType_OnMediumChanged: + printf("OnMediumChanged\n"); + break; + + case VBoxEventType_OnVRDEServerChanged: + printf("OnVRDEServerChanged\n"); + break; + + case VBoxEventType_OnUSBControllerChanged: + printf("OnUSBControllerChanged\n"); + break; + + case VBoxEventType_OnUSBDeviceStateChanged: + printf("OnUSBDeviceStateChanged\n"); + break; + + case VBoxEventType_OnSharedFolderChanged: + printf("OnSharedFolderChanged\n"); + break; + + case VBoxEventType_OnRuntimeError: + printf("OnRuntimeError\n"); + break; + + case VBoxEventType_OnCanShowWindow: + printf("OnCanShowWindow\n"); + break; + case VBoxEventType_OnShowWindow: + printf("OnShowWindow\n"); + break; + + default: + printf("unknown event: %d\n", evType); + } + + return S_OK; +} + +#ifdef USE_ACTIVE_EVENT_LISTENER + +struct IEventListenerDemo; +typedef struct IEventListenerDemo IEventListenerDemo; + +typedef struct IEventListenerDemoVtbl +{ + HRESULT (*QueryInterface)(IEventListenerDemo *pThis, REFIID riid, void **ppvObject); + ULONG (*AddRef)(IEventListenerDemo *pThis); + ULONG (*Release)(IEventListenerDemo *pThis); +#ifdef WIN32 + HRESULT (*GetTypeInfoCount)(IEventListenerDemo *pThis, UINT *pctinfo); + HRESULT (*GetTypeInfo)(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo); + HRESULT (*GetIDsOfNames)(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); + HRESULT (*Invoke)(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr); +#endif + HRESULT (*HandleEvent)(IEventListenerDemo *pThis, IEvent *aEvent); +} IEventListenerDemoVtbl; + +typedef struct IEventListenerDemo +{ + struct IEventListenerDemoVtbl *lpVtbl; + + int cRef; + +#ifdef WIN32 + /* Active event delivery needs a free threaded marshaler, as the default + * proxy marshaling cannot deal correctly with this case. */ + IUnknown *pUnkMarshaler; +#endif +} IEventListenerDemo; + +/* Defines for easily calling IEventListenerDemo functions. */ + +/* IUnknown functions. */ +#define IEventListenerDemo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl->QueryInterface(This,riid,ppvObject) ) + +#define IEventListenerDemo_AddRef(This) \ + ( (This)->lpVtbl->AddRef(This) ) + +#define IEventListenerDemo_Release(This) \ + ( (This)->lpVtbl->Release(This) ) + +#ifdef WIN32 +/* IDispatch functions. */ +#define IEventListenerDemo_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl->GetTypeInfoCount(This,pctinfo) ) + +#define IEventListenerDemo_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl->GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IEventListenerDemo_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl->GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IEventListenerDemo_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl->Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) +#endif + +/* IEventListener functions. */ +#define IEventListenerDemo_HandleEvent(This,aEvent) \ + ( (This)->lpVtbl->HandleEvent(This,aEvent) ) + + +/** + * Event handler function, for active event processing. + */ +static HRESULT IEventListenerDemoImpl_HandleEvent(IEventListenerDemo *pThis, IEvent *event) +{ + return EventListenerDemoProcessEvent(event); +} + +static HRESULT IEventListenerDemoImpl_QueryInterface(IEventListenerDemo *pThis, const IID *iid, void **resultp) +{ + /* match iid */ + if ( !memcmp(iid, &IID_IEventListener, sizeof(IID)) + || !memcmp(iid, &IID_IDispatch, sizeof(IID)) + || !memcmp(iid, &IID_IUnknown, sizeof(IID))) + { + IEventListenerDemo_AddRef(pThis); + *resultp = pThis; + return S_OK; + } +#ifdef WIN32 + if (!memcmp(iid, &IID_IMarshal, sizeof(IID))) + return IUnknown_QueryInterface(pThis->pUnkMarshaler, iid, resultp); +#endif + + return E_NOINTERFACE; +} + +static HRESULT IEventListenerDemoImpl_AddRef(IEventListenerDemo *pThis) +{ + return ++(pThis->cRef); +} + +static HRESULT IEventListenerDemoImpl_Release(IEventListenerDemo *pThis) +{ + HRESULT c; + + c = --(pThis->cRef); + if (!c) + free(pThis); + return c; +} + +#ifdef WIN32 +static HRESULT IEventListenerDemoImpl_GetTypeInfoCount(IEventListenerDemo *pThis, UINT *pctinfo) +{ + if (!pctinfo) + return E_POINTER; + *pctinfo = 1; + return S_OK; +} + +static HRESULT IEventListenerDemoImpl_GetTypeInfo(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + if (!ppTInfo) + return E_POINTER; + ITypeInfo_AddRef(g_pTInfoIEventListener); + *ppTInfo = g_pTInfoIEventListener; + return S_OK; +} + +static HRESULT IEventListenerDemoImpl_GetIDsOfNames(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + return ITypeInfo_GetIDsOfNames(g_pTInfoIEventListener, rgszNames, cNames, rgDispId); +} + +static HRESULT IEventListenerDemoImpl_Invoke(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + return ITypeInfo_Invoke(g_pTInfoIEventListener, (IDispatch *)pThis, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT LoadTypeInfo(REFIID riid, ITypeInfo **pTInfo) +{ + HRESULT rc; + ITypeLib *pTypeLib; + rc = LoadRegTypeLib(&LIBID_VirtualBox, 1 /* major */, 0 /* minor */, 0 /* lcid */, &pTypeLib); + if (FAILED(rc)) + return rc; + rc = ITypeLib_GetTypeInfoOfGuid(pTypeLib, riid, pTInfo); + + /* No longer need access to the type lib, release it. */ + ITypeLib_Release(pTypeLib); + + return rc; +} +#endif + +#ifdef __GNUC__ +typedef struct IEventListenerDemoVtblInt +{ + ptrdiff_t offset_to_top; + void *typeinfo; + IEventListenerDemoVtbl lpVtbl; +} IEventListenerDemoVtblInt; + +static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt = +{ + 0, /* offset_to_top */ + NULL, /* typeinfo, not vital */ + { + IEventListenerDemoImpl_QueryInterface, + IEventListenerDemoImpl_AddRef, + IEventListenerDemoImpl_Release, +#ifdef WIN32 + IEventListenerDemoImpl_GetTypeInfoCount, + IEventListenerDemoImpl_GetTypeInfo, + IEventListenerDemoImpl_GetIDsOfNames, + IEventListenerDemoImpl_Invoke, +#endif + IEventListenerDemoImpl_HandleEvent + } +}; +#elif defined(_MSC_VER) +typedef struct IEventListenerDemoVtblInt +{ + IEventListenerDemoVtbl lpVtbl; +} IEventListenerDemoVtblInt; + +static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt = +{ + { + IEventListenerDemoImpl_QueryInterface, + IEventListenerDemoImpl_AddRef, + IEventListenerDemoImpl_Release, +#ifdef WIN32 + IEventListenerDemoImpl_GetTypeInfoCount, + IEventListenerDemoImpl_GetTypeInfo, + IEventListenerDemoImpl_GetIDsOfNames, + IEventListenerDemoImpl_Invoke, +#endif + IEventListenerDemoImpl_HandleEvent + } +}; +#else +# error Port me! +#endif + +/** + * Register active event listener for the selected VM. + * + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + * @param id identifies the machine to start + */ +static void registerActiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId) +{ + IConsole *console = NULL; + HRESULT rc; + + rc = ISession_get_Console(session, &console); + if ((SUCCEEDED(rc)) && console) + { + IEventSource *es = NULL; + rc = IConsole_get_EventSource(console, &es); + if (SUCCEEDED(rc) && es) + { + static const ULONG interestingEvents[] = + { + VBoxEventType_OnMousePointerShapeChanged, + VBoxEventType_OnMouseCapabilityChanged, + VBoxEventType_OnKeyboardLedsChanged, + VBoxEventType_OnStateChanged, + VBoxEventType_OnAdditionsStateChanged, + VBoxEventType_OnNetworkAdapterChanged, + VBoxEventType_OnSerialPortChanged, + VBoxEventType_OnParallelPortChanged, + VBoxEventType_OnStorageControllerChanged, + VBoxEventType_OnMediumChanged, + VBoxEventType_OnVRDEServerChanged, + VBoxEventType_OnUSBControllerChanged, + VBoxEventType_OnUSBDeviceStateChanged, + VBoxEventType_OnSharedFolderChanged, + VBoxEventType_OnRuntimeError, + VBoxEventType_OnCanShowWindow, + VBoxEventType_OnShowWindow + }; + SAFEARRAY *interestingEventsSA = NULL; + IEventListenerDemo *consoleListener = NULL; + + /* The VirtualBox API expects enum values as VT_I4, which in the + * future can be hopefully relaxed. */ + interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0])); + g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents)); + + consoleListener = calloc(1, sizeof(IEventListenerDemo)); + if (consoleListener) + { + consoleListener->lpVtbl = &(g_IEventListenerDemoVtblInt.lpVtbl); +#ifdef WIN32 + CoCreateFreeThreadedMarshaler((IUnknown *)consoleListener, &consoleListener->pUnkMarshaler); +#endif + IEventListenerDemo_AddRef(consoleListener); + + rc = IEventSource_RegisterListener(es, (IEventListener *)consoleListener, + ComSafeArrayAsInParam(interestingEventsSA), + 1 /* active */); + if (SUCCEEDED(rc)) + { + /* Just wait here for events, no easy way to do this better + * as there's not much to do after this completes. */ + printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); + fflush(stdout); +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, TRUE); +#else + signal(SIGINT, (void (*)(int))ctrlCHandler); +#endif + + while (!g_fStop) + { + g_pVBoxFuncs->pfnProcessEventQueue(250); + } + +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, FALSE); +#else + signal(SIGINT, SIG_DFL); +#endif + } + else + { + printf("Failed to register event listener.\n"); + } + IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); +#ifdef WIN32 + if (consoleListener->pUnkMarshaler) + IUnknown_Release(consoleListener->pUnkMarshaler); +#endif + IEventListenerDemo_Release(consoleListener); + } + else + { + printf("Failed while allocating memory for console event listener.\n"); + } + g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); + IEventSource_Release(es); + } + else + { + printf("Failed to get the event source instance.\n"); + } + IConsole_Release(console); + } +} + +#else /* !USE_ACTIVE_EVENT_LISTENER */ + +/** + * Register passive event listener for the selected VM. + * + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + * @param id identifies the machine to start + */ +static void registerPassiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId) +{ + IConsole *console = NULL; + HRESULT rc; + + rc = ISession_get_Console(session, &console); + if ((SUCCEEDED(rc)) && console) + { + IEventSource *es = NULL; + rc = IConsole_get_EventSource(console, &es); + if (SUCCEEDED(rc) && es) + { + static const ULONG interestingEvents[] = + { + VBoxEventType_OnMousePointerShapeChanged, + VBoxEventType_OnMouseCapabilityChanged, + VBoxEventType_OnKeyboardLedsChanged, + VBoxEventType_OnStateChanged, + VBoxEventType_OnAdditionsStateChanged, + VBoxEventType_OnNetworkAdapterChanged, + VBoxEventType_OnSerialPortChanged, + VBoxEventType_OnParallelPortChanged, + VBoxEventType_OnStorageControllerChanged, + VBoxEventType_OnMediumChanged, + VBoxEventType_OnVRDEServerChanged, + VBoxEventType_OnUSBControllerChanged, + VBoxEventType_OnUSBDeviceStateChanged, + VBoxEventType_OnSharedFolderChanged, + VBoxEventType_OnRuntimeError, + VBoxEventType_OnCanShowWindow, + VBoxEventType_OnShowWindow + }; + SAFEARRAY *interestingEventsSA = NULL; + IEventListener *consoleListener = NULL; + + /* The VirtualBox API expects enum values as VT_I4, which in the + * future can be hopefully relaxed. */ + interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0])); + g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents)); + + rc = IEventSource_CreateListener(es, &consoleListener); + if (SUCCEEDED(rc) && consoleListener) + { + rc = IEventSource_RegisterListener(es, consoleListener, + ComSafeArrayAsInParam(interestingEventsSA), + 0 /* passive */); + if (SUCCEEDED(rc)) + { + /* Just wait here for events, no easy way to do this better + * as there's not much to do after this completes. */ + printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); + fflush(stdout); +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, TRUE); +#else + signal(SIGINT, (void (*)(int))ctrlCHandler); +#endif + + while (!g_fStop) + { + IEvent *ev = NULL; + rc = IEventSource_GetEvent(es, consoleListener, 250, &ev); + if (FAILED(rc)) + { + printf("Failed getting event: %#x\n", rc); + g_fStop = 1; + continue; + } + /* handle timeouts, resulting in NULL events */ + if (!ev) + continue; + rc = EventListenerDemoProcessEvent(ev); + if (FAILED(rc)) + { + printf("Failed processing event: %#x\n", rc); + g_fStop = 1; + /* finish processing the event */ + } + rc = IEventSource_EventProcessed(es, consoleListener, ev); + if (FAILED(rc)) + { + printf("Failed to mark event as processed: %#x\n", rc); + g_fStop = 1; + /* continue with event release */ + } + if (ev) + { + IEvent_Release(ev); + ev = NULL; + } + } + +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, FALSE); +#else + signal(SIGINT, SIG_DFL); +#endif + } + else + { + printf("Failed to register event listener.\n"); + } + IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); + IEventListener_Release(consoleListener); + } + else + { + printf("Failed to create an event listener instance.\n"); + } + g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); + IEventSource_Release(es); + } + else + { + printf("Failed to get the event source instance.\n"); + } + IConsole_Release(console); + } +} + +#endif /* !USE_ACTIVE_EVENT_LISTENER */ + +/** + * Print detailed error information if available. + * @param pszExecutable string with the executable name + * @param pszErrorMsg string containing the code location specific error message + * @param rc COM/XPCOM result code + */ +static void PrintErrorInfo(const char *pszExecutable, const char *pszErrorMsg, HRESULT rc) +{ + IErrorInfo *ex; + HRESULT rc2 = S_OK; + fprintf(stderr, "%s: %s (rc=%#010x)\n", pszExecutable, pszErrorMsg, (unsigned)rc); + rc2 = g_pVBoxFuncs->pfnGetException(&ex); + if (SUCCEEDED(rc2)) + { + IVirtualBoxErrorInfo *ei; + rc2 = IErrorInfo_QueryInterface(ex, &IID_IVirtualBoxErrorInfo, (void **)&ei); + if (FAILED(rc2)) + ei = NULL; + if (ei) + { + /* got extended error info, maybe multiple infos */ + do + { + LONG resultCode = S_OK; + BSTR componentUtf16 = NULL; + char *component = NULL; + BSTR textUtf16 = NULL; + char *text = NULL; + IVirtualBoxErrorInfo *ei_next = NULL; + fprintf(stderr, "Extended error info (IVirtualBoxErrorInfo):\n"); + + IVirtualBoxErrorInfo_get_ResultCode(ei, &resultCode); + fprintf(stderr, " resultCode=%#010x\n", (unsigned)resultCode); + + IVirtualBoxErrorInfo_get_Component(ei, &componentUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(componentUtf16, &component); + g_pVBoxFuncs->pfnComUnallocString(componentUtf16); + fprintf(stderr, " component=%s\n", component); + g_pVBoxFuncs->pfnUtf8Free(component); + + IVirtualBoxErrorInfo_get_Text(ei, &textUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); + g_pVBoxFuncs->pfnComUnallocString(textUtf16); + fprintf(stderr, " text=%s\n", text); + g_pVBoxFuncs->pfnUtf8Free(text); + + rc2 = IVirtualBoxErrorInfo_get_Next(ei, &ei_next); + if (FAILED(rc2)) + ei_next = NULL; + IVirtualBoxErrorInfo_Release(ei); + ei = ei_next; + } + while (ei); + } + + IErrorInfo_Release(ex); + g_pVBoxFuncs->pfnClearException(); + } +} + +/** + * Start a VM. + * + * @param argv0 executable name + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + * @param id identifies the machine to start + */ +static void startVM(const char *argv0, IVirtualBox *virtualBox, ISession *session, BSTR id) +{ + HRESULT rc; + IMachine *machine = NULL; + IProgress *progress = NULL; + BSTR env = NULL; + BSTR sessionType; + + rc = IVirtualBox_FindMachine(virtualBox, id, &machine); + if (FAILED(rc) || !machine) + { + PrintErrorInfo(argv0, "Error: Couldn't get the Machine reference", rc); + return; + } + + g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType); + rc = IMachine_LaunchVMProcess(machine, session, sessionType, env, &progress); + g_pVBoxFuncs->pfnUtf16Free(sessionType); + if (SUCCEEDED(rc)) + { + BOOL completed; + LONG resultCode; + + printf("Waiting for the remote session to open...\n"); + IProgress_WaitForCompletion(progress, -1); + + rc = IProgress_get_Completed(progress, &completed); + if (FAILED(rc)) + fprintf(stderr, "Error: GetCompleted status failed\n"); + + IProgress_get_ResultCode(progress, &resultCode); + if (FAILED(resultCode)) + { + IVirtualBoxErrorInfo *errorInfo; + BSTR textUtf16; + char *text; + + IProgress_get_ErrorInfo(progress, &errorInfo); + IVirtualBoxErrorInfo_get_Text(errorInfo, &textUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); + printf("Error: %s\n", text); + + g_pVBoxFuncs->pfnComUnallocString(textUtf16); + g_pVBoxFuncs->pfnUtf8Free(text); + IVirtualBoxErrorInfo_Release(errorInfo); + } + else + { + fprintf(stderr, "VM process has been successfully started\n"); + + /* Kick off the event listener demo part, which is quite separate. + * Ignore it if you need a more basic sample. */ +#ifdef USE_ACTIVE_EVENT_LISTENER + registerActiveEventListener(virtualBox, session, id); +#else /* !USE_ACTIVE_EVENT_LISTENER */ + registerPassiveEventListener(virtualBox, session, id); +#endif /* !USE_ACTIVE_EVENT_LISTENER */ + } + IProgress_Release(progress); + } + else + PrintErrorInfo(argv0, "Error: LaunchVMProcess failed", rc); + + /* It's important to always release resources. */ + IMachine_Release(machine); +} + +/** + * List the registered VMs. + * + * @param argv0 executable name + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + */ +static void listVMs(const char *argv0, IVirtualBox *virtualBox, ISession *session) +{ + HRESULT rc; + SAFEARRAY *machinesSA = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc(); + IMachine **machines = NULL; + ULONG machineCnt = 0; + ULONG i; + unsigned start_id; + + /* + * Get the list of all registered VMs. + */ + rc = IVirtualBox_get_Machines(virtualBox, ComSafeArrayAsOutIfaceParam(machinesSA, IMachine *)); + if (FAILED(rc)) + { + PrintErrorInfo(argv0, "could not get list of machines", rc); + return; + } + + /* + * Extract interface pointers from machinesSA, and update the reference + * counter of each object, as destroying machinesSA would call Release. + */ + g_pVBoxFuncs->pfnSafeArrayCopyOutIfaceParamHelper((IUnknown ***)&machines, &machineCnt, machinesSA); + g_pVBoxFuncs->pfnSafeArrayDestroy(machinesSA); + + if (!machineCnt) + { + printf("\tNo VMs\n"); + return; + } + + printf("VM List:\n\n"); + + /* + * Iterate through the collection. + */ + + for (i = 0; i < machineCnt; ++i) + { + IMachine *machine = machines[i]; + BOOL isAccessible = FALSE; + + printf("\tMachine #%u\n", (unsigned)i); + + if (!machine) + { + printf("\t(skipped, NULL)\n"); + continue; + } + + IMachine_get_Accessible(machine, &isAccessible); + + if (isAccessible) + { + BSTR machineNameUtf16; + char *machineName; + + IMachine_get_Name(machine, &machineNameUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16,&machineName); + g_pVBoxFuncs->pfnComUnallocString(machineNameUtf16); + printf("\tName: %s\n", machineName); + g_pVBoxFuncs->pfnUtf8Free(machineName); + } + else + { + printf("\tName: \n"); + } + + { + BSTR uuidUtf16; + char *uuidUtf8; + + IMachine_get_Id(machine, &uuidUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(uuidUtf16, &uuidUtf8); + g_pVBoxFuncs->pfnComUnallocString(uuidUtf16); + printf("\tUUID: %s\n", uuidUtf8); + g_pVBoxFuncs->pfnUtf8Free(uuidUtf8); + } + + if (isAccessible) + { + { + BSTR configFileUtf16; + char *configFileUtf8; + + IMachine_get_SettingsFilePath(machine, &configFileUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(configFileUtf16, &configFileUtf8); + g_pVBoxFuncs->pfnComUnallocString(configFileUtf16); + printf("\tConfig file: %s\n", configFileUtf8); + g_pVBoxFuncs->pfnUtf8Free(configFileUtf8); + } + + { + ULONG memorySize; + + IMachine_get_MemorySize(machine, &memorySize); + printf("\tMemory size: %uMB\n", memorySize); + } + + { + BSTR typeId; + BSTR osNameUtf16; + char *osName; + IGuestOSType *osType = NULL; + + IMachine_get_OSTypeId(machine, &typeId); + IVirtualBox_GetGuestOSType(virtualBox, typeId, &osType); + g_pVBoxFuncs->pfnComUnallocString(typeId); + IGuestOSType_get_Description(osType, &osNameUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(osNameUtf16,&osName); + g_pVBoxFuncs->pfnComUnallocString(osNameUtf16); + printf("\tGuest OS: %s\n\n", osName); + g_pVBoxFuncs->pfnUtf8Free(osName); + + IGuestOSType_Release(osType); + } + } + } + + /* + * Let the user chose a machine to start. + */ + + printf("Type Machine# to start (0 - %u) or 'quit' to do nothing: ", + (unsigned)(machineCnt - 1)); + fflush(stdout); + + if (scanf("%u", &start_id) == 1 && start_id < machineCnt) + { + IMachine *machine = machines[start_id]; + + if (machine) + { + BSTR uuidUtf16 = NULL; + + IMachine_get_Id(machine, &uuidUtf16); + startVM(argv0, virtualBox, session, uuidUtf16); + g_pVBoxFuncs->pfnComUnallocString(uuidUtf16); + } + } + + /* + * Don't forget to release the objects in the array. + */ + + for (i = 0; i < machineCnt; ++i) + { + IMachine *machine = machines[i]; + + if (machine) + { + IMachine_Release(machine); + } + } + if (machines) + free(machines); +} + +/* Main - Start the ball rolling. */ + +int main(int argc, char **argv) +{ + IVirtualBoxClient *vboxclient = NULL; + IVirtualBox *vbox = NULL; + ISession *session = NULL; + ULONG revision = 0; + BSTR versionUtf16 = NULL; + BSTR homefolderUtf16 = NULL; + HRESULT rc; /* Result code of various function (method) calls. */ + + printf("Starting main()\n"); + + if (VBoxCGlueInit()) + { + fprintf(stderr, "%s: FATAL: VBoxCGlueInit failed: %s\n", + argv[0], g_szVBoxErrMsg); + return EXIT_FAILURE; + } + + { + unsigned ver = g_pVBoxFuncs->pfnGetVersion(); + printf("VirtualBox version: %u.%u.%u\n", ver / 1000000, ver / 1000 % 1000, ver % 1000); + ver = g_pVBoxFuncs->pfnGetAPIVersion(); + printf("VirtualBox API version: %u.%u\n", ver / 1000, ver % 1000); + } + + g_pVBoxFuncs->pfnClientInitialize(NULL, &vboxclient); + if (!vboxclient) + { + fprintf(stderr, "%s: FATAL: could not get VirtualBoxClient reference\n", argv[0]); + return EXIT_FAILURE; + } + + printf("----------------------------------------------------\n"); + + rc = IVirtualBoxClient_get_VirtualBox(vboxclient, &vbox); + if (FAILED(rc) || !vbox) + { + PrintErrorInfo(argv[0], "FATAL: could not get VirtualBox reference", rc); + return EXIT_FAILURE; + } + rc = IVirtualBoxClient_get_Session(vboxclient, &session); + if (FAILED(rc) || !session) + { + PrintErrorInfo(argv[0], "FATAL: could not get Session reference", rc); + return EXIT_FAILURE; + } + +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 + rc = LoadTypeInfo(&IID_IEventListener, &g_pTInfoIEventListener); + if (FAILED(rc) || !g_pTInfoIEventListener) + { + PrintErrorInfo(argv[0], "FATAL: could not get type information for IEventListener", rc); + return EXIT_FAILURE; + } +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + + /* + * Now ask for revision, version and home folder information of + * this vbox. Were not using fancy macros here so it + * remains easy to see how we access C++'s vtable. + */ + + /* 1. Revision */ + + rc = IVirtualBox_get_Revision(vbox, &revision); + if (SUCCEEDED(rc)) + printf("\tRevision: %u\n", revision); + else + PrintErrorInfo(argv[0], "GetRevision() failed", rc); + + /* 2. Version */ + + rc = IVirtualBox_get_Version(vbox, &versionUtf16); + if (SUCCEEDED(rc)) + { + char *version = NULL; + g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &version); + printf("\tVersion: %s\n", version); + g_pVBoxFuncs->pfnUtf8Free(version); + g_pVBoxFuncs->pfnComUnallocString(versionUtf16); + } + else + PrintErrorInfo(argv[0], "GetVersion() failed", rc); + + /* 3. Home Folder */ + + rc = IVirtualBox_get_HomeFolder(vbox, &homefolderUtf16); + if (SUCCEEDED(rc)) + { + char *homefolder = NULL; + g_pVBoxFuncs->pfnUtf16ToUtf8(homefolderUtf16, &homefolder); + printf("\tHomeFolder: %s\n", homefolder); + g_pVBoxFuncs->pfnUtf8Free(homefolder); + g_pVBoxFuncs->pfnComUnallocString(homefolderUtf16); + } + else + PrintErrorInfo(argv[0], "GetHomeFolder() failed", rc); + + listVMs(argv[0], vbox, session); + ISession_UnlockMachine(session); + + printf("----------------------------------------------------\n"); + + /* + * Do as mom told us: always clean up after yourself. + */ + +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 + if (g_pTInfoIEventListener) + { + ITypeInfo_Release(g_pTInfoIEventListener); + g_pTInfoIEventListener = NULL; + } +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + + if (session) + { + ISession_Release(session); + session = NULL; + } + if (vbox) + { + IVirtualBox_Release(vbox); + vbox = NULL; + } + if (vboxclient) + { + IVirtualBoxClient_Release(vboxclient); + vboxclient = NULL; + } + + g_pVBoxFuncs->pfnClientUninitialize(); + VBoxCGlueTerm(); + printf("Finished main()\n"); + + return 0; +} +/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/tstXPCOMCCall.c b/src/VBox/Main/cbinding/tstXPCOMCCall.c deleted file mode 100644 index a2311829..00000000 --- a/src/VBox/Main/cbinding/tstXPCOMCCall.c +++ /dev/null @@ -1,759 +0,0 @@ -/* $Revision: 60692 $ */ -/** @file tstXPCOMCGlue.c - * Demonstrator program to illustrate use of C bindings of Main API. - * - * Linux only at the moment due to shared library magic in the Makefile. - */ - -/* - * Copyright (C) 2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#include "VBoxXPCOMCGlue.h" -#include -#include -#include -#include -#include -#include - -/******************************************************************************* -* Internal Functions * -*******************************************************************************/ -static void listVMs(IVirtualBox *virtualBox, ISession *session, nsIEventQueue *queue); -static void registerCallBack(IVirtualBox *virtualBox, ISession *session, PRUnichar *machineId, nsIEventQueue *queue); -static void startVM(IVirtualBox *virtualBox, ISession *session, PRUnichar *id, nsIEventQueue *queue); - -/******************************************************************************* -* Global Variables * -*******************************************************************************/ -/** Set by signal handler. */ -static volatile int g_fStop = 0; - -int volatile g_refcount = 0; - -/* #define for printing nsID type UUID's */ - -#define printUUID(iid) \ -{\ - printf(#iid ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",\ - (unsigned)(iid)->m0,\ - (unsigned)(iid)->m1,\ - (unsigned)(iid)->m2,\ - (unsigned)(iid)->m3[0],\ - (unsigned)(iid)->m3[1],\ - (unsigned)(iid)->m3[2],\ - (unsigned)(iid)->m3[3],\ - (unsigned)(iid)->m3[4],\ - (unsigned)(iid)->m3[5],\ - (unsigned)(iid)->m3[6],\ - (unsigned)(iid)->m3[7]);\ -}\ - -/** - * Callback functions - */ -static const char *GetStateName(PRUint32 machineState) -{ - switch (machineState) - { - case MachineState_Null: return ""; - case MachineState_PoweredOff: return "PoweredOff"; - case MachineState_Saved: return "Saved"; - case MachineState_Teleported: return "Teleported"; - case MachineState_Aborted: return "Aborted"; - case MachineState_Running: return "Running"; - case MachineState_Teleporting: return "Teleporting"; - case MachineState_LiveSnapshotting: return "LiveSnapshotting"; - case MachineState_Paused: return "Paused"; - case MachineState_Stuck: return "Stuck"; - case MachineState_Starting: return "Starting"; - case MachineState_Stopping: return "Stopping"; - case MachineState_Saving: return "Saving"; - case MachineState_Restoring: return "Restoring"; - case MachineState_TeleportingPausedVM: return "TeleportingPausedVM"; - case MachineState_TeleportingIn: return "TeleportingIn"; - case MachineState_Discarding: return "Discarding"; - case MachineState_SettingUp: return "SettingUp"; - default: return "no idea"; - } -} - -static nsresult OnMousePointerShapeChange( - IConsoleCallback *pThis, - PRBool visible, - PRBool alpha, - PRUint32 xHot, - PRUint32 yHot, - PRUint32 width, - PRUint32 height, - PRUint8 * shape -) { - printf("OnMousePointerShapeChange\n"); - return 0; -} - -static nsresult OnMouseCapabilityChange( - IConsoleCallback *pThis, - PRBool supportsAbsolute, - PRBool needsHostCursor -) { - printf("OnMouseCapabilityChange\n"); - return 0; -} - -static nsresult OnKeyboardLedsChange( - IConsoleCallback *pThis, - PRBool numLock, - PRBool capsLock, - PRBool scrollLock -) { - printf("OnMouseCapabilityChange\n"); - return 0; -} - -static nsresult OnStateChange( - IConsoleCallback *pThis, - PRUint32 state -) { - printf("OnStateChange: %s\n", GetStateName(state)); - fflush(stdout); - if ( state == MachineState_PoweredOff - || state == MachineState_Saved - || state == MachineState_Teleported - || state == MachineState_Aborted - ) - g_fStop = 1; - return 0; -} - -static nsresult OnAdditionsStateChange(IConsoleCallback *pThis ) -{ - printf("OnAdditionsStateChange\n"); - return 0; -} - -static nsresult OnNetworkAdapterChange( - IConsoleCallback *pThis, - INetworkAdapter * networkAdapter -) { - printf("OnNetworkAdapterChange\n"); - return 0; -} - -static nsresult OnSerialPortChange( - IConsoleCallback *pThis, - ISerialPort * serialPort -) { - printf("OnSerialPortChange\n"); - return 0; -} - -static nsresult OnParallelPortChange( - IConsoleCallback *pThis, - IParallelPort * parallelPort -) { - printf("OnParallelPortChange\n"); - return 0; -} - -static nsresult OnStorageControllerChange(IConsoleCallback *pThis) -{ - printf("OnStorageControllerChange\n"); - return 0; -} - -static nsresult OnMediumChange(IConsoleCallback *pThis, - IMediumAttachment *mediumAttachment) -{ - printf("OnMediumChange\n"); - return 0; -} - -static nsresult OnVRDPServerChange(IConsoleCallback *pThis ) -{ - printf("OnVRDPServerChange\n"); - return 0; -} - -static nsresult OnUSBControllerChange(IConsoleCallback *pThis ) -{ - printf("OnUSBControllerChange\n"); - return 0; -} - -static nsresult OnUSBDeviceStateChange( - IConsoleCallback *pThis, - IUSBDevice * device, - PRBool attached, - IVirtualBoxErrorInfo * error -) { - printf("OnUSBDeviceStateChange\n"); - return 0; -} - -static nsresult OnSharedFolderChange( - IConsoleCallback *pThis, - PRUint32 scope -) { - printf("OnSharedFolderChange\n"); - return 0; -} - -static nsresult OnRuntimeError( - IConsoleCallback *pThis, - PRBool fatal, - PRUnichar * id, - PRUnichar * message -) { - printf("OnRuntimeError\n"); - return 0; -} - -static nsresult OnCanShowWindow( - IConsoleCallback *pThis, - PRBool * canShow -) { - printf("OnCanShowWindow\n"); - return 0; -} - -static nsresult OnShowWindow( - IConsoleCallback *pThis, - PRUint64 * winId -) { - printf("OnShowWindow\n"); - return 0; -} - - -static nsresult AddRef(nsISupports *pThis) -{ - nsresult c; - - c = ++g_refcount; - printf("AddRef: %d\n", c); - return c; -} - -static nsresult Release(nsISupports *pThis) -{ - nsresult c; - - c = --g_refcount; - printf("Release: %d\n", c); - if (c == 0) - { - /* delete object */ - free(pThis->vtbl); - free(pThis); - } - return c; -} - -static nsresult QueryInterface(nsISupports *pThis, const nsID *iid, void **resultp) -{ - static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID; - static const nsID isupportIID = NS_ISUPPORTS_IID; - - /* match iid */ - if ( memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 - || memcmp(iid, &isupportIID, sizeof(nsID)) == 0) - { - ++g_refcount; - printf("QueryInterface: %d\n", g_refcount); - *resultp = pThis; - return NS_OK; - } - - /* printf("vboxCallback QueryInterface didn't find a matching interface\n"); */ - printUUID(iid); - printUUID(&ivirtualboxCallbackUUID); - return NS_NOINTERFACE; -} - -/** - * Signal callback. - * - * @param iSig The signal number (ignored). - */ -static void sigIntHandler(int iSig) -{ - printf("sigIntHandler\n"); - (void)iSig; - g_fStop = 1; -} - -/** - * Register callback functions for the selected VM. - * - * @param virtualBox ptr to IVirtualBox object - * @param session ptr to ISession object - * @param id identifies the machine to start - * @param queue handle to the event queue - */ -static void registerCallBack(IVirtualBox *virtualBox, ISession *session, PRUnichar *machineId, nsIEventQueue *queue) -{ - IConsole *console = NULL; - nsresult rc; - - rc = session->vtbl->GetConsole(session, &console); - if ((NS_SUCCEEDED(rc)) && console) - { - IConsoleCallback *consoleCallback = NULL; - - consoleCallback = calloc(1, sizeof(IConsoleCallback)); - consoleCallback->vtbl = calloc(1, sizeof(struct IConsoleCallback_vtbl)); - - if (consoleCallback && consoleCallback->vtbl) - { - consoleCallback->vtbl->nsisupports.AddRef = &AddRef; - consoleCallback->vtbl->nsisupports.Release = &Release; - consoleCallback->vtbl->nsisupports.QueryInterface = &QueryInterface; - consoleCallback->vtbl->OnMousePointerShapeChange = &OnMousePointerShapeChange; - consoleCallback->vtbl->OnMouseCapabilityChange = &OnMouseCapabilityChange; - consoleCallback->vtbl->OnKeyboardLedsChange =&OnKeyboardLedsChange; - consoleCallback->vtbl->OnStateChange = &OnStateChange; - consoleCallback->vtbl->OnAdditionsStateChange = &OnAdditionsStateChange; - consoleCallback->vtbl->OnNetworkAdapterChange = &OnNetworkAdapterChange; - consoleCallback->vtbl->OnSerialPortChange = &OnSerialPortChange; - consoleCallback->vtbl->OnParallelPortChange = &OnParallelPortChange; - consoleCallback->vtbl->OnStorageControllerChange = &OnStorageControllerChange; - consoleCallback->vtbl->OnMediumChange = &OnMediumChange; - consoleCallback->vtbl->OnVRDPServerChange = &OnVRDPServerChange; - consoleCallback->vtbl->OnUSBControllerChange = &OnUSBControllerChange; - consoleCallback->vtbl->OnUSBDeviceStateChange = &OnUSBDeviceStateChange; - consoleCallback->vtbl->OnSharedFolderChange = &OnSharedFolderChange; - consoleCallback->vtbl->OnRuntimeError = &OnRuntimeError; - consoleCallback->vtbl->OnCanShowWindow = &OnCanShowWindow; - consoleCallback->vtbl->OnShowWindow = &OnShowWindow; - g_refcount = 1; - - rc = console->vtbl->RegisterCallback(console, consoleCallback); - if (NS_SUCCEEDED(rc)) - { - /* crude way to show how it works, but any - * great ideas anyone? - */ - PRInt32 fd; - int ret; - - printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); - fflush(stdout); - signal(SIGINT, sigIntHandler); - - fd = queue->vtbl->GetEventQueueSelectFD(queue); - if (fd >= 0) - { - while (!g_fStop) - { - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = POLLIN | POLLERR | POLLHUP; - pfd.revents = 0; - - ret = poll(&pfd, 1, 250); - - if (ret <= 0) - continue; - - if (pfd.revents & POLLHUP) - g_fStop = 1; - - queue->vtbl->ProcessPendingEvents(queue); - } - } - else - { - while (!g_fStop) - { - PLEvent *pEvent = NULL; - rc = queue->vtbl->WaitForEvent(queue, &pEvent); - /*printf("event: %p rc=%x\n", (void *)pEvent, rc);*/ - if (NS_SUCCEEDED(rc)) - queue->vtbl->HandleEvent(queue, pEvent); - } - } - signal(SIGINT, SIG_DFL); - } - console->vtbl->UnregisterCallback(console, consoleCallback); - consoleCallback->vtbl->nsisupports.Release((nsISupports *)consoleCallback); - } - else - { - printf("Failed while allocating memory for console Callback.\n"); - } - } -} - -/** - * List the registered VMs. - * - * @param virtualBox ptr to IVirtualBox object - * @param session ptr to ISession object - * @param queue handle to the event queue - */ -static void listVMs(IVirtualBox *virtualBox, ISession *session, nsIEventQueue *queue) -{ - nsresult rc; - IMachine **machines = NULL; - PRUint32 machineCnt = 0; - PRUint32 i; - unsigned start_id; - - /* - * Get the list of all registered VMs. - */ - - rc = virtualBox->vtbl->GetMachines(virtualBox, &machineCnt, &machines); - if (NS_FAILED(rc)) - { - fprintf(stderr, "could not get list of machines, rc=%08x\n", - (unsigned)rc); - return; - } - - if (machineCnt == 0) - { - printf("\tNo VMs\n"); - return; - } - - printf("VM List:\n\n"); - - /* - * Iterate through the collection. - */ - - for (i = 0; i < machineCnt; ++i) - { - IMachine *machine = machines[i]; - PRBool isAccessible = PR_FALSE; - - printf("\tMachine #%u\n", (unsigned)i); - - if (!machine) - { - printf("\t(skipped, NULL)\n"); - continue; - } - - machine->vtbl->GetAccessible(machine, &isAccessible); - - if (isAccessible) - { - PRUnichar *machineNameUtf16; - char *machineName; - - machine->vtbl->GetName(machine, &machineNameUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16,&machineName); - printf("\tName: %s\n", machineName); - - g_pVBoxFuncs->pfnUtf8Free(machineName); - g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16); - } - else - { - printf("\tName: \n"); - } - - { - PRUnichar *uuidUtf16 = NULL; - char *uuidUtf8 = NULL; - - machine->vtbl->GetId(machine, &uuidUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(uuidUtf16, &uuidUtf8); - printf("\tUUID: %s\n", uuidUtf8); - - g_pVBoxFuncs->pfnUtf8Free(uuidUtf8); - g_pVBoxFuncs->pfnUtf16Free(uuidUtf16); - } - - if (isAccessible) - { - { - PRUnichar *configFile; - char *configFile1 = calloc((size_t)64, (size_t)1); - - machine->vtbl->GetSettingsFilePath(machine, &configFile); - g_pVBoxFuncs->pfnUtf16ToUtf8(configFile, &configFile1); - printf("\tConfig file: %s\n", configFile1); - - free(configFile1); - g_pVBoxFuncs->pfnComUnallocMem(configFile); - } - - { - PRUint32 memorySize; - - machine->vtbl->GetMemorySize(machine, &memorySize); - printf("\tMemory size: %uMB\n", memorySize); - } - - { - PRUnichar *typeId; - PRUnichar *osNameUtf16; - char *osName; - IGuestOSType *osType = NULL; - - machine->vtbl->GetOSTypeId(machine, &typeId); - virtualBox->vtbl->GetGuestOSType(virtualBox, typeId, &osType); - osType->vtbl->GetDescription(osType, &osNameUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(osNameUtf16,&osName); - printf("\tGuest OS: %s\n\n", osName); - - osType->vtbl->nsisupports.Release((void *)osType); - g_pVBoxFuncs->pfnUtf8Free(osName); - g_pVBoxFuncs->pfnComUnallocMem(osNameUtf16); - g_pVBoxFuncs->pfnComUnallocMem(typeId); - } - } - } - - /* - * Let the user chose a machine to start. - */ - - printf("Type Machine# to start (0 - %u) or 'quit' to do nothing: ", - (unsigned)(machineCnt - 1)); - fflush(stdout); - - if (scanf("%u", &start_id) == 1 && start_id < machineCnt) - { - IMachine *machine = machines[start_id]; - - if (machine) - { - PRUnichar *uuidUtf16 = NULL; - - machine->vtbl->GetId(machine, &uuidUtf16); - startVM(virtualBox, session, uuidUtf16, queue); - - g_pVBoxFuncs->pfnUtf16Free(uuidUtf16); - } - } - - /* - * Don't forget to release the objects in the array. - */ - - for (i = 0; i < machineCnt; ++i) - { - IMachine *machine = machines[i]; - - if (machine) - { - machine->vtbl->nsisupports.Release((nsISupports *)machine); - } - } -} - -/** - * Start a VM. - * - * @param virtualBox ptr to IVirtualBox object - * @param session ptr to ISession object - * @param id identifies the machine to start - * @param queue handle to the event queue - */ - -static void startVM(IVirtualBox *virtualBox, ISession *session, PRUnichar *id, nsIEventQueue *queue) -{ - nsresult rc; - IMachine *machine = NULL; - IProgress *progress = NULL; - PRUnichar *env = NULL; - PRUnichar *sessionType; - - rc = virtualBox->vtbl->GetMachine(virtualBox, id, &machine); - - if (NS_FAILED(rc) || !machine) - { - fprintf(stderr, "Error: Couldn't get the machine handle.\n"); - return; - } - - g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType); - - rc = virtualBox->vtbl->OpenRemoteSession( - virtualBox, - session, - id, - sessionType, - env, - &progress - ); - - g_pVBoxFuncs->pfnUtf16Free(sessionType); - - if (NS_FAILED(rc)) - { - fprintf(stderr, "Error: OpenRemoteSession failed.\n"); - } - else - { - PRBool completed; - PRInt32 resultCode; - - printf("Waiting for the remote session to open...\n"); - progress->vtbl->WaitForCompletion(progress, -1); - - rc = progress->vtbl->GetCompleted(progress, &completed); - if (NS_FAILED(rc)) - { - fprintf (stderr, "Error: GetCompleted status failed.\n"); - } - - progress->vtbl->GetResultCode(progress, &resultCode); - if (NS_FAILED(resultCode)) - { - IVirtualBoxErrorInfo *errorInfo; - PRUnichar *textUtf16; - char *text; - - progress->vtbl->GetErrorInfo(progress, &errorInfo); - errorInfo->vtbl->GetText(errorInfo, &textUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); - printf("Error: %s\n", text); - - g_pVBoxFuncs->pfnComUnallocMem(textUtf16); - g_pVBoxFuncs->pfnUtf8Free(text); - } - else - { - fprintf(stderr, "Remote session has been successfully opened.\n"); - registerCallBack(virtualBox, session, id, queue); - } - progress->vtbl->nsisupports.Release((void *)progress); - } - - /* It's important to always release resources. */ - machine->vtbl->nsisupports.Release((void *)machine); -} - -/* Main - Start the ball rolling. */ - -int main(int argc, char **argv) -{ - IVirtualBox *vbox = NULL; - ISession *session = NULL; - nsIEventQueue *queue = NULL; - PRUint32 revision = 0; - PRUnichar *versionUtf16 = NULL; - PRUnichar *homefolderUtf16 = NULL; - nsresult rc; /* Result code of various function (method) calls. */ - - printf("Starting Main\n"); - - /* - * VBoxComInitialize does all the necessary startup action and - * provides us with pointers to vbox and session handles. - * It should be matched by a call to VBoxComUninitialize(vbox) - * when done. - */ - - if (VBoxCGlueInit() != 0) - { - fprintf(stderr, "%s: FATAL: VBoxCGlueInit failed: %s\n", - argv[0], g_szVBoxErrMsg); - return EXIT_FAILURE; - } - - g_pVBoxFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &vbox, - ISESSION_IID_STR, &session); - if (vbox == NULL) - { - fprintf(stderr, "%s: FATAL: could not get vbox handle\n", argv[0]); - return EXIT_FAILURE; - } - if (session == NULL) - { - fprintf(stderr, "%s: FATAL: could not get session handle\n", argv[0]); - return EXIT_FAILURE; - } - g_pVBoxFuncs->pfnGetEventQueue(&queue); - printf("Got the event queue: %p\n", (void *)queue); - - /* - * Now ask for revision, version and home folder information of - * this vbox. Were not using fancy macros here so it - * remains easy to see how we access C++'s vtable. - */ - - printf("----------------------------------------------------\n"); - - /* 1. Revision */ - - rc = vbox->vtbl->GetRevision(vbox, &revision); - if (NS_SUCCEEDED(rc)) - { - printf("\tRevision: %u\n", revision); - } - else - { - fprintf(stderr, "%s: GetRevision() returned %08x\n", - argv[0], (unsigned)rc); - } - - /* 2. Version */ - - rc = vbox->vtbl->GetVersion(vbox, &versionUtf16); - if (NS_SUCCEEDED(rc)) - { - char *version = NULL; - g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &version); - printf("\tVersion: %s\n", version); - g_pVBoxFuncs->pfnUtf8Free(version); - g_pVBoxFuncs->pfnComUnallocMem(versionUtf16); - } - else - { - fprintf(stderr, "%s: GetVersion() returned %08x\n", - argv[0], (unsigned)rc); - } - - /* 3. Home Folder */ - - rc = vbox->vtbl->GetHomeFolder(vbox, &homefolderUtf16); - if (NS_SUCCEEDED(rc)) - { - char *homefolder = NULL; - g_pVBoxFuncs->pfnUtf16ToUtf8(homefolderUtf16, &homefolder); - printf("\tHomeFolder: %s\n", homefolder); - g_pVBoxFuncs->pfnUtf8Free(homefolder); - g_pVBoxFuncs->pfnComUnallocMem(homefolderUtf16); - } - else - { - fprintf(stderr, "%s: GetHomeFolder() returned %08x\n", - argv[0], (unsigned)rc); - } - - listVMs(vbox, session, queue); - session->vtbl->Close(session); - - printf("----------------------------------------------------\n"); - - /* - * Do as mom told us: always clean up after yourself. - */ - - g_pVBoxFuncs->pfnComUninitialize(); - VBoxCGlueTerm(); - printf("Finished Main\n"); - - return 0; -} -/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/tstXPCOMCGlue.c b/src/VBox/Main/cbinding/tstXPCOMCGlue.c deleted file mode 100644 index 751bb1ac..00000000 --- a/src/VBox/Main/cbinding/tstXPCOMCGlue.c +++ /dev/null @@ -1,381 +0,0 @@ -/* $Revision: 66862 $ */ -/** @file tstXPCOMCGlue.c - * Demonstrator program to illustrate use of C bindings of Main API. - * - * Linux only at the moment due to shared library magic in the Makefile. - */ - -/* - * Copyright (C) 2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#include "VBoxXPCOMCGlue.h" -#include -#include -#include - -static void listVMs(IVirtualBox *virtualBox, ISession *session); -static void startVM(IVirtualBox *virtualBox, ISession *session, PRUnichar *id); - -/** - * List the registered VMs. - * - * @param virtualBox ptr to IVirtualBox object - * @param session ptr to ISession object - */ -static void listVMs(IVirtualBox *virtualBox, ISession *session) -{ - nsresult rc; - IMachine **machines = NULL; - PRUint32 machineCnt = 0; - PRUint32 i; - unsigned start_id; - - /* - * Get the list of all registered VMs. - */ - - rc = virtualBox->vtbl->GetMachines(virtualBox, &machineCnt, &machines); - if (NS_FAILED(rc)) - { - fprintf(stderr, "could not get list of machines, rc=%08x\n", - (unsigned)rc); - return; - } - - if (machineCnt == 0) - { - printf("\tNo VMs\n"); - return; - } - - printf("VM List:\n\n"); - - /* - * Iterate through the collection. - */ - - for (i = 0; i < machineCnt; ++i) - { - IMachine *machine = machines[i]; - PRBool isAccessible = PR_FALSE; - - printf("\tMachine #%u\n", (unsigned)i); - - if (!machine) - { - printf("\t(skipped, NULL)\n"); - continue; - } - - machine->vtbl->GetAccessible(machine, &isAccessible); - - if (isAccessible) - { - PRUnichar *machineNameUtf16; - char *machineName; - - machine->vtbl->GetName(machine, &machineNameUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16,&machineName); - printf("\tName: %s\n", machineName); - - g_pVBoxFuncs->pfnUtf8Free(machineName); - g_pVBoxFuncs->pfnComUnallocMem(machineNameUtf16); - } - else - { - printf("\tName: \n"); - } - - - { - PRUnichar *uuidUtf16 = NULL; - char *uuidUtf8 = NULL; - - machine->vtbl->GetId(machine, &uuidUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(uuidUtf16, &uuidUtf8); - printf("\tUUID: %s\n", uuidUtf8); - - g_pVBoxFuncs->pfnUtf8Free(uuidUtf8); - g_pVBoxFuncs->pfnUtf16Free(uuidUtf16); - } - - if (isAccessible) - { - { - PRUnichar *configFile; - char *configFile1 = calloc((size_t)64, (size_t)1); - - machine->vtbl->GetSettingsFilePath(machine, &configFile); - g_pVBoxFuncs->pfnUtf16ToUtf8(configFile, &configFile1); - printf("\tConfig file: %s\n", configFile1); - - free(configFile1); - g_pVBoxFuncs->pfnComUnallocMem(configFile); - } - - { - PRUint32 memorySize; - - machine->vtbl->GetMemorySize(machine, &memorySize); - printf("\tMemory size: %uMB\n", memorySize); - } - - { - PRUnichar *typeId; - PRUnichar *osNameUtf16; - char *osName; - IGuestOSType *osType = NULL; - - machine->vtbl->GetOSTypeId(machine, &typeId); - virtualBox->vtbl->GetGuestOSType(virtualBox, typeId, &osType); - osType->vtbl->GetDescription(osType, &osNameUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(osNameUtf16,&osName); - printf("\tGuest OS: %s\n\n", osName); - - osType->vtbl->nsisupports.Release((void *)osType); - g_pVBoxFuncs->pfnUtf8Free(osName); - g_pVBoxFuncs->pfnComUnallocMem(osNameUtf16); - g_pVBoxFuncs->pfnComUnallocMem(typeId); - } - } - } - - /* - * Let the user chose a machine to start. - */ - - printf("Type Machine# to start (0 - %u) or 'quit' to do nothing: ", - (unsigned)(machineCnt - 1)); - fflush(stdout); - - if (scanf("%u", &start_id) == 1 && start_id < machineCnt) - { - IMachine *machine = machines[start_id]; - - if (machine) - { - PRUnichar *uuidUtf16 = NULL; - - machine->vtbl->GetId(machine, &uuidUtf16); - startVM(virtualBox, session, uuidUtf16); - - g_pVBoxFuncs->pfnUtf16Free(uuidUtf16); - } - } - - /* - * Don't forget to release the objects in the array. - */ - - for (i = 0; i < machineCnt; ++i) - { - IMachine *machine = machines[i]; - - if (machine) - { - machine->vtbl->nsisupports.Release((void *)machine); - } - } -} - -/** - * Start a VM. - * - * @param virtualBox ptr to IVirtualBox object - * @param session ptr to ISession object - * @param id identifies the machine to start - */ -static void startVM(IVirtualBox *virtualBox, ISession *session, PRUnichar *id) -{ - nsresult rc; - IMachine *machine = NULL; - IProgress *progress = NULL; - PRUnichar *env = NULL; - PRUnichar *sessionType; - - rc = virtualBox->vtbl->FindMachine(virtualBox, id, &machine); - - if (NS_FAILED(rc) || !machine) - { - fprintf(stderr, "Error: Couldn't get the machine handle.\n"); - return; - } - - g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType); - - rc = machine->vtbl->LaunchVMProcess(machine, - session, - sessionType, - env, - &progress - ); - - g_pVBoxFuncs->pfnUtf16Free(sessionType); - - if (NS_FAILED(rc)) - { - fprintf(stderr, "Error: OpenRemoteSession failed.\n"); - } - else - { - PRBool completed; - PRInt32 resultCode; - - printf("Waiting for the remote session to open...\n"); - progress->vtbl->WaitForCompletion(progress, -1); - - rc = progress->vtbl->GetCompleted(progress, &completed); - if (NS_FAILED(rc)) - { - fprintf (stderr, "Error: GetCompleted status failed.\n"); - } - - progress->vtbl->GetResultCode(progress, &resultCode); - if (NS_FAILED(resultCode)) - { - IVirtualBoxErrorInfo *errorInfo; - PRUnichar *textUtf16; - char *text; - - progress->vtbl->GetErrorInfo(progress, &errorInfo); - errorInfo->vtbl->GetText(errorInfo, &textUtf16); - g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); - printf("Error: %s\n", text); - - g_pVBoxFuncs->pfnComUnallocMem(textUtf16); - g_pVBoxFuncs->pfnUtf8Free(text); - } - else - { - fprintf(stderr, "Remote session has been successfully opened.\n"); - } - progress->vtbl->nsisupports.Release((void *)progress); - } - - /* It's important to always release resources. */ - machine->vtbl->nsisupports.Release((void *)machine); -} - -/* Main - Start the ball rolling. */ - -int main(int argc, char **argv) -{ - IVirtualBox *vbox = NULL; - ISession *session = NULL; - PRUint32 revision = 0; - PRUnichar *versionUtf16 = NULL; - PRUnichar *homefolderUtf16 = NULL; - nsresult rc; /* Result code of various function (method) calls. */ - - printf("Starting Main\n"); - - /* - * VBoxComInitialize does all the necessary startup action and - * provides us with pointers to vbox and session handles. - * It should be matched by a call to VBoxComUninitialize(vbox) - * when done. - */ - - if (VBoxCGlueInit() != 0) - { - fprintf(stderr, "%s: FATAL: VBoxCGlueInit failed: %s\n", - argv[0], g_szVBoxErrMsg); - return EXIT_FAILURE; - } - - g_pVBoxFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &vbox, - ISESSION_IID_STR, &session); - if (vbox == NULL) - { - fprintf(stderr, "%s: FATAL: could not get vbox handle\n", argv[0]); - return EXIT_FAILURE; - } - if (session == NULL) - { - fprintf(stderr, "%s: FATAL: could not get session handle\n", argv[0]); - return EXIT_FAILURE; - } - - /* - * Now ask for revision, version and home folder information of - * this vbox. Were not using fancy macros here so it - * remains easy to see how we access C++'s vtable. - */ - - printf("----------------------------------------------------\n"); - - /* 1. Revision */ - - rc = vbox->vtbl->GetRevision(vbox, &revision); - if (NS_SUCCEEDED(rc)) - { - printf("\tRevision: %u\n", revision); - } - else - { - fprintf(stderr, "%s: GetRevision() returned %08x\n", - argv[0], (unsigned)rc); - } - - /* 2. Version */ - - rc = vbox->vtbl->GetVersion(vbox, &versionUtf16); - if (NS_SUCCEEDED(rc)) - { - char *version = NULL; - g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &version); - printf("\tVersion: %s\n", version); - g_pVBoxFuncs->pfnUtf8Free(version); - g_pVBoxFuncs->pfnComUnallocMem(versionUtf16); - } - else - { - fprintf(stderr, "%s: GetVersion() returned %08x\n", - argv[0], (unsigned)rc); - } - - /* 3. Home Folder */ - - rc = vbox->vtbl->GetHomeFolder(vbox, &homefolderUtf16); - if (NS_SUCCEEDED(rc)) - { - char *homefolder = NULL; - g_pVBoxFuncs->pfnUtf16ToUtf8(homefolderUtf16, &homefolder); - printf("\tHomeFolder: %s\n", homefolder); - g_pVBoxFuncs->pfnUtf8Free(homefolder); - g_pVBoxFuncs->pfnComUnallocMem(homefolderUtf16); - } - else - { - fprintf(stderr, "%s: GetHomeFolder() returned %08x\n", - argv[0], (unsigned)rc); - } - - listVMs(vbox, session); - session->vtbl->UnlockMachine(session); - - printf("----------------------------------------------------\n"); - - /* - * Do as mom told us: always clean up after yourself. - */ - - g_pVBoxFuncs->pfnComUninitialize(); - VBoxCGlueTerm(); - printf("Finished Main\n"); - - return 0; -} -/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/xpcidl.xsl b/src/VBox/Main/cbinding/xpcidl.xsl deleted file mode 100644 index c1220c70..00000000 --- a/src/VBox/Main/cbinding/xpcidl.xsl +++ /dev/null @@ -1,2107 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/* - * DO NOT EDIT! This is a generated file. - * - * XPCOM IDL (XPIDL) definition for VirtualBox Main API (COM interfaces) - * generated from XIDL (XML interface definition). - * - * Source : src/VBox/Main/idl/VirtualBox.xidl - * Generator : src/VBox/Main/idl/xpcidl.xsl - * - * This file contains portions from the following Mozilla XPCOM files: - * xpcom/include/xpcom/nsID.h - * xpcom/include/nsIException.h - * xpcom/include/nsprpub/prtypes.h - * xpcom/include/xpcom/nsISupportsBase.h - * - * These files were originally triple-licensed (MPL/GPL2/LGPL2.1). Oracle - * elects to distribute this derived work under the LGPL2.1 only. - */ - -/* - * Copyright (C) 2008-2012 Oracle Corporation - * - * This file is part of a free software library; you can redistribute - * it and/or modify it under the terms of the GNU Lesser General - * Public License version 2.1 as published by the Free Software - * Foundation and shipped in the "COPYING" file with this library. - * The library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY of any kind. - * - * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if - * any license choice other than GPL or LGPL is available it will - * apply instead, Oracle elects to use only the Lesser General Public - * License version 2.1 (LGPLv2) at this time for any software where - * a choice of LGPL license versions is made available with the - * language indicating that LGPLv2 or any later version may be used, - * or where a choice of which version of the LGPL is applied is - * otherwise unspecified. - */ - -#ifndef ___VirtualBox_CXPCOM_h -#define ___VirtualBox_CXPCOM_h - -#ifdef __cplusplus -# include "VirtualBox_XPCOM.h" -#else /* !__cplusplus */ - -#include <stddef.h> -#include "wchar.h" - -#if defined(WIN32) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) __declspec(dllimport) __type -#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(XP_BEOS) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) extern __declspec(dllexport) __type -#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(WIN16) - -#define PR_CALLBACK_DECL __cdecl - -#if defined(_WINDLL) -#define PR_EXPORT(__type) extern __type _cdecl _export _loadds -#define PR_IMPORT(__type) extern __type _cdecl _export _loadds -#define PR_EXPORT_DATA(__type) extern __type _export -#define PR_IMPORT_DATA(__type) extern __type _export - -#define PR_EXTERN(__type) extern __type _cdecl _export _loadds -#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds -#define PR_EXTERN_DATA(__type) extern __type _export -#define PR_IMPLEMENT_DATA(__type) __type _export - -#define PR_CALLBACK __cdecl __loadds -#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK - -#else /* this must be .EXE */ -#define PR_EXPORT(__type) extern __type _cdecl _export -#define PR_IMPORT(__type) extern __type _cdecl _export -#define PR_EXPORT_DATA(__type) extern __type _export -#define PR_IMPORT_DATA(__type) extern __type _export - -#define PR_EXTERN(__type) extern __type _cdecl _export -#define PR_IMPLEMENT(__type) __type _cdecl _export -#define PR_EXTERN_DATA(__type) extern __type _export -#define PR_IMPLEMENT_DATA(__type) __type _export - -#define PR_CALLBACK __cdecl __loadds -#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK -#endif /* _WINDLL */ - -#elif defined(XP_MAC) - -#define PR_EXPORT(__type) extern __declspec(export) __type -#define PR_EXPORT_DATA(__type) extern __declspec(export) __type -#define PR_IMPORT(__type) extern __declspec(export) __type -#define PR_IMPORT_DATA(__type) extern __declspec(export) __type - -#define PR_EXTERN(__type) extern __declspec(export) __type -#define PR_IMPLEMENT(__type) __declspec(export) __type -#define PR_EXTERN_DATA(__type) extern __declspec(export) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(XP_OS2) && defined(__declspec) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) __declspec(dllimport) __type -#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(XP_OS2_VACPP) - -#define PR_EXPORT(__type) extern __type -#define PR_EXPORT_DATA(__type) extern __type -#define PR_IMPORT(__type) extern __type -#define PR_IMPORT_DATA(__type) extern __type - -#define PR_EXTERN(__type) extern __type -#define PR_IMPLEMENT(__type) __type -#define PR_EXTERN_DATA(__type) extern __type -#define PR_IMPLEMENT_DATA(__type) __type -#define PR_CALLBACK _Optlink -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK - -#else /* Unix */ - -# ifdef VBOX_HAVE_VISIBILITY_HIDDEN -# define PR_EXPORT(__type) __attribute__((visibility("default"))) extern __type -# define PR_EXPORT_DATA(__type) __attribute__((visibility("default"))) extern __type -# define PR_IMPORT(__type) extern __type -# define PR_IMPORT_DATA(__type) extern __type -# define PR_EXTERN(__type) __attribute__((visibility("default"))) extern __type -# define PR_IMPLEMENT(__type) __attribute__((visibility("default"))) __type -# define PR_EXTERN_DATA(__type) __attribute__((visibility("default"))) extern __type -# define PR_IMPLEMENT_DATA(__type) __attribute__((visibility("default"))) __type -# define PR_CALLBACK -# define PR_CALLBACK_DECL -# define PR_STATIC_CALLBACK(__x) static __x -# else -# define PR_EXPORT(__type) extern __type -# define PR_EXPORT_DATA(__type) extern __type -# define PR_IMPORT(__type) extern __type -# define PR_IMPORT_DATA(__type) extern __type -# define PR_EXTERN(__type) extern __type -# define PR_IMPLEMENT(__type) __type -# define PR_EXTERN_DATA(__type) extern __type -# define PR_IMPLEMENT_DATA(__type) __type -# define PR_CALLBACK -# define PR_CALLBACK_DECL -# define PR_STATIC_CALLBACK(__x) static __x -# endif -#endif - -#if defined(_NSPR_BUILD_) -#define NSPR_API(__type) PR_EXPORT(__type) -#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) -#else -#define NSPR_API(__type) PR_IMPORT(__type) -#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) -#endif - -typedef unsigned char PRUint8; -#if (defined(HPUX) && defined(__cplusplus) \ - && !defined(__GNUC__) && __cplusplus < 199707L) \ - || (defined(SCO) && defined(__cplusplus) \ - && !defined(__GNUC__) && __cplusplus == 1L) -typedef char PRInt8; -#else -typedef signed char PRInt8; -#endif - -#define PR_INT8_MAX 127 -#define PR_INT8_MIN (-128) -#define PR_UINT8_MAX 255U - -typedef unsigned short PRUint16; -typedef short PRInt16; - -#define PR_INT16_MAX 32767 -#define PR_INT16_MIN (-32768) -#define PR_UINT16_MAX 65535U - -typedef unsigned int PRUint32; -typedef int PRInt32; -#define PR_INT32(x) x -#define PR_UINT32(x) x ## U - -#define PR_INT32_MAX PR_INT32(2147483647) -#define PR_INT32_MIN (-PR_INT32_MAX - 1) -#define PR_UINT32_MAX PR_UINT32(4294967295) - -typedef long PRInt64; -typedef unsigned long PRUint64; -typedef int PRIntn; -typedef unsigned int PRUintn; - -typedef double PRFloat64; -typedef size_t PRSize; - -typedef ptrdiff_t PRPtrdiff; - -typedef unsigned long PRUptrdiff; - -typedef PRIntn PRBool; - -#define PR_TRUE 1 -#define PR_FALSE 0 - -typedef PRUint8 PRPackedBool; - -/* -** Status code used by some routines that have a single point of failure or -** special status return. -*/ -typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; - -#ifndef __PRUNICHAR__ -#define __PRUNICHAR__ -#if defined(WIN32) || defined(XP_MAC) -typedef wchar_t PRUnichar; -#else -typedef PRUint16 PRUnichar; -#endif -#endif - -typedef long PRWord; -typedef unsigned long PRUword; - -#define nsnull 0 -typedef PRUint32 nsresult; - -#if defined(__GNUC__) && (__GNUC__ > 2) -#define NS_LIKELY(x) (__builtin_expect((x), 1)) -#define NS_UNLIKELY(x) (__builtin_expect((x), 0)) -#else -#define NS_LIKELY(x) (x) -#define NS_UNLIKELY(x) (x) -#endif - -#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) -#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) - -#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -# define PR_IntervalNow VBoxNsprPR_IntervalNow -# define PR_TicksPerSecond VBoxNsprPR_TicksPerSecond -# define PR_SecondsToInterval VBoxNsprPR_SecondsToInterval -# define PR_MillisecondsToInterval VBoxNsprPR_MillisecondsToInterval -# define PR_MicrosecondsToInterval VBoxNsprPR_MicrosecondsToInterval -# define PR_IntervalToSeconds VBoxNsprPR_IntervalToSeconds -# define PR_IntervalToMilliseconds VBoxNsprPR_IntervalToMilliseconds -# define PR_IntervalToMicroseconds VBoxNsprPR_IntervalToMicroseconds -# define PR_EnterMonitor VBoxNsprPR_EnterMonitor -# define PR_ExitMonitor VBoxNsprPR_ExitMonitor -# define PR_Notify VBoxNsprPR_Notify -# define PR_NotifyAll VBoxNsprPR_NotifyAll -# define PR_Wait VBoxNsprPR_Wait -# define PR_NewMonitor VBoxNsprPR_NewMonitor -# define PR_DestroyMonitor VBoxNsprPR_DestroyMonitor -#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ - -typedef PRUint32 PRIntervalTime; - -#define PR_INTERVAL_MIN 1000UL -#define PR_INTERVAL_MAX 100000UL -#define PR_INTERVAL_NO_WAIT 0UL -#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL - -NSPR_API(PRIntervalTime) PR_IntervalNow(void); -NSPR_API(PRUint32) PR_TicksPerSecond(void); -NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); -NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); -NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); -NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); -NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); -NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); - -typedef struct PRMonitor PRMonitor; - -NSPR_API(PRMonitor*) PR_NewMonitor(void); -NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); -NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); -NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); -NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); -NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); -NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); - -#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -# define PR_CreateThread VBoxNsprPR_CreateThread -# define PR_JoinThread VBoxNsprPR_JoinThread -# define PR_Sleep VBoxNsprPR_Sleep -# define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread -# define PR_GetThreadState VBoxNsprPR_GetThreadState -# define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate -# define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate -# define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex -# define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority -# define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority -# define PR_Interrupt VBoxNsprPR_Interrupt -# define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt -# define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt -# define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt -# define PR_GetThreadScope VBoxNsprPR_GetThreadScope -# define PR_GetThreadType VBoxNsprPR_GetThreadType -#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ - -typedef struct PRThread PRThread; -typedef struct PRThreadStack PRThreadStack; - -typedef enum PRThreadType { - PR_USER_THREAD, - PR_SYSTEM_THREAD -} PRThreadType; - -typedef enum PRThreadScope { - PR_LOCAL_THREAD, - PR_GLOBAL_THREAD, - PR_GLOBAL_BOUND_THREAD -} PRThreadScope; - -typedef enum PRThreadState { - PR_JOINABLE_THREAD, - PR_UNJOINABLE_THREAD -} PRThreadState; - -typedef enum PRThreadPriority -{ - PR_PRIORITY_FIRST = 0, /* just a placeholder */ - PR_PRIORITY_LOW = 0, /* the lowest possible priority */ - PR_PRIORITY_NORMAL = 1, /* most common expected priority */ - PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ - PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ - PR_PRIORITY_LAST = 3 /* this is just a placeholder */ -} PRThreadPriority; - -NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, - void (PR_CALLBACK *start)(void *arg), - void *arg, - PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state, - PRUint32 stackSize); -NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); -NSPR_API(PRThread*) PR_GetCurrentThread(void); -#ifndef NO_NSPR_10_SUPPORT -#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ -#endif /* NO_NSPR_10_SUPPORT */ -NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); -NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); - -typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); - -NSPR_API(PRStatus) PR_NewThreadPrivateIndex( - PRUintn *newIndex, PRThreadPrivateDTOR destructor); -NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); -NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); -NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); -NSPR_API(void) PR_ClearInterrupt(void); -NSPR_API(void) PR_BlockInterrupt(void); -NSPR_API(void) PR_UnblockInterrupt(void); -NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); -NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); -NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); -NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); - -#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -# define PR_DestroyLock VBoxNsprPR_DestroyLock -# define PR_Lock VBoxNsprPR_Lock -# define PR_NewLock VBoxNsprPR_NewLock -# define PR_Unlock VBoxNsprPR_Unlock -#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ - -typedef struct PRLock PRLock; - -NSPR_API(PRLock*) PR_NewLock(void); -NSPR_API(void) PR_DestroyLock(PRLock *lock); -NSPR_API(void) PR_Lock(PRLock *lock); -NSPR_API(PRStatus) PR_Unlock(PRLock *lock); - -#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -# define PR_NewCondVar VBoxNsprPR_NewCondVar -# define PR_DestroyCondVar VBoxNsprPR_DestroyCondVar -# define PR_WaitCondVar VBoxNsprPR_WaitCondVar -# define PR_NotifyCondVar VBoxNsprPR_NotifyCondVar -# define PR_NotifyAllCondVar VBoxNsprPR_NotifyAllCondVar -#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ - -typedef struct PRCondVar PRCondVar; - -NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); -NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); -NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); -NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); -NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); - -typedef struct PRCListStr PRCList; - -struct PRCListStr { - PRCList *next; - PRCList *prev; -}; - -#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -# define PL_DestroyEvent VBoxNsplPL_DestroyEvent -# define PL_HandleEvent VBoxNsplPL_HandleEvent -# define PL_InitEvent VBoxNsplPL_InitEvent -# define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue -# define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue -# define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue -# define PL_DequeueEvent VBoxNsplPL_DequeueEvent -# define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue -# define PL_EventAvailable VBoxNsplPL_EventAvailable -# define PL_EventLoop VBoxNsplPL_EventLoop -# define PL_GetEvent VBoxNsplPL_GetEvent -# define PL_GetEventOwner VBoxNsplPL_GetEventOwner -# define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor -# define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD -# define PL_MapEvents VBoxNsplPL_MapEvents -# define PL_PostEvent VBoxNsplPL_PostEvent -# define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent -# define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID -# define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents -# define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc -# define PL_RevokeEvents VBoxNsplPL_RevokeEvents -# define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc -# define PL_WaitForEvent VBoxNsplPL_WaitForEvent -# define PL_IsQueueNative VBoxNsplPL_IsQueueNative -# define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread -# define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint -#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ - -typedef struct PLEvent PLEvent; -typedef struct PLEventQueue PLEventQueue; - -PR_EXTERN(PLEventQueue*) -PL_CreateEventQueue(const char* name, PRThread* handlerThread); -PR_EXTERN(PLEventQueue *) - PL_CreateNativeEventQueue( - const char *name, - PRThread *handlerThread - ); -PR_EXTERN(PLEventQueue *) - PL_CreateMonitoredEventQueue( - const char *name, - PRThread *handlerThread - ); -PR_EXTERN(void) -PL_DestroyEventQueue(PLEventQueue* self); -PR_EXTERN(PRMonitor*) -PL_GetEventQueueMonitor(PLEventQueue* self); - -#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ - PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) - -#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ - PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) - -PR_EXTERN(PRStatus) PL_PostEvent(PLEventQueue* self, PLEvent* event); -PR_EXTERN(void*) PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); -PR_EXTERN(PLEvent*) PL_GetEvent(PLEventQueue* self); -PR_EXTERN(PRBool) PL_EventAvailable(PLEventQueue* self); - -typedef void (PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); - -PR_EXTERN(void) PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); -PR_EXTERN(void) PL_RevokeEvents(PLEventQueue* self, void* owner); -PR_EXTERN(void) PL_ProcessPendingEvents(PLEventQueue* self); -PR_EXTERN(PLEvent*) PL_WaitForEvent(PLEventQueue* self); -PR_EXTERN(void) PL_EventLoop(PLEventQueue* self); -PR_EXTERN(PRInt32) PL_GetEventQueueSelectFD(PLEventQueue* self); -PR_EXTERN(PRBool) PL_IsQueueOnCurrentThread( PLEventQueue *queue ); -PR_EXTERN(PRBool) PL_IsQueueNative(PLEventQueue *queue); - -typedef void* (PR_CALLBACK *PLHandleEventProc)(PLEvent* self); -typedef void (PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); -PR_EXTERN(void) -PL_InitEvent(PLEvent* self, void* owner, - PLHandleEventProc handler, - PLDestroyEventProc destructor); -PR_EXTERN(void*) PL_GetEventOwner(PLEvent* self); -PR_EXTERN(void) PL_HandleEvent(PLEvent* self); -PR_EXTERN(void) PL_DestroyEvent(PLEvent* self); -PR_EXTERN(void) PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); -PR_EXTERN(void) PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); - -struct PLEvent { - PRCList link; - PLHandleEventProc handler; - PLDestroyEventProc destructor; - void* owner; - void* synchronousResult; - PRLock* lock; - PRCondVar* condVar; - PRBool handled; -#ifdef PL_POST_TIMINGS - PRIntervalTime postTime; -#endif -#ifdef XP_UNIX - unsigned long id; -#endif /* XP_UNIX */ - /* other fields follow... */ -}; - -#if defined(XP_WIN) || defined(XP_OS2) - -PR_EXTERN(HWND) - PL_GetNativeEventReceiverWindow( - PLEventQueue *eqp - ); -#endif /* XP_WIN || XP_OS2 */ - -#ifdef XP_UNIX - -PR_EXTERN(PRInt32) -PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); - -typedef unsigned long (PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); - -PR_EXTERN(void) -PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, - void *aClosure); -PR_EXTERN(void) PL_UnregisterEventIDFunc(PLEventQueue *aSelf); - -#endif /* XP_UNIX */ - -/* Standard "it worked" return value */ -#define NS_OK 0 - -#define NS_ERROR_BASE ((nsresult) 0xC1F30000) - -/* Returned when an instance is not initialized */ -#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) - -/* Returned when an instance is already initialized */ -#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) - -/* Returned by a not implemented function */ -#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) - -/* Returned when a given interface is not supported. */ -#define NS_NOINTERFACE ((nsresult) 0x80004002L) -#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE - -#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) -#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER - -/* Returned when a function aborts */ -#define NS_ERROR_ABORT ((nsresult) 0x80004004L) - -/* Returned when a function fails */ -#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) - -/* Returned when an unexpected error occurs */ -#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) - -/* Returned when a memory allocation fails */ -#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) - -/* Returned when an illegal value is passed */ -#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) -#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE - -/* Returned when a class doesn't allow aggregation */ -#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) - -/* Returned when an operation can't complete due to an unavailable resource */ -#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) - -/* Returned when a class is not registered */ -#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) - -/* Returned when a class cannot be registered, but may be tried again later */ -#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) - -/* Returned when a dynamically loaded factory couldn't be found */ -#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) - -/* Returned when a factory doesn't support signatures */ -#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ - (NS_ERROR_BASE + 0x101) - -/* Returned when a factory already is registered */ -#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) - - -/** - * An "interface id" which can be used to uniquely identify a given - * interface. - * A "unique identifier". This is modeled after OSF DCE UUIDs. - */ - -struct nsID { - PRUint32 m0; - PRUint16 m1; - PRUint16 m2; - PRUint8 m3[8]; -}; - -typedef struct nsID nsID; -typedef nsID nsIID; - -struct nsISupports; /* forward declaration */ -struct nsIStackFrame; /* forward declaration */ -struct nsIException; /* forward declaration */ -typedef struct nsISupports nsISupports; /* forward declaration */ -typedef struct nsIStackFrame nsIStackFrame; /* forward declaration */ -typedef struct nsIException nsIException; /* forward declaration */ - -/** - * IID for the nsISupports interface - * {00000000-0000-0000-c000-000000000046} - * - * To maintain binary compatibility with COM's IUnknown, we define the IID - * of nsISupports to be the same as that of COM's IUnknown. - */ -#define NS_ISUPPORTS_IID \ - { 0x00000000, 0x0000, 0x0000, \ - {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } - -/** - * Reference count values - * - * This is the return type for AddRef() and Release() in nsISupports. - * IUnknown of COM returns an unsigned long from equivalent functions. - * The following ifdef exists to maintain binary compatibility with - * IUnknown. - */ - -/** - * Basic component object model interface. Objects which implement - * this interface support runtime interface discovery (QueryInterface) - * and a reference counted memory model (AddRef/Release). This is - * modelled after the win32 IUnknown API. - */ -struct nsISupports_vtbl { - - /** - * @name Methods - */ - - /** - * A run time mechanism for interface discovery. - * @param aIID [in] A requested interface IID - * @param aInstancePtr [out] A pointer to an interface pointer to - * receive the result. - * @return NS_OK if the interface is supported by the associated - * instance, NS_NOINTERFACE if it is not. - * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. - */ - nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); - /** - * Increases the reference count for this interface. - * The associated instance will not be deleted unless - * the reference count is returned to zero. - * - * @return The resulting reference count. - */ - nsresult (*AddRef)(nsISupports *pThis); - - /** - * Decreases the reference count for this interface. - * Generally, if the reference count returns to zero, - * the associated instance is deleted. - * - * @return The resulting reference count. - */ - nsresult (*Release)(nsISupports *pThis); - -}; - -struct nsISupports { - struct nsISupports_vtbl *vtbl; -}; - -/* starting interface: nsIException */ -#define NS_IEXCEPTION_IID_STR "f3a8d3b4-c424-4edc-8bf6-8974c983ba78" - -#define NS_IEXCEPTION_IID \ - {0xf3a8d3b4, 0xc424, 0x4edc, \ - { 0x8b, 0xf6, 0x89, 0x74, 0xc9, 0x83, 0xba, 0x78 }} - -struct nsIException_vtbl { - - /* Methods from the Class nsISupports */ - struct nsISupports_vtbl nsisupports; - - /* readonly attribute string message; */ - nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); - - /* readonly attribute nsresult (*result; */ - nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); - - /* readonly attribute string name; */ - nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); - - /* readonly attribute string filename; */ - nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); - - /* readonly attribute PRUint32 lineNumber; */ - nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); - - /* readonly attribute PRUint32 columnNumber; */ - nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); - - /* readonly attribute nsIStackFrame location; */ - nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); - - /* readonly attribute nsIException inner; */ - nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); - - /* readonly attribute nsISupports data; */ - nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); - - /* string toString (); */ - nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); -}; - -struct nsIException { - struct nsIException_vtbl *vtbl; -}; - -/* starting interface: nsIStackFrame */ -#define NS_ISTACKFRAME_IID_STR "91d82105-7c62-4f8b-9779-154277c0ee90" - -#define NS_ISTACKFRAME_IID \ - {0x91d82105, 0x7c62, 0x4f8b, \ - { 0x97, 0x79, 0x15, 0x42, 0x77, 0xc0, 0xee, 0x90 }} - -struct nsIStackFrame_vtbl { - - /* Methods from the Class nsISupports */ - struct nsISupports_vtbl nsisupports; - - /* readonly attribute PRUint32 language; */ - nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); - - /* readonly attribute string languageName; */ - nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); - - /* readonly attribute string filename; */ - nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); - - /* readonly attribute string name; */ - nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); - - /* readonly attribute PRInt32 lineNumber; */ - nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); - - /* readonly attribute string sourceLine; */ - nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); - - /* readonly attribute nsIStackFrame caller; */ - nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); - - /* string toString (); */ - nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); -}; - -struct nsIStackFrame { - struct nsIStackFrame_vtbl *vtbl; -}; - -/* starting interface: nsIEventTarget */ -#define NS_IEVENTTARGET_IID_STR "ea99ad5b-cc67-4efb-97c9-2ef620a59f2a" - -#define NS_IEVENTTARGET_IID \ - {0xea99ad5b, 0xcc67, 0x4efb, \ - { 0x97, 0xc9, 0x2e, 0xf6, 0x20, 0xa5, 0x9f, 0x2a }} - -struct nsIEventTarget; -typedef struct nsIEventTarget nsIEventTarget; - -struct nsIEventTarget_vtbl { - - struct nsISupports_vtbl nsisupports; - - nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); - - nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); - -}; - -struct nsIEventTarget { - struct nsIEventTarget_vtbl *vtbl; -}; - -/* starting interface: nsIEventQueue */ -#define NS_IEVENTQUEUE_IID_STR "176afb41-00a4-11d3-9f2a-00400553eef0" - -#define NS_IEVENTQUEUE_IID \ - {0x176afb41, 0x00a4, 0x11d3, \ - { 0x9f, 0x2a, 0x00, 0x40, 0x05, 0x53, 0xee, 0xf0 }} - -struct nsIEventQueue; -typedef struct nsIEventQueue nsIEventQueue; - -struct nsIEventQueue_vtbl { - - struct nsIEventTarget_vtbl nsieventtarget; - - nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); - - nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); - - nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); - - nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); - - nsresult (*EventLoop)(nsIEventQueue *pThis); - - nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); - - nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); - - nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); - - nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); - - PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); - - nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); - - nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); - - nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); - - nsresult (*EnterMonitor)(nsIEventQueue *pThis); - - nsresult (*ExitMonitor)(nsIEventQueue *pThis); - - nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); - - nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); - - nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); - - nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); - -}; - -struct nsIEventQueue { - struct nsIEventQueue_vtbl *vtbl; -}; - - - - -#endif /* !__cplusplus */ - -#ifdef IN_VBOXXPCOMC -# define VBOXXPCOMC_DECL(type) PR_EXPORT(type) -#else -# define VBOXXPCOMC_DECL(type) PR_IMPORT(type) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * Function table for dynamic linking. - * Use VBoxGetFunctions() to obtain the pointer to it. - */ -typedef struct VBOXXPCOMC -{ - /** The size of the structure. */ - unsigned cb; - /** The structure version. */ - unsigned uVersion; - - unsigned int (*pfnGetVersion)(void); - - void (*pfnComInitialize)(const char *pszVirtualBoxIID, - IVirtualBox **ppVirtualBox, - const char *pszSessionIID, - ISession **ppSession); - void (*pfnComUninitialize)(void); - - void (*pfnComUnallocMem)(void *pv); - void (*pfnUtf16Free)(PRUnichar *pwszString); - void (*pfnUtf8Free)(char *pszString); - - int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString); - int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString); - - void (*pfnGetEventQueue)(nsIEventQueue **eventQueue); - - /** Tail version, same as uVersion. */ - unsigned uEndVersion; -} VBOXXPCOMC; -/** Pointer to a const VBoxXPCOMC function table. */ -typedef VBOXXPCOMC const *PCVBOXXPCOM; - -/** The current interface version. - * For use with VBoxGetXPCOMCFunctions and to be found in - * VBOXXPCOMC::uVersion. */ -#define VBOX_XPCOMC_VERSION 0x00020000U - -VBOXXPCOMC_DECL(PCVBOXXPCOM) VBoxGetXPCOMCFunctions(unsigned uVersion); -/** Typedef for VBoxGetXPCOMCFunctions. */ -typedef PCVBOXXPCOM (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion); - -/** The symbol name of VBoxGetXPCOMCFunctions. */ -#if defined(__OS2__) -# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "_VBoxGetXPCOMCFunctions" -#else -# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "VBoxGetXPCOMCFunctions" -#endif - - -#ifdef __cplusplus -} -#endif - -#endif /* !___VirtualBox_CXPCOM_h */ - - - - - - - - - - - - @if attributes are not currently allowed because xpidl lacks - support for #ifdef and stuff. - - #if - - - - - #endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct - - ; - - - - - - typedef struct - - - - ; - - - - - - /* Start of struct - - Declaration */ - #define - - - - - - #define - - - - _IID { \ - 0x - , 0x - , 0x - , \ - { 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - } \ } - struct - - _vtbl { - - - struct nsISupports_vtbl nsisupports; - struct nsISupports_vtbl nsisupports; - struct nsIException_vtbl nsiexception; - - struct - - _vtbl - - - - ; - - - - - - - - - - - }; - - struct - - { struct - - _vtbl *vtbl; }; - /* End of struct - - Declaration */ - - - - - - - - - - - - - - nsresult (*Get - - - - )( - - *pThis, - - PRUint32 * - - Size, - - - ** - - ); - - - nsresult (*Set - - - - )( - - *pThis, - - PRUint32 - - Size, - - - * - - ); - - - - - - - nsresult (*Get - - - - )( - - *pThis, - - * - - ); - - - - - - nsresult (*Get - - - - )( - - *pThis, - - * - - ); - nsresult (*Set - - - - )( - - *pThis, - - - - ); - - - - - - - - - - - - - - - - #define COM_FORWARD_ - - _GETTER_ - - - - _TO(smth) NS_IMETHOD Get - - - - ( - - PRUint32 * a - - - - Size, - - - - * - - * a - - - - ) { return smth Get - - - - ( - - a - - - - Size, - - a - - - - ); } - - #define COM_FORWARD_ - - _GETTER_ - - - - _TO_OBJ(obj) COM_FORWARD_ - - _GETTER_ - - - - _TO ((obj)->) - - #define COM_FORWARD_ - - _GETTER_ - - - - _TO_BASE(base) COM_FORWARD_ - - _GETTER_ - - - - _TO (base::) - - - - #define COM_FORWARD_ - - _SETTER_ - - - - _TO(smth) NS_IMETHOD Set - - - - ( - - PRUint32 a - - - - Size, - - - const - - - - * - - a - - - - ) { return smth Set - - - - (a - - - - ); } - - #define COM_FORWARD_ - - _SETTER_ - - - - _TO_OBJ(obj) COM_FORWARD_ - - _SETTER_ - - - - _TO ((obj)->) - - #define COM_FORWARD_ - - _SETTER_ - - - - _TO_BASE(base) COM_FORWARD_ - - _SETTER_ - - - - _TO (base::) - - - - - - - - - - - - - - nsresult (* - - - - - )( - - - *pThis, - - - - , - - - - ); - - - )( - - *pThis ); - - - - - - - - - - - - #define COM_FORWARD_ - - _ - - - - _TO(smth) NS_IMETHOD - - - - - - ( - - - , - - - ) { return smth - - - - ( - - - a - - - - Size+++, - - a - - - - , - - - a - - - - Size, - - a - - - - ); } - - - () { return smth - - - - (); } - - - - - #define COM_FORWARD_ - - _ - - - - _TO_OBJ(obj) COM_FORWARD_ - - _ - - - - _TO ((obj)->) - - #define COM_FORWARD_ - - _ - - - - _TO_BASE(base) COM_FORWARD_ - - _ - - - - _TO (base::) - - - - - - - - - - - - - - - - - #define NS_ - - - - _CID { \ - 0x - , 0x - , 0x - , \ - { 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - } \ } - #define NS_ - - - - - _CONTRACTID "@ - - / - - ;1" - - /* for compatibility with Win32 */ - #define CLSID_ - - (nsCID) NS_ - - - - _CID - - - - - - - /* Start of enum - - Declaration */ - #define - - - - - - #define - - - - _IID { \ - 0x - , 0x - , 0x - , \ - { 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - , 0x - } \ } - enum - - { - - - - - _ - = - - , - - - - }; - /* End of enum - - Declaration */ - - - - - - - - - - - - PRUint32 - - Size, - - - PRUint32 * - - Size, - - - PRUint32 * - - Size, - - - PRUint32 - - Size, - - - - - - - - * - - - - - * - - * - - - - ** - - - - * - - - - - - - - - - - - - - - * - - - - * - - - - - - - - - - - - - - - PRUint32 - - * - - a - - - - Size, - - - - * - - - * - - a - - - - - - - - - - - - - - - - - - - booleanPtr - octetPtr - shortPtr - ushortPtr - longPtr - llongPtr - ulongPtr - ullongPtr - - - - attribute 'mod= - - ' cannot be used with type - - - - - - - - - - wstring - - - - attribute 'mod= - - ' cannot be used with type - - - - - - - - - - of attribute 'mod' is invalid! - - - - - - - - - nsresult - boolean - octet - short - unsigned short - long - long long - unsigned long - unsigned long long - char - wchar - string - wstring - - - - - - - nsIDPtr - - - - - : Non-readonly uuid attributes are not supported! - - - - - - - - nsIDRef - - - nsIDPtr - - - - - - - nsISupports - - - - - PRUint32 - - - - - - - - - Unknown parameter type: - - - - - - - - - - - - - - - - - - - - - - - PRBool * - PRUint8 * - PRInt16 * - PRUint16 * - PRInt32 * - PRInt64 * - PRUint32 * - PRUint64 * - - - - attribute 'mod= - - ' cannot be used with type - - - - - - - - - - PRUnichar * - - - - attribute 'mod= - - ' cannot be used with type - - - - - - - - - - - - nsresult - PRBool - PRUint8 - PRInt16 - PRUint16 - PRInt32 - PRInt64 - PRUint32 - PRUint64 - char - PRUnichar - - char * - PRUnichar * - - - - - - - nsID * - - - - - - - const nsID * - - - nsID * - - - - - - - nsISupports * - - - - - PRUint32 - - - - - * - - - - - - - - - - - diff --git a/src/VBox/Main/glue/AutoLock.cpp b/src/VBox/Main/glue/AutoLock.cpp index bf1d4c9a..fa909b9c 100644 --- a/src/VBox/Main/glue/AutoLock.cpp +++ b/src/VBox/Main/glue/AutoLock.cpp @@ -1,10 +1,10 @@ +/* $Id: AutoLock.cpp $ */ /** @file - * - * Automatic locks, implementation + * Automatic locks, implementation. */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -15,6 +15,16 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define GLUE_USE_CRITSECTRW + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ #include #include #include @@ -38,6 +48,7 @@ #include #include + namespace util { @@ -133,11 +144,15 @@ struct RWLockHandle::Data Data() { } - RTSEMRW sem; - VBoxLockingClass lockClass; +#ifdef GLUE_USE_CRITSECTRW + mutable RTCRITSECTRW CritSect; +#else + RTSEMRW sem; +#endif + VBoxLockingClass lockClass; #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION - com::Utf8Str strDescription; + com::Utf8Str strDescription; #endif }; @@ -146,64 +161,110 @@ RWLockHandle::RWLockHandle(VBoxLockingClass lockClass) m = new Data(); m->lockClass = lockClass; - #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION m->strDescription = com::Utf8StrFmt("r/w %RCv", this); - int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL); +#endif + +#ifdef GLUE_USE_CRITSECTRW +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTCritSectRwInitEx(&m->CritSect, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL); +# else + int vrc = RTCritSectRwInitEx(&m->CritSect, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL); +# endif #else +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL); +# else int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL); +# endif #endif AssertRC(vrc); } /*virtual*/ RWLockHandle::~RWLockHandle() { +#ifdef GLUE_USE_CRITSECTRW + RTCritSectRwDelete(&m->CritSect); +#else RTSemRWDestroy(m->sem); +#endif delete m; } /*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const { +#ifdef GLUE_USE_CRITSECTRW + return RTCritSectRwIsWriteOwner(&m->CritSect); +#else return RTSemRWIsWriteOwner(m->sem); +#endif } /*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL) { -#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION - int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +#ifdef GLUE_USE_CRITSECTRW +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTCritSectRwEnterExclDebug(&m->CritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +# else + int vrc = RTCritSectRwEnterExcl(&m->CritSect); +# endif #else +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +# else int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT); +# endif #endif AssertRC(vrc); } /*virtual*/ void RWLockHandle::unlockWrite() { +#ifdef GLUE_USE_CRITSECTRW + int vrc = RTCritSectRwLeaveExcl(&m->CritSect); +#else int vrc = RTSemRWReleaseWrite(m->sem); +#endif AssertRC(vrc); } /*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL) { -#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION - int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +#ifdef GLUE_USE_CRITSECTRW +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTCritSectRwEnterSharedDebug(&m->CritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +# else + int vrc = RTCritSectRwEnterShared(&m->CritSect); +# endif #else +# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS); +# else int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT); +# endif #endif AssertRC(vrc); } /*virtual*/ void RWLockHandle::unlockRead() { +#ifdef GLUE_USE_CRITSECTRW + int vrc = RTCritSectRwLeaveShared(&m->CritSect); +#else int vrc = RTSemRWReleaseRead(m->sem); +#endif AssertRC(vrc); } /*virtual*/ uint32_t RWLockHandle::writeLockLevel() const { /* Note! This does not include read recursions done by the writer! */ +#ifdef GLUE_USE_CRITSECTRW + return RTCritSectRwGetWriteRecursion(&m->CritSect); +#else return RTSemRWGetWriteRecursion(m->sem); +#endif } #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION diff --git a/src/VBox/Main/glue/ErrorInfo.cpp b/src/VBox/Main/glue/ErrorInfo.cpp index 13cdee83..149708f5 100644 --- a/src/VBox/Main/glue/ErrorInfo.cpp +++ b/src/VBox/Main/glue/ErrorInfo.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -43,12 +43,23 @@ namespace com // //////////////////////////////////////////////////////////////////////////////// +HRESULT ErrorInfo::getVirtualBoxErrorInfo(ComPtr &pVirtualBoxErrorInfo) +{ + HRESULT rc = S_OK; + if (mErrorInfo) + rc = mErrorInfo.queryInterfaceTo(pVirtualBoxErrorInfo.asOutParam()); + else + pVirtualBoxErrorInfo.setNull(); + return rc; +} + void ErrorInfo::copyFrom(const ErrorInfo &x) { mIsBasicAvailable = x.mIsBasicAvailable; mIsFullAvailable = x.mIsFullAvailable; mResultCode = x.mResultCode; + mResultDetail = x.mResultDetail; mInterfaceID = x.mInterfaceID; mComponent = x.mComponent; mText = x.mText; @@ -77,6 +88,7 @@ void ErrorInfo::cleanup() } mResultCode = S_OK; + mResultDetail = 0; mInterfaceID.clear(); mComponent.setNull(); mText.setNull(); @@ -224,12 +236,16 @@ void ErrorInfo::init(IVirtualBoxErrorInfo *info) HRESULT rc = E_FAIL; bool gotSomething = false; bool gotAll = true; - LONG lrc; + LONG lrc, lrd; rc = info->COMGETTER(ResultCode)(&lrc); mResultCode = lrc; gotSomething |= SUCCEEDED(rc); gotAll &= SUCCEEDED(rc); + rc = info->COMGETTER(ResultDetail)(&lrd); mResultDetail = lrd; + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + Bstr iid; rc = info->COMGETTER(InterfaceID)(iid.asOutParam()); gotSomething |= SUCCEEDED(rc); @@ -266,6 +282,8 @@ void ErrorInfo::init(IVirtualBoxErrorInfo *info) mIsBasicAvailable = gotSomething; mIsFullAvailable = gotAll; + mErrorInfo = info; + AssertMsg(gotSomething, ("Nothing to fetch!\n")); } diff --git a/src/VBox/Main/glue/EventQueue.cpp b/src/VBox/Main/glue/EventQueue.cpp index d5a09c69..c918c993 100644 --- a/src/VBox/Main/glue/EventQueue.cpp +++ b/src/VBox/Main/glue/EventQueue.cpp @@ -1,11 +1,10 @@ /* $Id: EventQueue.cpp $ */ /** @file - * MS COM / XPCOM Abstraction Layer: - * Event and EventQueue class declaration + * Event queue class declaration. */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -16,23 +15,18 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -#include "VBox/com/EventQueue.h" +/** @todo Adapt / update documentation! */ -#ifdef RT_OS_DARWIN -# include -#endif +#include "VBox/com/EventQueue.h" -#if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2) -# define USE_XPCOM_QUEUE -#endif +#include +#include /* For bad_alloc. */ #include +#include #include #include #include -#ifdef USE_XPCOM_QUEUE -# include -#endif namespace com { @@ -40,430 +34,33 @@ namespace com // EventQueue class //////////////////////////////////////////////////////////////////////////////// -#ifndef VBOX_WITH_XPCOM - -# define CHECK_THREAD_RET(ret) \ - do { \ - AssertMsg(GetCurrentThreadId() == mThreadId, ("Must be on event queue thread!")); \ - if (GetCurrentThreadId() != mThreadId) \ - return ret; \ - } while (0) - -/** Magic LPARAM value for the WM_USER messages that we're posting. - * @remarks This magic value is duplicated in - * vboxapi/PlatformMSCOM::interruptWaitEvents(). */ -#define EVENTQUEUE_WIN_LPARAM_MAGIC UINT32_C(0xf241b819) - - -#else // VBOX_WITH_XPCOM - -# define CHECK_THREAD_RET(ret) \ - do { \ - if (!mEventQ) \ - return ret; \ - BOOL isOnCurrentThread = FALSE; \ - mEventQ->IsOnCurrentThread(&isOnCurrentThread); \ - AssertMsg(isOnCurrentThread, ("Must be on event queue thread!")); \ - if (!isOnCurrentThread) \ - return ret; \ - } while (0) - -#endif // VBOX_WITH_XPCOM - -/** Pointer to the main event queue. */ -EventQueue *EventQueue::sMainQueue = NULL; - - -#ifdef VBOX_WITH_XPCOM - -struct MyPLEvent : public PLEvent -{ - MyPLEvent(Event *e) : event(e) {} - Event *event; -}; - -/* static */ -void *PR_CALLBACK com::EventQueue::plEventHandler(PLEvent *self) -{ - Event *ev = ((MyPLEvent *)self)->event; - if (ev) - ev->handler(); - else - { - EventQueue *eq = (EventQueue *)self->owner; - Assert(eq); - eq->mInterrupted = true; - } - return NULL; -} - -/* static */ -void PR_CALLBACK com::EventQueue::plEventDestructor(PLEvent *self) -{ - Event *ev = ((MyPLEvent *)self)->event; - if (ev) - delete ev; - delete self; -} - -#endif // VBOX_WITH_XPCOM - -/** - * Constructs an event queue for the current thread. - * - * Currently, there can be only one event queue per thread, so if an event - * queue for the current thread already exists, this object is simply attached - * to the existing event queue. - */ -EventQueue::EventQueue() -{ -#ifndef VBOX_WITH_XPCOM - - mThreadId = GetCurrentThreadId(); - // force the system to create the message queue for the current thread - MSG msg; - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - - if (!DuplicateHandle(GetCurrentProcess(), - GetCurrentThread(), - GetCurrentProcess(), - &mhThread, - 0 /*dwDesiredAccess*/, - FALSE /*bInheritHandle*/, - DUPLICATE_SAME_ACCESS)) - mhThread = INVALID_HANDLE_VALUE; - -#else // VBOX_WITH_XPCOM - - mEQCreated = false; - mInterrupted = false; - - // Here we reference the global nsIEventQueueService instance and hold it - // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away - // from calling StopAcceptingEvents() on all event queues upon destruction of - // nsIEventQueueService, and makes sense when, for some reason, this happens - // *before* we're able to send a NULL event to stop our event handler thread - // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM() - // that is performing a global cleanup of everything. A good example of such - // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component - // is still alive (because it is still referenced): eventually, it results in - // a VirtualBox::uninit() call from where it is already not possible to post - // NULL to the event thread (because it stopped accepting events). - - nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService)); - - if (NS_SUCCEEDED(rc)) - { - rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, - getter_AddRefs(mEventQ)); - if (rc == NS_ERROR_NOT_AVAILABLE) - { - rc = mEventQService->CreateThreadEventQueue(); - if (NS_SUCCEEDED(rc)) - { - mEQCreated = true; - rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, - getter_AddRefs(mEventQ)); - } - } - } - AssertComRC(rc); - -#endif // VBOX_WITH_XPCOM -} - -EventQueue::~EventQueue() -{ -#ifndef VBOX_WITH_XPCOM - if (mhThread != INVALID_HANDLE_VALUE) - { - CloseHandle(mhThread); - mhThread = INVALID_HANDLE_VALUE; - } -#else // VBOX_WITH_XPCOM - // process all pending events before destruction - if (mEventQ) - { - if (mEQCreated) - { - mEventQ->StopAcceptingEvents(); - mEventQ->ProcessPendingEvents(); - mEventQService->DestroyThreadEventQueue(); - } - mEventQ = nsnull; - mEventQService = nsnull; - } -#endif // VBOX_WITH_XPCOM -} - -/** - * Initializes the main event queue instance. - * @returns VBox status code. - * - * @remarks If you're using the rest of the COM/XPCOM glue library, - * com::Initialize() will take care of initializing and uninitializing - * the EventQueue class. If you don't call com::Initialize, you must - * make sure to call this method on the same thread that did the - * XPCOM initialization or we'll end up using the wrong main queue. - */ -/* static */ -int EventQueue::init() +EventQueue::EventQueue(void) + : mUserCnt(0), + mShutdown(false) { - Assert(sMainQueue == NULL); - Assert(RTThreadIsMain(RTThreadSelf())); - sMainQueue = new EventQueue(); - -#ifdef VBOX_WITH_XPCOM - /* Check that it actually is the main event queue, i.e. that - we're called on the right thread. */ - nsCOMPtr q; - nsresult rv = NS_GetMainEventQ(getter_AddRefs(q)); - Assert(NS_SUCCEEDED(rv)); - Assert(q == sMainQueue->mEventQ); - - /* Check that it's a native queue. */ - PRBool fIsNative = PR_FALSE; - rv = sMainQueue->mEventQ->IsQueueNative(&fIsNative); - Assert(NS_SUCCEEDED(rv) && fIsNative); -#endif // VBOX_WITH_XPCOM - - return VINF_SUCCESS; -} - -/** - * Uninitialize the global resources (i.e. the main event queue instance). - * @returns VINF_SUCCESS - */ -/* static */ -int EventQueue::uninit() -{ - if (sMainQueue) - { - /* Must process all events to make sure that no NULL event is left - * after this point. It would need to modify the state of sMainQueue. */ -#ifdef RT_OS_DARWIN /* Do not process the native runloop, the toolkit may not be ready for it. */ - sMainQueue->mEventQ->ProcessPendingEvents(); -#else - sMainQueue->processEventQueue(0); -#endif - delete sMainQueue; - sMainQueue = NULL; - } - return VINF_SUCCESS; -} + int rc = RTCritSectInit(&mCritSect); + AssertRC(rc); -/** - * Get main event queue instance. - * - * Depends on init() being called first. - */ -/* static */ -EventQueue* EventQueue::getMainEventQueue() -{ - return sMainQueue; + rc = RTSemEventCreate(&mSemEvent); + AssertRC(rc); } -#ifdef VBOX_WITH_XPCOM -# ifdef RT_OS_DARWIN -/** - * Wait for events and process them (Darwin). - * - * @retval VINF_SUCCESS - * @retval VERR_TIMEOUT - * @retval VERR_INTERRUPTED - * - * @param cMsTimeout How long to wait, or RT_INDEFINITE_WAIT. - */ -static int waitForEventsOnDarwin(RTMSINTERVAL cMsTimeout) +EventQueue::~EventQueue(void) { - /* - * Wait for the requested time, if we get a hit we do a poll to process - * any other pending messages. - * - * Note! About 1.0e10: According to the sources anything above 3.1556952e+9 - * means indefinite wait and 1.0e10 is what CFRunLoopRun() uses. - */ - CFTimeInterval rdTimeout = cMsTimeout == RT_INDEFINITE_WAIT ? 1e10 : (double)cMsTimeout / 1000; - OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/); - if (orc == kCFRunLoopRunHandledSource) - { - OSStatus orc2 = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/); - if ( orc2 == kCFRunLoopRunStopped - || orc2 == kCFRunLoopRunFinished) - orc = orc2; - } - if ( orc == 0 /*???*/ - || orc == kCFRunLoopRunHandledSource) - return VINF_SUCCESS; - if ( orc == kCFRunLoopRunStopped - || orc == kCFRunLoopRunFinished) - return VERR_INTERRUPTED; - AssertMsg(orc == kCFRunLoopRunTimedOut, ("Unexpected status code from CFRunLoopRunInMode: %#x", orc)); - return VERR_TIMEOUT; -} -# else // !RT_OS_DARWIN + int rc = RTCritSectDelete(&mCritSect); + AssertRC(rc); -/** - * Wait for events (generic XPCOM). - * - * @retval VINF_SUCCESS - * @retval VERR_TIMEOUT - * @retval VINF_INTERRUPTED - * @retval VERR_INTERNAL_ERROR_4 - * - * @param pQueue The queue to wait on. - * @param cMsTimeout How long to wait, or RT_INDEFINITE_WAIT. - */ -static int waitForEventsOnXPCOM(nsIEventQueue *pQueue, RTMSINTERVAL cMsTimeout) -{ - int fd = pQueue->GetEventQueueSelectFD(); - fd_set fdsetR; - FD_ZERO(&fdsetR); - FD_SET(fd, &fdsetR); - - fd_set fdsetE = fdsetR; - - struct timeval tv = {0,0}; - struct timeval *ptv; - if (cMsTimeout == RT_INDEFINITE_WAIT) - ptv = NULL; - else - { - tv.tv_sec = cMsTimeout / 1000; - tv.tv_usec = (cMsTimeout % 1000) * 1000; - ptv = &tv; - } + rc = RTSemEventDestroy(mSemEvent); + AssertRC(rc); - int rc = select(fd + 1, &fdsetR, NULL, &fdsetE, ptv); - if (rc > 0) - rc = VINF_SUCCESS; - else if (rc == 0) - rc = VERR_TIMEOUT; - else if (errno == EINTR) - rc = VINF_INTERRUPTED; - else + EventQueueListIterator it = mEvents.begin(); + while (it != mEvents.end()) { - static uint32_t s_ErrorCount = 0; - if (s_ErrorCount < 500) - { - LogRel(("waitForEventsOnXPCOM rc=%d errno=%d\n", rc, errno)); - ++s_ErrorCount; - } - - AssertMsgFailed(("rc=%d errno=%d\n", rc, errno)); - rc = VERR_INTERNAL_ERROR_4; + (*it)->Release(); + it = mEvents.erase(it); } - return rc; } -# endif // !RT_OS_DARWIN -#endif // VBOX_WITH_XPCOM - -#ifndef VBOX_WITH_XPCOM - -/** - * Dispatch a message on Windows. - * - * This will pick out our events and handle them specially. - * - * @returns @a rc or VERR_INTERRUPTED (WM_QUIT or NULL msg). - * @param pMsg The message to dispatch. - * @param rc The current status code. - */ -/*static*/ -int EventQueue::dispatchMessageOnWindows(MSG const *pMsg, int rc) -{ - /* - * Check for and dispatch our events. - */ - if ( pMsg->hwnd == NULL - && pMsg->message == WM_USER) - { - if (pMsg->lParam == EVENTQUEUE_WIN_LPARAM_MAGIC) - { - Event *pEvent = (Event *)pMsg->wParam; - if (pEvent) - { - pEvent->handler(); - delete pEvent; - } - else - rc = VERR_INTERRUPTED; - return rc; - } - AssertMsgFailed(("lParam=%p wParam=%p\n", pMsg->lParam, pMsg->wParam)); - } - - /* - * Check for the quit message and dispatch the message the normal way. - */ - if (pMsg->message == WM_QUIT) - rc = VERR_INTERRUPTED; - TranslateMessage(pMsg); - DispatchMessage(pMsg); - - return rc; -} - - -/** - * Process pending events (Windows). - * - * @retval VINF_SUCCESS - * @retval VERR_TIMEOUT - * @retval VERR_INTERRUPTED. - */ -static int processPendingEvents(void) -{ - int rc = VERR_TIMEOUT; - MSG Msg; - if (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE)) - { - rc = VINF_SUCCESS; - do - rc = EventQueue::dispatchMessageOnWindows(&Msg, rc); - while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE)); - } - return rc; -} - -#else // VBOX_WITH_XPCOM - -/** - * Process pending XPCOM events. - * @param pQueue The queue to process events on. - * @retval VINF_SUCCESS - * @retval VERR_TIMEOUT - * @retval VERR_INTERRUPTED (darwin only) - * @retval VERR_INTERNAL_ERROR_2 - */ -static int processPendingEvents(nsIEventQueue *pQueue) -{ - /* ProcessPendingEvents doesn't report back what it did, so check here. */ - PRBool fHasEvents = PR_FALSE; - nsresult hr = pQueue->PendingEvents(&fHasEvents); - if (NS_FAILED(hr)) - return VERR_INTERNAL_ERROR_2; - - /* Process pending events. */ - int rc = VINF_SUCCESS; - if (fHasEvents) - pQueue->ProcessPendingEvents(); - else - rc = VERR_TIMEOUT; - -# ifdef RT_OS_DARWIN - /* Process pending native events. */ - int rc2 = waitForEventsOnDarwin(0); - if (rc == VERR_TIMEOUT || rc2 == VERR_INTERRUPTED) - rc = rc2; -# endif - - return rc; -} - -#endif // VBOX_WITH_XPCOM - /** * Process events pending on this event queue, and wait up to given timeout, if * nothing is available. @@ -489,80 +86,92 @@ static int processPendingEvents(nsIEventQueue *pQueue) */ int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout) { - int rc; - CHECK_THREAD_RET(VERR_INVALID_CONTEXT); - -#ifdef VBOX_WITH_XPCOM - /* - * Process pending events, if none are available and we're not in a - * poll call, wait for some to appear. (We have to be a little bit - * careful after waiting for the events since Darwin will process - * them as part of the wait, while the XPCOM case will not.) - * - * Note! Unfortunately, WaitForEvent isn't interruptible with Ctrl-C, - * while select() is. So we cannot use it for indefinite waits. - */ - rc = processPendingEvents(mEventQ); - if ( rc == VERR_TIMEOUT - && cMsTimeout > 0) + size_t cNumEvents; + int rc = RTCritSectEnter(&mCritSect); + if (RT_SUCCESS(rc)) { -# ifdef RT_OS_DARWIN - /** @todo check how Ctrl-C works on Darwin. */ - rc = waitForEventsOnDarwin(cMsTimeout); - if (rc == VERR_TIMEOUT) - rc = processPendingEvents(mEventQ); -# else // !RT_OS_DARWIN - rc = waitForEventsOnXPCOM(mEventQ, cMsTimeout); - if ( RT_SUCCESS(rc) - || rc == VERR_TIMEOUT) - rc = processPendingEvents(mEventQ); -# endif // !RT_OS_DARWIN - } + if (mUserCnt == 0) /* No concurrent access allowed. */ + { + mUserCnt++; - if ( ( RT_SUCCESS(rc) - || rc == VERR_INTERRUPTED - || rc == VERR_TIMEOUT) - && mInterrupted) - { - mInterrupted = false; - rc = VERR_INTERRUPTED; - } + cNumEvents = mEvents.size(); + if (!cNumEvents) + { + int rc2 = RTCritSectLeave(&mCritSect); + AssertRC(rc2); -#else // !VBOX_WITH_XPCOM - if (cMsTimeout == RT_INDEFINITE_WAIT) - { - BOOL fRet; - MSG Msg; - rc = VINF_SUCCESS; - while ( rc != VERR_INTERRUPTED - && (fRet = GetMessage(&Msg, NULL /*hWnd*/, WM_USER, WM_USER)) - && fRet != -1) - rc = EventQueue::dispatchMessageOnWindows(&Msg, rc); - if (fRet == 0) - rc = VERR_INTERRUPTED; - else if (fRet == -1) - rc = RTErrConvertFromWin32(GetLastError()); + rc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout); + + rc2 = RTCritSectEnter(&mCritSect); + AssertRC(rc2); + + if (RT_SUCCESS(rc)) + { + if (mShutdown) + rc = VERR_INTERRUPTED; + cNumEvents = mEvents.size(); + } + } + + if (RT_SUCCESS(rc)) + rc = processPendingEvents(cNumEvents); + + Assert(mUserCnt); + mUserCnt--; + } + else + rc = VERR_WRONG_ORDER; + + int rc2 = RTCritSectLeave(&mCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; } - else + + Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT); + return rc; +} + +/** + * Processes all pending events in the queue at the time of + * calling. Note: Does no initial locking, must be done by the + * caller! + * + * @return IPRT status code. + */ +int EventQueue::processPendingEvents(size_t cNumEvents) +{ + if (!cNumEvents) /* Nothing to process? Bail out early. */ + return VINF_SUCCESS; + + int rc = VINF_SUCCESS; + + EventQueueListIterator it = mEvents.begin(); + for (size_t i = 0; + i < cNumEvents + && it != mEvents.end(); i++) { - rc = processPendingEvents(); - if ( rc == VERR_TIMEOUT - && cMsTimeout != 0) + Event *pEvent = *it; + AssertPtr(pEvent); + + mEvents.erase(it); + + int rc2 = RTCritSectLeave(&mCritSect); + AssertRC(rc2); + + pEvent->handler(); + pEvent->Release(); + + rc2 = RTCritSectEnter(&mCritSect); + AssertRC(rc2); + + it = mEvents.begin(); + if (mShutdown) { - DWORD rcW = MsgWaitForMultipleObjects(1, - &mhThread, - TRUE /*fWaitAll*/, - cMsTimeout, - QS_ALLINPUT); - AssertMsgReturn(rcW == WAIT_TIMEOUT || rcW == WAIT_OBJECT_0, - ("%d\n", rcW), - VERR_INTERNAL_ERROR_4); - rc = processPendingEvents(); + rc = VERR_INTERRUPTED; + break; } } -#endif // !VBOX_WITH_XPCOM - Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT); return rc; } @@ -573,13 +182,11 @@ int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout) * * @returns VBox status code. */ -int EventQueue::interruptEventQueueProcessing() +int EventQueue::interruptEventQueueProcessing(void) { - /* Send a NULL event. This event will be picked up and handled specially - * both for XPCOM and Windows. It is the responsibility of the caller to - * take care of not running the loop again in a way which will hang. */ - postEvent(NULL); - return VINF_SUCCESS; + ASMAtomicWriteBool(&mShutdown, true); + + return RTSemEventSignal(mSemEvent); } /** @@ -588,39 +195,52 @@ int EventQueue::interruptEventQueueProcessing() * @param event the event to post, must be allocated using |new| * @return TRUE if successful and false otherwise */ -BOOL EventQueue::postEvent(Event *event) +BOOL EventQueue::postEvent(Event *pEvent) { -#ifndef VBOX_WITH_XPCOM - /* Note! The event == NULL case is duplicated in vboxapi/PlatformMSCOM::interruptWaitEvents(). */ - return PostThreadMessage(mThreadId, WM_USER, (WPARAM)event, EVENTQUEUE_WIN_LPARAM_MAGIC); - -#else // VBOX_WITH_XPCOM - - if (!mEventQ) - return FALSE; + int rc = RTCritSectEnter(&mCritSect); + if (RT_SUCCESS(rc)) + { + try + { + if (pEvent) + { + pEvent->AddRef(); + mEvents.push_back(pEvent); + } + else /* No locking, since we're already in our crit sect. */ + mShutdown = true; - MyPLEvent *ev = new MyPLEvent(event); - mEventQ->InitEvent(ev, this, com::EventQueue::plEventHandler, - com::EventQueue::plEventDestructor); - HRESULT rc = mEventQ->PostEvent(ev); - return NS_SUCCEEDED(rc); + size_t cEvents = mEvents.size(); + if (cEvents > _1K) /** @todo Make value configurable? */ + { + static int s_cBitchedAboutLotEvents = 0; + if (s_cBitchedAboutLotEvents < 10) + LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n", + cEvents, ++s_cBitchedAboutLotEvents)); + } -#endif // VBOX_WITH_XPCOM -} + /* Leave critical section before signalling event. */ + rc = RTCritSectLeave(&mCritSect); + if (RT_SUCCESS(rc)) + { + int rc2 = RTSemEventSignal(mSemEvent); + AssertRC(rc2); + } + } + catch (std::bad_alloc &ba) + { + NOREF(ba); + rc = VERR_NO_MEMORY; + } + if (RT_FAILURE(rc)) + { + int rc2 = RTCritSectLeave(&mCritSect); + AssertRC(rc2); + } + } -/** - * Get select()'able selector for this event queue. - * This will return -1 on platforms and queue variants not supporting such - * functionality. - */ -int EventQueue::getSelectFD() -{ -#ifdef VBOX_WITH_XPCOM - return mEventQ->GetEventQueueSelectFD(); -#else - return -1; -#endif + return RT_SUCCESS(rc) ? TRUE : FALSE; } } diff --git a/src/VBox/Main/glue/NativeEventQueue.cpp b/src/VBox/Main/glue/NativeEventQueue.cpp new file mode 100644 index 00000000..23420f20 --- /dev/null +++ b/src/VBox/Main/glue/NativeEventQueue.cpp @@ -0,0 +1,655 @@ +/* $Id: NativeEventQueue.cpp $ */ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Main event queue class declaration + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "VBox/com/NativeEventQueue.h" + +#include /* For bad_alloc. */ + +#ifdef RT_OS_DARWIN +# include +#endif + +#if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2) +# define USE_XPCOM_QUEUE +#endif + +#include +#include +#include +#include +#ifdef USE_XPCOM_QUEUE +# include +#endif + +namespace com +{ + +// NativeEventQueue class +//////////////////////////////////////////////////////////////////////////////// + +#ifndef VBOX_WITH_XPCOM + +# define CHECK_THREAD_RET(ret) \ + do { \ + AssertMsg(GetCurrentThreadId() == mThreadId, ("Must be on event queue thread!")); \ + if (GetCurrentThreadId() != mThreadId) \ + return ret; \ + } while (0) + +/** Magic LPARAM value for the WM_USER messages that we're posting. + * @remarks This magic value is duplicated in + * vboxapi/PlatformMSCOM::interruptWaitEvents(). */ +#define EVENTQUEUE_WIN_LPARAM_MAGIC UINT32_C(0xf241b819) + + +#else // VBOX_WITH_XPCOM + +# define CHECK_THREAD_RET(ret) \ + do { \ + if (!mEventQ) \ + return ret; \ + BOOL isOnCurrentThread = FALSE; \ + mEventQ->IsOnCurrentThread(&isOnCurrentThread); \ + AssertMsg(isOnCurrentThread, ("Must be on event queue thread!")); \ + if (!isOnCurrentThread) \ + return ret; \ + } while (0) + +#endif // VBOX_WITH_XPCOM + +/** Pointer to the main event queue. */ +NativeEventQueue *NativeEventQueue::sMainQueue = NULL; + + +#ifdef VBOX_WITH_XPCOM + +struct MyPLEvent : public PLEvent +{ + MyPLEvent(NativeEvent *e) : event(e) {} + NativeEvent *event; +}; + +/* static */ +void *PR_CALLBACK com::NativeEventQueue::plEventHandler(PLEvent *self) +{ + NativeEvent *ev = ((MyPLEvent *)self)->event; + if (ev) + ev->handler(); + else + { + NativeEventQueue *eq = (NativeEventQueue *)self->owner; + Assert(eq); + eq->mInterrupted = true; + } + return NULL; +} + +/* static */ +void PR_CALLBACK com::NativeEventQueue::plEventDestructor(PLEvent *self) +{ + NativeEvent *ev = ((MyPLEvent *)self)->event; + if (ev) + delete ev; + delete self; +} + +#endif // VBOX_WITH_XPCOM + +/** + * Constructs an event queue for the current thread. + * + * Currently, there can be only one event queue per thread, so if an event + * queue for the current thread already exists, this object is simply attached + * to the existing event queue. + */ +NativeEventQueue::NativeEventQueue() +{ +#ifndef VBOX_WITH_XPCOM + + mThreadId = GetCurrentThreadId(); + // force the system to create the message queue for the current thread + MSG msg; + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + if (!DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &mhThread, + 0 /*dwDesiredAccess*/, + FALSE /*bInheritHandle*/, + DUPLICATE_SAME_ACCESS)) + mhThread = INVALID_HANDLE_VALUE; + +#else // VBOX_WITH_XPCOM + + mEQCreated = false; + mInterrupted = false; + + // Here we reference the global nsIEventQueueService instance and hold it + // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away + // from calling StopAcceptingEvents() on all event queues upon destruction of + // nsIEventQueueService, and makes sense when, for some reason, this happens + // *before* we're able to send a NULL event to stop our event handler thread + // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM() + // that is performing a global cleanup of everything. A good example of such + // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component + // is still alive (because it is still referenced): eventually, it results in + // a VirtualBox::uninit() call from where it is already not possible to post + // NULL to the event thread (because it stopped accepting events). + + nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService)); + + if (NS_SUCCEEDED(rc)) + { + rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, + getter_AddRefs(mEventQ)); + if (rc == NS_ERROR_NOT_AVAILABLE) + { + rc = mEventQService->CreateThreadEventQueue(); + if (NS_SUCCEEDED(rc)) + { + mEQCreated = true; + rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, + getter_AddRefs(mEventQ)); + } + } + } + AssertComRC(rc); + +#endif // VBOX_WITH_XPCOM +} + +NativeEventQueue::~NativeEventQueue() +{ +#ifndef VBOX_WITH_XPCOM + if (mhThread != INVALID_HANDLE_VALUE) + { + CloseHandle(mhThread); + mhThread = INVALID_HANDLE_VALUE; + } +#else // VBOX_WITH_XPCOM + // process all pending events before destruction + if (mEventQ) + { + if (mEQCreated) + { + mEventQ->StopAcceptingEvents(); + mEventQ->ProcessPendingEvents(); + mEventQService->DestroyThreadEventQueue(); + } + mEventQ = nsnull; + mEventQService = nsnull; + } +#endif // VBOX_WITH_XPCOM +} + +/** + * Initializes the main event queue instance. + * @returns VBox status code. + * + * @remarks If you're using the rest of the COM/XPCOM glue library, + * com::Initialize() will take care of initializing and uninitializing + * the NativeEventQueue class. If you don't call com::Initialize, you must + * make sure to call this method on the same thread that did the + * XPCOM initialization or we'll end up using the wrong main queue. + */ +/* static */ +int NativeEventQueue::init() +{ + Assert(sMainQueue == NULL); + Assert(RTThreadIsMain(RTThreadSelf())); + + try + { + sMainQueue = new NativeEventQueue(); + AssertPtr(sMainQueue); +#ifdef VBOX_WITH_XPCOM + /* Check that it actually is the main event queue, i.e. that + we're called on the right thread. */ + nsCOMPtr q; + nsresult rv = NS_GetMainEventQ(getter_AddRefs(q)); + AssertComRCReturn(rv, VERR_INVALID_POINTER); + Assert(q == sMainQueue->mEventQ); + + /* Check that it's a native queue. */ + PRBool fIsNative = PR_FALSE; + rv = sMainQueue->mEventQ->IsQueueNative(&fIsNative); + Assert(NS_SUCCEEDED(rv) && fIsNative); +#endif // VBOX_WITH_XPCOM + } + catch (std::bad_alloc &ba) + { + NOREF(ba); + return VERR_NO_MEMORY; + } + + return VINF_SUCCESS; +} + +/** + * Uninitialize the global resources (i.e. the main event queue instance). + * @returns VINF_SUCCESS + */ +/* static */ +int NativeEventQueue::uninit() +{ + if (sMainQueue) + { + /* Must process all events to make sure that no NULL event is left + * after this point. It would need to modify the state of sMainQueue. */ +#ifdef RT_OS_DARWIN /* Do not process the native runloop, the toolkit may not be ready for it. */ + sMainQueue->mEventQ->ProcessPendingEvents(); +#else + sMainQueue->processEventQueue(0); +#endif + delete sMainQueue; + sMainQueue = NULL; + } + return VINF_SUCCESS; +} + +/** + * Get main event queue instance. + * + * Depends on init() being called first. + */ +/* static */ +NativeEventQueue* NativeEventQueue::getMainEventQueue() +{ + return sMainQueue; +} + +#ifdef VBOX_WITH_XPCOM +# ifdef RT_OS_DARWIN +/** + * Wait for events and process them (Darwin). + * + * @retval VINF_SUCCESS + * @retval VERR_TIMEOUT + * @retval VERR_INTERRUPTED + * + * @param cMsTimeout How long to wait, or RT_INDEFINITE_WAIT. + */ +static int waitForEventsOnDarwin(RTMSINTERVAL cMsTimeout) +{ + /* + * Wait for the requested time, if we get a hit we do a poll to process + * any other pending messages. + * + * Note! About 1.0e10: According to the sources anything above 3.1556952e+9 + * means indefinite wait and 1.0e10 is what CFRunLoopRun() uses. + */ + CFTimeInterval rdTimeout = cMsTimeout == RT_INDEFINITE_WAIT ? 1e10 : (double)cMsTimeout / 1000; + OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/); + if (orc == kCFRunLoopRunHandledSource) + { + OSStatus orc2 = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/); + if ( orc2 == kCFRunLoopRunStopped + || orc2 == kCFRunLoopRunFinished) + orc = orc2; + } + if ( orc == 0 /*???*/ + || orc == kCFRunLoopRunHandledSource) + return VINF_SUCCESS; + if ( orc == kCFRunLoopRunStopped + || orc == kCFRunLoopRunFinished) + return VERR_INTERRUPTED; + AssertMsg(orc == kCFRunLoopRunTimedOut, ("Unexpected status code from CFRunLoopRunInMode: %#x", orc)); + return VERR_TIMEOUT; +} +# else // !RT_OS_DARWIN + +/** + * Wait for events (generic XPCOM). + * + * @retval VINF_SUCCESS + * @retval VERR_TIMEOUT + * @retval VINF_INTERRUPTED + * @retval VERR_INTERNAL_ERROR_4 + * + * @param pQueue The queue to wait on. + * @param cMsTimeout How long to wait, or RT_INDEFINITE_WAIT. + */ +static int waitForEventsOnXPCOM(nsIEventQueue *pQueue, RTMSINTERVAL cMsTimeout) +{ + int fd = pQueue->GetEventQueueSelectFD(); + fd_set fdsetR; + FD_ZERO(&fdsetR); + FD_SET(fd, &fdsetR); + + fd_set fdsetE = fdsetR; + + struct timeval tv = {0,0}; + struct timeval *ptv; + if (cMsTimeout == RT_INDEFINITE_WAIT) + ptv = NULL; + else + { + tv.tv_sec = cMsTimeout / 1000; + tv.tv_usec = (cMsTimeout % 1000) * 1000; + ptv = &tv; + } + + int rc = select(fd + 1, &fdsetR, NULL, &fdsetE, ptv); + if (rc > 0) + rc = VINF_SUCCESS; + else if (rc == 0) + rc = VERR_TIMEOUT; + else if (errno == EINTR) + rc = VINF_INTERRUPTED; + else + { + static uint32_t s_ErrorCount = 0; + if (s_ErrorCount < 500) + { + LogRel(("waitForEventsOnXPCOM rc=%d errno=%d\n", rc, errno)); + ++s_ErrorCount; + } + + AssertMsgFailed(("rc=%d errno=%d\n", rc, errno)); + rc = VERR_INTERNAL_ERROR_4; + } + return rc; +} + +# endif // !RT_OS_DARWIN +#endif // VBOX_WITH_XPCOM + +#ifndef VBOX_WITH_XPCOM + +/** + * Dispatch a message on Windows. + * + * This will pick out our events and handle them specially. + * + * @returns @a rc or VERR_INTERRUPTED (WM_QUIT or NULL msg). + * @param pMsg The message to dispatch. + * @param rc The current status code. + */ +/*static*/ +int NativeEventQueue::dispatchMessageOnWindows(MSG const *pMsg, int rc) +{ + /* + * Check for and dispatch our events. + */ + if ( pMsg->hwnd == NULL + && pMsg->message == WM_USER) + { + if (pMsg->lParam == EVENTQUEUE_WIN_LPARAM_MAGIC) + { + NativeEvent *pEvent = (NativeEvent *)pMsg->wParam; + if (pEvent) + { + pEvent->handler(); + delete pEvent; + } + else + rc = VERR_INTERRUPTED; + return rc; + } + AssertMsgFailed(("lParam=%p wParam=%p\n", pMsg->lParam, pMsg->wParam)); + } + + /* + * Check for the quit message and dispatch the message the normal way. + */ + if (pMsg->message == WM_QUIT) + rc = VERR_INTERRUPTED; + TranslateMessage(pMsg); + DispatchMessage(pMsg); + + return rc; +} + + +/** + * Process pending events (Windows). + * + * @retval VINF_SUCCESS + * @retval VERR_TIMEOUT + * @retval VERR_INTERRUPTED. + */ +static int processPendingEvents(void) +{ + int rc = VERR_TIMEOUT; + MSG Msg; + if (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE)) + { + rc = VINF_SUCCESS; + do + rc = NativeEventQueue::dispatchMessageOnWindows(&Msg, rc); + while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE)); + } + return rc; +} + +#else // VBOX_WITH_XPCOM + +/** + * Process pending XPCOM events. + * @param pQueue The queue to process events on. + * @retval VINF_SUCCESS + * @retval VERR_TIMEOUT + * @retval VERR_INTERRUPTED (darwin only) + * @retval VERR_INTERNAL_ERROR_2 + */ +static int processPendingEvents(nsIEventQueue *pQueue) +{ + /* ProcessPendingEvents doesn't report back what it did, so check here. */ + PRBool fHasEvents = PR_FALSE; + nsresult hr = pQueue->PendingEvents(&fHasEvents); + if (NS_FAILED(hr)) + return VERR_INTERNAL_ERROR_2; + + /* Process pending events. */ + int rc = VINF_SUCCESS; + if (fHasEvents) + pQueue->ProcessPendingEvents(); + else + rc = VERR_TIMEOUT; + +# ifdef RT_OS_DARWIN + /* Process pending native events. */ + int rc2 = waitForEventsOnDarwin(0); + if (rc == VERR_TIMEOUT || rc2 == VERR_INTERRUPTED) + rc = rc2; +# endif + + return rc; +} + +#endif // VBOX_WITH_XPCOM + +/** + * Process events pending on this event queue, and wait up to given timeout, if + * nothing is available. + * + * Must be called on same thread this event queue was created on. + * + * @param cMsTimeout The timeout specified as milliseconds. Use + * RT_INDEFINITE_WAIT to wait till an event is posted on the + * queue. + * + * @returns VBox status code + * @retval VINF_SUCCESS if one or more messages was processed. + * @retval VERR_TIMEOUT if cMsTimeout expired. + * @retval VERR_INVALID_CONTEXT if called on the wrong thread. + * @retval VERR_INTERRUPTED if interruptEventQueueProcessing was called. + * On Windows will also be returned when WM_QUIT is encountered. + * On Darwin this may also be returned when the native queue is + * stopped or destroyed/finished. + * @retval VINF_INTERRUPTED if the native system call was interrupted by a + * an asynchronous event delivery (signal) or just felt like returning + * out of bounds. On darwin it will also be returned if the queue is + * stopped. + */ +int NativeEventQueue::processEventQueue(RTMSINTERVAL cMsTimeout) +{ + int rc; + CHECK_THREAD_RET(VERR_INVALID_CONTEXT); + +#ifdef VBOX_WITH_XPCOM + /* + * Process pending events, if none are available and we're not in a + * poll call, wait for some to appear. (We have to be a little bit + * careful after waiting for the events since Darwin will process + * them as part of the wait, while the XPCOM case will not.) + * + * Note! Unfortunately, WaitForEvent isn't interruptible with Ctrl-C, + * while select() is. So we cannot use it for indefinite waits. + */ + rc = processPendingEvents(mEventQ); + if ( rc == VERR_TIMEOUT + && cMsTimeout > 0) + { +# ifdef RT_OS_DARWIN + /** @todo check how Ctrl-C works on Darwin. */ + rc = waitForEventsOnDarwin(cMsTimeout); + if (rc == VERR_TIMEOUT) + rc = processPendingEvents(mEventQ); +# else // !RT_OS_DARWIN + rc = waitForEventsOnXPCOM(mEventQ, cMsTimeout); + if ( RT_SUCCESS(rc) + || rc == VERR_TIMEOUT) + rc = processPendingEvents(mEventQ); +# endif // !RT_OS_DARWIN + } + + if ( ( RT_SUCCESS(rc) + || rc == VERR_INTERRUPTED + || rc == VERR_TIMEOUT) + && mInterrupted) + { + mInterrupted = false; + rc = VERR_INTERRUPTED; + } + +#else // !VBOX_WITH_XPCOM + if (cMsTimeout == RT_INDEFINITE_WAIT) + { + BOOL fRet; + MSG Msg; + rc = VINF_SUCCESS; + while ( rc != VERR_INTERRUPTED + && (fRet = GetMessage(&Msg, NULL /*hWnd*/, WM_USER, WM_USER)) + && fRet != -1) + rc = NativeEventQueue::dispatchMessageOnWindows(&Msg, rc); + if (fRet == 0) + rc = VERR_INTERRUPTED; + else if (fRet == -1) + rc = RTErrConvertFromWin32(GetLastError()); + } + else + { + rc = processPendingEvents(); + if ( rc == VERR_TIMEOUT + && cMsTimeout != 0) + { + DWORD rcW = MsgWaitForMultipleObjects(1, + &mhThread, + TRUE /*fWaitAll*/, + cMsTimeout, + QS_ALLINPUT); + AssertMsgReturn(rcW == WAIT_TIMEOUT || rcW == WAIT_OBJECT_0, + ("%d\n", rcW), + VERR_INTERNAL_ERROR_4); + rc = processPendingEvents(); + } + } +#endif // !VBOX_WITH_XPCOM + + Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT); + return rc; +} + +/** + * Interrupt thread waiting on event queue processing. + * + * Can be called on any thread. + * + * @returns VBox status code. + */ +int NativeEventQueue::interruptEventQueueProcessing() +{ + /* Send a NULL event. This event will be picked up and handled specially + * both for XPCOM and Windows. It is the responsibility of the caller to + * take care of not running the loop again in a way which will hang. */ + postEvent(NULL); + return VINF_SUCCESS; +} + +/** + * Posts an event to this event loop asynchronously. + * + * @param event the event to post, must be allocated using |new| + * @return TRUE if successful and false otherwise + */ +BOOL NativeEventQueue::postEvent(NativeEvent *pEvent) +{ +#ifndef VBOX_WITH_XPCOM + /* Note! The event == NULL case is duplicated in vboxapi/PlatformMSCOM::interruptWaitEvents(). */ + BOOL fRc = PostThreadMessage(mThreadId, WM_USER, (WPARAM)pEvent, EVENTQUEUE_WIN_LPARAM_MAGIC); + if (!fRc) + { + static int s_cBitchedAboutFullNativeEventQueue = 0; + if ( GetLastError() == ERROR_NOT_ENOUGH_QUOTA + && s_cBitchedAboutFullNativeEventQueue < 10) + LogRel(("Warning: Asynchronous event queue (%p, thread %RI32) full, event (%p) not delivered (%d/10)\n", + this, mThreadId, pEvent, ++s_cBitchedAboutFullNativeEventQueue)); + else + AssertFailed(); + } + return fRc; +#else // VBOX_WITH_XPCOM + if (!mEventQ) + return FALSE; + + try + { + MyPLEvent *pMyEvent = new MyPLEvent(pEvent); + mEventQ->InitEvent(pMyEvent, this, com::NativeEventQueue::plEventHandler, + com::NativeEventQueue::plEventDestructor); + HRESULT rc = mEventQ->PostEvent(pMyEvent); + return NS_SUCCEEDED(rc); + } + catch (std::bad_alloc &ba) + { + AssertMsgFailed(("Out of memory while allocating memory for event=%p: %s\n", + pEvent, ba.what())); + } + + return FALSE; +#endif // VBOX_WITH_XPCOM +} + +/** + * Get select()'able selector for this event queue. + * This will return -1 on platforms and queue variants not supporting such + * functionality. + */ +int NativeEventQueue::getSelectFD() +{ +#ifdef VBOX_WITH_XPCOM + return mEventQ->GetEventQueueSelectFD(); +#else + return -1; +#endif +} + +} +/* namespace com */ diff --git a/src/VBox/Main/glue/com.cpp b/src/VBox/Main/glue/com.cpp index f2252662..66ca1525 100644 --- a/src/VBox/Main/glue/com.cpp +++ b/src/VBox/Main/glue/com.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2012 Oracle Corporation + * Copyright (C) 2005-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -54,10 +54,25 @@ #include #include +#if !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS) +char szXdgConfigHome[RTPATH_MAX] = ""; +#endif + +/** + * Possible locations for the VirtualBox user configuration folder, + * listed from oldest (as in legacy) to newest. These can be either + * absolute or relative to the home directory. We use the first entry + * of the list which corresponds to a real folder on storage, or + * create a folder corresponding to the last in the list (the least + * legacy) if none do. + */ +const char *const apcszUserHome[] = #ifdef RT_OS_DARWIN -# define VBOX_USER_HOME_SUFFIX "Library/VirtualBox" +{ "Library/VirtualBox" }; +#elif defined RT_OS_WINDOWS +{ ".VirtualBox" }; #else -# define VBOX_USER_HOME_SUFFIX ".VirtualBox" +{ ".VirtualBox", szXdgConfigHome }; #endif #include "Logging.h" @@ -181,6 +196,24 @@ HRESULT GlueCreateInstance(const CLSID &clsid, #endif // VBOX_WITH_XPCOM +static int composeHomePath(char *aDir, size_t aDirLen, + const char *pcszBase) +{ + int vrc; + if (RTPathStartsWithRoot(pcszBase)) + vrc = RTStrCopy(aDir, aDirLen, pcszBase); + else + { + /* compose the config directory (full path) */ + /** @todo r=bird: RTPathUserHome doesn't necessarily return a + * full (abs) path like the comment above seems to indicate. */ + vrc = RTPathUserHome(aDir, aDirLen); + if (RT_SUCCESS(vrc)) + vrc = RTPathAppend(aDir, aDirLen, pcszBase); + } + return vrc; +} + int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir) { AssertReturn(aDir, VERR_INVALID_POINTER); @@ -193,6 +226,7 @@ int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir) int vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_USER_HOME", szTmp, sizeof(szTmp), NULL); if (RT_SUCCESS(vrc) || vrc == VERR_ENV_VAR_NOT_FOUND) { + bool fFound = false; if (RT_SUCCESS(vrc)) { /* get the full path name */ @@ -200,17 +234,37 @@ int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir) } else { - /* compose the config directory (full path) */ - /** @todo r=bird: RTPathUserHome doesn't necessarily return a full (abs) path - * like the comment above seems to indicate. */ - vrc = RTPathUserHome(aDir, aDirLen); - if (RT_SUCCESS(vrc)) - vrc = RTPathAppend(aDir, aDirLen, VBOX_USER_HOME_SUFFIX); +#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) + const char *pcszConfigHome = RTEnvGet("XDG_CONFIG_HOME"); + if (pcszConfigHome && pcszConfigHome[0]) + { + vrc = RTStrCopy(szXdgConfigHome, + sizeof(szXdgConfigHome), + pcszConfigHome); + if (RT_SUCCESS(vrc)) + vrc = RTPathAppend(szXdgConfigHome, + sizeof(szXdgConfigHome), + "VirtualBox"); + } + else + vrc = RTStrCopy(szXdgConfigHome, + sizeof(szXdgConfigHome), + ".config/VirtualBox"); +#endif + for (unsigned i = 0; i < RT_ELEMENTS(apcszUserHome); ++i) + { + vrc = composeHomePath(aDir, aDirLen, apcszUserHome[i]); + if (RTDirExists(aDir)) + { + fFound = true; + break; + } + } } /* ensure the home directory exists */ if (RT_SUCCESS(vrc)) - if (!RTDirExists(aDir) && fCreateDir) + if (!fFound && fCreateDir) vrc = RTDirCreateFullPath(aDir, 0700); } @@ -242,6 +296,7 @@ static void vboxHeaderFooter(PRTLOGGER pReleaseLogger, RTLOGPHASE enmPhase, PFNR g_pszLogEntity, VBOX_VERSION_STRING, RTBldCfgRevision(), RTBldCfgTargetDotArch(), __DATE__, __TIME__, szTmp); + pfnLog(pReleaseLogger, "Build Type: %s\n", KBUILD_TYPE); int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "OS Product: %s\n", szTmp); @@ -320,7 +375,7 @@ int VBoxLogRelCreate(const char *pcszEntity, const char *pcszLogFile, fFlags |= RTLOGFLAGS_USECRLF; #endif g_pszLogEntity = pcszEntity; - int vrc = RTLogCreateEx(&pReleaseLogger, fFlags, "all all.restrict default.unrestricted", + int vrc = RTLogCreateEx(&pReleaseLogger, fFlags, pcszGroupSettings, pcszEnvVarBase, RT_ELEMENTS(s_apszGroups), s_apszGroups, fDestFlags, vboxHeaderFooter, cHistory, uHistoryFileSize, uHistoryFileTime, pszError, cbError, pcszLogFile); diff --git a/src/VBox/Main/glue/constants-python.xsl b/src/VBox/Main/glue/constants-python.xsl index df18f43b..3795d25e 100644 --- a/src/VBox/Main/glue/constants-python.xsl +++ b/src/VBox/Main/glue/constants-python.xsl @@ -8,7 +8,7 @@ XSLT stylesheet that generates VirtualBox_constants.py from VirtualBox.xidl. - Copyright (C) 2009 Oracle Corporation + Copyright (C) 2009-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -26,79 +26,138 @@ indent="no"/> -# Copyright (C) Oracle Corporation -# -# This file is part of VirtualBox Open Source Edition (OSE), as -# available from http://www.virtualbox.org. This file is free software; -# you can redistribute it and/or modify it under the terms of the GNU -# General Public License (GPL) as published by the Free Software -# Foundation, in version 2 as it comes in the "COPYING" file of the -# VirtualBox OSE distribution. VirtualBox OSE is distributed in the -# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -# -# This file is autogenerated from VirtualBox.xidl, DO NOT EDIT! -# - +# -*- coding: utf-8 -*- + +""" +VirtualBox COM/XPCOM constants. + +This file is autogenerated from VirtualBox.xidl, DO NOT EDIT! +""" + +__copyright__ = \ +""" +Copyright (C) 2009-2013 Oracle Corporation + +This file is part of VirtualBox Open Source Edition (OSE), as +available from http://www.virtualbox.org. This file is free software; +you can redistribute it and/or modify it under the terms of the GNU +General Public License (GPL) as published by the Free Software +Foundation, in version 2 as it comes in the "COPYING" file of the +VirtualBox OSE distribution. VirtualBox OSE is distributed in the +hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +""" + +__version__ = "$Revision: 87223 $"; + + + class VirtualBoxReflectionInfo: - def __init__(self, isSym): - self.isSym = isSym - - _Values = { - '':{ - '':, - }, - - } - - _ValuesSym = { - '':{ - '': '', - }, - - } - - _ValuesFlat = { - - - - - '_':, - - , - } - - _ValuesFlatSym = { - - - - - - - - '': '', - - , - } - - def __getattr__(self,attr): - if self.isSym: - v = self._ValuesFlatSym.get(attr) - else: - v = self._ValuesFlat.get(attr) - if v is not None: - return v - else: - raise AttributeError - - def all_values(self,enum_name): - if self.isSym: - vals = self._ValuesSym.get(enum_name) - else: - vals = self._Values.get(enum_name) - if vals is not None: - return vals - else: - return {} + """ + Enum constants for the various python styles. + """ + + def __init__(self, fIsSym): + self.__fIsSym = fIsSym + __dValues = { + + + + ' ': { + + + ' + ': + , + + + }, + + + } + + __dValuesSym = { + + + ' ': { + + + ' ': ' + + ', + + + }, + + + } + + __dValuesFlat = { + + + + + + + ' _ + ': + , + + + + # Result constants: + + + ' ': + , + + + } + + __dValuesFlatSym = { + + + + + + + + + + ' ': + ' ', + + + + # Result constants: + + + ' ': + '', + + + } + + def __getattr__(self, sAttrName): + if self.__fIsSym: + oValue = self.__dValuesFlatSym.get(sAttrName) + else: + oValue = self.__dValuesFlat.get(sAttrName) + if oValue is None: + raise AttributeError + return oValue + + def all_values(self, sEnumName): + """ Returns a dictionary with all the value names for a given enum type. """ + if self.__fIsSym: + dValues = self.__dValuesSym.get(sEnumName) + else: + dValues = self.__dValues.get(sEnumName) + if dValues is None: + dValues = {} + return dValues + + + diff --git a/src/VBox/Main/glue/errorprint.cpp b/src/VBox/Main/glue/errorprint.cpp index 45979d62..b1b53ee8 100644 --- a/src/VBox/Main/glue/errorprint.cpp +++ b/src/VBox/Main/glue/errorprint.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2009-2010 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/glue/glue-java.xsl b/src/VBox/Main/glue/glue-java.xsl index 0bcc4398..a1f47fc8 100644 --- a/src/VBox/Main/glue/glue-java.xsl +++ b/src/VBox/Main/glue/glue-java.xsl @@ -1,8 +1,8 @@ + xmlns:xsl='http://www.w3.org/1999/XSL/Transform' + xmlns:vbox="http://www.virtualbox.org/" + xmlns:exsl="http://exslt.org/common" + extension-element-prefixes="exsl"> - - - - + + + + - + /* - * Copyright (C) 2010-2011 Oracle Corporation + * Copyright (C) 2010-2014 Oracle Corporation * - * This file is part of the VirtualBox SDK, as available from - * http://www.virtualbox.org. This library is free software; you can - * redistribute it and/or modify it under the terms of the GNU Lesser General - * Public License as published by the Free Software Foundation, in version 2.1 - * as it comes in the "COPYING.LIB" file of the VirtualBox SDK distribution. - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. + * This file is part of the VirtualBox SDK, as available from + * http://www.virtualbox.org. This library is free software; you can + * redistribute it and/or modify it under the terms of the GNU Lesser General + * Public License as published by the Free Software Foundation, in version 2.1 + * as it comes in the "COPYING.LIB" file of the VirtualBox SDK distribution. + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. * - + * * DO NOT EDIT! This is a generated file. @@ -75,39 +74,48 @@ - - - - + + + + + + - - + + - - - - + + + import org.mozilla.interfaces.*; + - - - - + + import com.jacob.com.*; + import com.jacob.activeX.ActiveXComponent; + - - - + + import javax.xml.ws.*; + + + + + + + + - - - + - - + + + + @@ -115,15 +123,23 @@ + - - + + - - - - - + + + + + + + + + + + + @@ -131,6 +147,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -160,18 +218,24 @@ - + + + + + + + - + - + @@ -214,14 +278,14 @@ - + {@link @@ -231,10 +295,15 @@ - + + + + + + - + @@ -254,13 +323,13 @@ - + - + # @@ -268,26 +337,26 @@ - + - + - + - + - + @@ -298,12 +367,12 @@ + Should be replaced in the xidl by multiple without nested tag --> @@ -317,18 +386,18 @@ - /** + /** - + @@ -337,7 +406,7 @@ @@ -347,10 +416,10 @@ <tr> - + - + <td> @@ -363,17 +432,15 @@ - + @@ -386,7 +453,7 @@ @@ -400,11 +467,11 @@ - */ + */ @@ -422,7 +489,7 @@ @@ -438,7 +505,7 @@ @@ -458,7 +525,7 @@ @@ -471,7 +538,7 @@ @@ -480,7 +547,7 @@ @@ -497,47 +564,55 @@ - - - - - - - - - , - - - ; - - - - - - private final int value; - - - value = v; - } - - public int value() { - return value; - } - - - - if (c.value == (int)v) { - return c; - } - } - throw new IllegalArgumentException(Long.toString(v)); - } - - - - + + + + { + + + + + + + , + + + ; + + + - } + + private final int value; + + + { + value = v; + } + + public int value() + { + return value; + } + + + { + + { + if (c.value == (int)v) + { + return c; + } + } + throw new IllegalArgumentException(Long.toString(v)); + } + + + { + + } + } + @@ -546,32 +621,39 @@ - - - + try + { - - - + } + catch (org.mozilla.xpcom.XPCOMException e) + { + throw new VBoxException(e.getMessage(), e); + } - - - + } + catch (com.jacob.com.ComException e) + { + throw new VBoxException(e.getMessage(), e); + } - - - - - + } + catch (InvalidObjectFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); + } + catch (RuntimeFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); + } @@ -587,15 +669,15 @@ - + - + com.jacob.com.Dispatch - + String @@ -611,19 +693,20 @@ - - - - - - - - + + + + + + + + + - - + + @@ -636,14 +719,14 @@ - + List - + < - + @@ -664,11 +747,11 @@ - + > - + [] @@ -687,43 +770,43 @@ - + long - + long - + int - + int - + short - + byte - + boolean - + nsISupports - + String - + String @@ -739,7 +822,7 @@ - + long @@ -750,27 +833,27 @@ - + [] - + Variant - + List< - + String - + String @@ -783,51 +866,51 @@ - + /*base64*/String - + Long - + Long - + Integer - + Integer - + Short - + Boolean - + String - + String - + - + > @@ -875,16 +958,16 @@ - + - + - + @@ -893,12 +976,12 @@ - + - + - + @@ -907,7 +990,7 @@ - + @@ -943,54 +1026,54 @@ - + - + - + - + - + - - + + - + - - + + - + - + - + - + @@ -1035,19 +1118,19 @@ - + - + - + - + - + @@ -1055,7 +1138,7 @@ - + @@ -1085,15 +1168,15 @@ - + - + - + @@ -1177,21 +1260,21 @@ - + - + - - + + - + - + @@ -1199,10 +1282,10 @@ - + - + @@ -1216,19 +1299,19 @@ - + - + - + - + - + @@ -1283,21 +1366,21 @@ - + - + - - + + - + - + @@ -1305,10 +1388,10 @@ - + - + @@ -1316,10 +1399,10 @@ - + - + @@ -1327,10 +1410,10 @@ - + - + @@ -1339,10 +1422,10 @@ - + - + @@ -1350,10 +1433,10 @@ - + - + @@ -1361,16 +1444,16 @@ - + - + - + @@ -1407,49 +1490,49 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1496,150 +1579,150 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + null + + + + + null, + + + + + + + + + + + + - - - - - + + + + + + + + + + + , + - + ); - + - + - + , - - - - - - - - - - - - - + + + + + + + + + + + + + - + ); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + obj + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + , + + + + + ); + @@ -1657,35 +1740,33 @@ + + + + null + + ); + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -1695,104 +1776,111 @@ - - - + + + - - - + + + - + - - - - - - - - + + + + + + + - - + + private VboxPortType port; - + + { + this.real = real; + this.port = port; + } - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + { + + + + + + + + + + } + @@ -1805,9 +1893,10 @@ - - - + + + + @@ -1830,10 +1919,10 @@ - + retVal.value - + retVal @@ -1856,10 +1945,11 @@ - + , - + ) + { @@ -1873,13 +1963,13 @@ - + - + - + @@ -1904,7 +1994,7 @@ '>(); ')"/> - + @@ -1916,18 +2006,18 @@ - + - + - + - + @@ -1943,7 +2033,7 @@ - + @@ -1959,7 +2049,7 @@ - + } @@ -1972,9 +2062,7 @@ - - - + @@ -2013,7 +2101,7 @@ , - + ); @@ -2023,7 +2111,8 @@ - + + { @@ -2031,9 +2120,9 @@ - - - + nsISupports nsobj = obj != null ? (nsISupports)obj.getWrapped() : null; + if (nsobj == null) return null; + @@ -2053,7 +2142,7 @@ - + } @@ -2063,9 +2152,7 @@ - - - + @@ -2102,7 +2189,7 @@ - + @@ -2111,7 +2198,8 @@ , - + ) + { @@ -2121,8 +2209,8 @@ - - + Variant _args[]) + { @@ -2130,16 +2218,15 @@ - + - - - - - - + + + + + @@ -2165,50 +2252,50 @@ - + - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + + + + + + + , + - + ); - + - + - + - + @@ -2224,7 +2311,7 @@ - + } @@ -2242,20 +2329,23 @@ - - - + + { + super(wrapped, port); + } - - - + + { + super(wrapped); + } - - - + + { + + } @@ -2268,12 +2358,14 @@ - - + + + + @@ -2303,7 +2395,8 @@ - + + { @@ -2315,11 +2408,11 @@ - + - - + } + @@ -2331,7 +2424,8 @@ - + + { @@ -2340,7 +2434,7 @@ - + } @@ -2375,41 +2469,46 @@ - import java.util.List; + + import java.util.List; - + - - - - - - - + + + + { + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + { + + + + { + + + + + + + + + + + + - - + + } + @@ -2429,7 +2528,8 @@ import java.util.List; - + + { @@ -2439,7 +2539,7 @@ - + } @@ -2461,19 +2561,22 @@ - + + { - + + { - - - + + { + this.sink = sink; + } @@ -2483,7 +2586,7 @@ - + } @@ -2492,298 +2595,376 @@ - + - + { - public T value; - - public Holder() - { - } - public Holder(T value) - { - this.value = value; - } -} -]]> - - - - - - - - - + public T value; - + - - - - - + + + - + - + + - - - + + + - - - - + + + + - + wrap(byte[] vals) { - if (vals==null) +public class Helper +{ + public static List wrap(byte[] values) + { + if (values == null) return null; - List ret = new ArrayList(vals.length); - for (short v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (short v : values) + { + ret.add(v); } return ret; } - public static List wrap(int[] vals) { - if (vals==null) - return null; + public static List wrap(short[] values) + { + if (values == null) + return null; - List ret = new ArrayList(vals.length); - for (int v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (short v : values) + { + ret.add(v); } return ret; } - public static List wrap(long[] vals) { - if (vals==null) - return null; + public static List wrap(int[] values) + { + if (values == null) + return null; - List ret = new ArrayList(vals.length); - for (long v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (int v : values) + { + ret.add(v); } return ret; } - public static List wrap(String[] vals) { - if (vals==null) + public static List wrap(long[] values) + { + if (values == null) return null; - List ret = new ArrayList(vals.length); - for (String v : vals) { + + List ret = new ArrayList(values.length); + for (long v : values) + { ret.add(v); } return ret; } - public static List wrap(Class wrapperClass, T[] thisPtrs) { - if (thisPtrs==null) - return null; + public static List wrap(boolean[] values) + { + if (values == null) + return null; - List ret = new ArrayList(thisPtrs.length); - for (T thisPtr : thisPtrs) { - ret.add(thisPtr); + List ret = new ArrayList(values.length); + for (boolean v: values) + { + ret.add(v); } return ret; } - public static List wrapEnum(Class wrapperClass, long values[]) { - try { - if (values==null) - return null; - Constructor c = wrapperClass.getConstructor(int.class); + public static List wrap(String[] values) + { + if (values == null) + return null; + + List ret = new ArrayList(values.length); + for (String v : values) + { + ret.add(v); + } + return ret; + } + + public static List wrap(Class wrapperClass, T[] values) + { + if (values == null) + return null; + + List ret = new ArrayList(values.length); + for (T v : values) + { + ret.add(v); + } + return ret; + } + + @SuppressWarnings( "unchecked") + public static List wrapEnum(Class wrapperClass, long values[]) + { + try + { + if (values == null) + return null; + //// This code is questionable, as it invokes a private constructor + //// (all enums only have default constructors), and we don't really + //// know what to pass as the name, and the ordinal may or may not + //// be sensible, especially if the long was abused as a bitset. + //Constructor c = wrapperClass.getDeclaredConstructor(String.class, int.class, int.class); + //c.setAccessible(true); // make it callable + //List ret = new ArrayList(values.length); + //for (long v : values) + //{ + // T convEnum = c.newInstance("unknown", (int)v, (int)v); + // ret.add(convEnum); + //} + + // Alternative implementation: use the fromValue method, which is + // what the code handling single enums will do. I see no reason to + // use the above very ugly hack if there are better alternatives, + // which as a bonus complain about unknown values. This variant is + // slower, but also orders of magnitude safer. + java.lang.reflect.Method fromValue = wrapperClass.getMethod("fromValue", long.class); List ret = new ArrayList(values.length); - for (long v : values) { - ret.add(c.newInstance(v)); + for (long v : values) + { + T convEnum = (T)fromValue.invoke(null, v); + ret.add(convEnum); } return ret; - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + //catch (InstantiationException e) + //{ + // throw new AssertionError(e); + //} + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } - public static short[] unwrapUShort(List vals) { - if (vals==null) - return null; + public static short[] unwrapUShort(List values) + { + if (values == null) + return null; - short[] ret = new short[vals.size()]; + short[] ret = new short[values.size()]; int i = 0; - for (short l : vals) { - ret[i++] = l; + for (short l : values) + { + ret[i++] = l; } return ret; } - public static int[] unwrapInteger(List vals) { - if (vals == null) - return null; + public static int[] unwrapInteger(List values) + { + if (values == null) + return null; - int[] ret = new int[vals.size()]; + int[] ret = new int[values.size()]; int i = 0; - for (int l : vals) { - ret[i++] = l; + for (int l : values) + { + ret[i++] = l; } return ret; } - public static long[] unwrapULong(List vals) { - if (vals == null) - return null; + public static long[] unwrapULong(List values) + { + if (values == null) + return null; - long[] ret = new long[vals.size()]; + long[] ret = new long[values.size()]; int i = 0; - for (long l : vals) { - ret[i++] = l; + for (long l : values) + { + ret[i++] = l; } return ret; } - public static boolean[] unwrapBoolean(List vals) { - if (vals==null) - return null; + public static boolean[] unwrapBoolean(List values) + { + if (values == null) + return null; - boolean[] ret = new boolean[vals.size()]; + boolean[] ret = new boolean[values.size()]; int i = 0; - for (boolean l : vals) { - ret[i++] = l; + for (boolean l : values) + { + ret[i++] = l; } return ret; } - public static String[] unwrapStr(List vals) { - if (vals==null) + public static String[] unwrapStr(List values) + { + if (values == null) return null; - String[] ret = new String[vals.size()]; + String[] ret = new String[values.size()]; int i = 0; - for (String l : vals) { - ret[i++] = l; + for (String l : values) + { + ret[i++] = l; } return ret; } - public static > long[] unwrapEnum(Class enumClass, List values) { - if (values == null) return null; + public static > long[] unwrapEnum(Class enumClass, List values) + { + if (values == null) + return null; long result[] = new long[values.size()]; - try { - java.lang.reflect.Method valueM = enumClass.getMethod("value"); - int i = 0; - for (T v : values) { - result[i++] = (Integer)valueM.invoke(v); - } - return result; - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } catch(SecurityException e) { - throw new AssertionError(e); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } catch (IllegalArgumentException e) { - throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw new AssertionError(e); + try + { + java.lang.reflect.Method valueM = enumClass.getMethod("value"); + int i = 0; + for (T v : values) + { + result[i++] = (Integer)valueM.invoke(v); + } + return result; + } + catch (NoSuchMethodException e) + { + throw new AssertionError(e); + } + catch(SecurityException e) + { + throw new AssertionError(e); + } + catch (IllegalAccessException e) + { + throw new AssertionError(e); + } + catch (IllegalArgumentException e) + { + throw new AssertionError(e); + } + catch (InvocationTargetException e) + { + throw new AssertionError(e); } } - public static List wrap2(Class wrapperClass1, Class wrapperClass2, T2[] thisPtrs) { - try { - if (thisPtrs==null) + public static List wrap2(Class wrapperClass1, Class wrapperClass2, T2[] values) + { + try + { + if (values == null) return null; Constructor c = wrapperClass1.getConstructor(wrapperClass2); - List ret = new ArrayList(thisPtrs.length); - for (T2 thisPtr : thisPtrs) { - ret.add(c.newInstance(thisPtr)); + List ret = new ArrayList(values.length); + for (T2 v : values) + { + ret.add(c.newInstance(v)); } return ret; - } catch (NoSuchMethodException e) { + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (InstantiationException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } @SuppressWarnings( "unchecked") - public static T[] unwrap(Class wrapperClass, List thisPtrs) { - if (thisPtrs==null) + public static T[] unwrap(Class wrapperClass, List values) + { + if (values == null) return null; - if (thisPtrs.size() == 0) + if (values.size() == 0) return null; - return (T[])thisPtrs.toArray((T[])Array.newInstance(wrapperClass, thisPtrs.size())); + return (T[])values.toArray((T[])Array.newInstance(wrapperClass, values.size())); } @SuppressWarnings( "unchecked" ) @@ -2794,40 +2975,112 @@ public class Helper { public static Object queryInterface(Object obj, String uuid) { - try { + try + { /* Kind of ugly, but does the job of casting */ org.mozilla.xpcom.Mozilla moz = org.mozilla.xpcom.Mozilla.getInstance(); long xpobj = moz.wrapJavaObject(obj, uuid); return moz.wrapXPCOMObject(xpobj, uuid); - } catch (Exception e) { - return null; - } + } + catch (Exception e) + { + return null; + } } @SuppressWarnings("unchecked") - public static T2[] unwrap2(Class wrapperClass1, Class wrapperClass2, List thisPtrs) { - if (thisPtrs==null) return null; + public static T2[] unwrap2(Class wrapperClass1, Class wrapperClass2, List values) + { + if (values == null) + return null; - T2 ret[] = (T2[])Array.newInstance(wrapperClass2, thisPtrs.size()); + T2 ret[] = (T2[])Array.newInstance(wrapperClass2, values.size()); int i = 0; - for (T1 obj : thisPtrs) { - ret[i++] = (T2)obj.getWrapped(); + for (T1 obj : values) + { + ret[i++] = (T2)obj.getWrapped(); } return ret; } } ]]> + + + + + + + + + + + + + +import org.mozilla.xpcom.*; + +public class VBoxException extends RuntimeException +{ + private int resultCode; + private IVirtualBoxErrorInfo errorInfo; - - - + public VBoxException(String message) + { + super(message); + resultCode = -1; + errorInfo = null; + } + + public VBoxException(String message, Throwable cause) + { + super(message, cause); + if (cause instanceof org.mozilla.xpcom.XPCOMException) + { + resultCode = (int)((org.mozilla.xpcom.XPCOMException)cause).errorcode; + try + { + Mozilla mozilla = Mozilla.getInstance(); + nsIServiceManager sm = mozilla.getServiceManager(); + nsIExceptionService es = (nsIExceptionService)sm.getServiceByContractID("@mozilla.org/exceptionservice;1", nsIExceptionService.NS_IEXCEPTIONSERVICE_IID); + nsIExceptionManager em = es.getCurrentExceptionManager(); + nsIException ex = em.getCurrentException(); + errorInfo = new IVirtualBoxErrorInfo((org.mozilla.interfaces.IVirtualBoxErrorInfo)ex.queryInterface(org.mozilla.interfaces.IVirtualBoxErrorInfo.IVIRTUALBOXERRORINFO_IID)); + } + catch (NullPointerException e) + { + e.printStackTrace(); + // nothing we can do + errorInfo = null; + } + } + else + resultCode = -1; + } + + public int getResultCode() + { + return resultCode; + } + + public IVirtualBoxErrorInfo getVirtualBoxErrorInfo() + { + return errorInfo; + } +} + + + + + + - + - + = end) - return false; - } - - return true; - } - - public boolean startVm(String name, String type, int timeout) - { - IMachine m = vbox.findMachine(name); - if (m == null) - return false; - ISession session = getSessionObject(); - - if (type == null) - type = "gui"; - IProgress p = m.launchVMProcess(session, type, ""); - progressBar(p, timeout); - session.unlockMachine(); - return true; - } - public void waitForEvents(long tmo) { mozilla.waitForEvents(tmo); } } ]]> + - - - + + + - - - - + + + + - + - - - - - - - - - - - + + + + + + + + + + + + + - - +]]> + + + + - + - + + - - - + + + - - - - + + + + - + wrap(short[] vals) { - if (vals==null) return null; - if (vals.length == 0) return Collections.emptyList(); +public class Helper +{ + public static List wrap(short[] values) + { + if (values == null) + return null; + if (values.length == 0) + return Collections.emptyList(); - List ret = new ArrayList(vals.length); - for (short v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (short v : values) + { + ret.add(v); } return ret; } - public static List wrap(int[] vals) { - if (vals == null) return null; - if (vals.length == 0) return Collections.emptyList(); + public static List wrap(int[] values) + { + if (values == null) + return null; + if (values.length == 0) + return Collections.emptyList(); - List ret = new ArrayList(vals.length); - for (int v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (int v : values) + { + ret.add(v); } return ret; } - public static List wrap(long[] vals) { - if (vals==null) return null; - if (vals.length == 0) return Collections.emptyList(); + public static List wrap(long[] values) + { + if (values == null) + return null; + if (values.length == 0) + return Collections.emptyList(); - List ret = new ArrayList(vals.length); - for (long v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (long v : values) + { + ret.add(v); } return ret; } - public static List wrap(String[] vals) { - if (vals==null) return null; - if (vals.length == 0) return Collections.emptyList(); + public static List wrap(String[] values) + { + if (values == null) + return null; + if (values.length == 0) + return Collections.emptyList(); - List ret = new ArrayList(vals.length); - for (String v : vals) { - ret.add(v); + List ret = new ArrayList(values.length); + for (String v : values) + { + ret.add(v); } return ret; } public static T wrapDispatch(Class wrapperClass, Dispatch d) { - try { - if (d == null || d.m_pDispatch == 0) - return null; - Constructor c = wrapperClass.getConstructor(Dispatch.class); - return (T)c.newInstance(d); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } catch (InstantiationException e) { - throw new AssertionError(e); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw new AssertionError(e); - } + try + { + if (d == null || d.m_pDispatch == 0) + return null; + Constructor c = wrapperClass.getConstructor(Dispatch.class); + return (T)c.newInstance(d); + } + catch (NoSuchMethodException e) + { + throw new AssertionError(e); + } + catch (InstantiationException e) + { + throw new AssertionError(e); + } + catch (IllegalAccessException e) + { + throw new AssertionError(e); + } + catch (InvocationTargetException e) + { + throw new AssertionError(e); + } } @SuppressWarnings("unchecked") public static Object wrapVariant(Class wrapperClass, Variant v) { - if (v == null) - return null; - - short vt = v.getvt(); - switch (vt) - { - case Variant.VariantNull: - return null; - case Variant.VariantBoolean: - return v.getBoolean(); - case Variant.VariantByte: - return v.getByte(); - case Variant.VariantShort: - return v.getShort(); - case Variant.VariantInt: - return v.getInt(); - case Variant.VariantLongInt: - return v.getLong(); - case Variant.VariantString: - return v.getString(); - case Variant.VariantDispatch: - return wrapDispatch(wrapperClass, v.getDispatch()); - default: - throw new RuntimeException("unhandled variant type "+vt); - } + if (v == null) + return null; + + short vt = v.getvt(); + switch (vt) + { + case Variant.VariantNull: + return null; + case Variant.VariantBoolean: + return v.getBoolean(); + case Variant.VariantByte: + return v.getByte(); + case Variant.VariantShort: + return v.getShort(); + case Variant.VariantInt: + return v.getInt(); + case Variant.VariantLongInt: + return v.getLong(); + case Variant.VariantString: + return v.getString(); + case Variant.VariantDispatch: + return wrapDispatch(wrapperClass, v.getDispatch()); + default: + throw new VBoxException("unhandled variant type " + vt); + } } - public static byte[] wrapBytes(SafeArray sa) { - if (sa==null) return null; + public static byte[] wrapBytes(SafeArray sa) + { + if (sa == null) + return null; int saLen = sa.getUBound() - sa.getLBound() + 1; @@ -3186,168 +3457,229 @@ public class Helper { int j = 0; for (int i = sa.getLBound(); i <= sa.getUBound(); i++) { - Variant v = sa.getVariant(i); - // come upo with more effective approach!!! - ret[j++] = v.getByte(); + Variant v = sa.getVariant(i); + // come up with more effective approach!!! + ret[j++] = v.getByte(); } return ret; } @SuppressWarnings("unchecked") - public static List wrap(Class wrapperClass, SafeArray sa) { - if (sa==null) return null; + public static List wrap(Class wrapperClass, SafeArray sa) + { + if (sa == null) + return null; int saLen = sa.getUBound() - sa.getLBound() + 1; - if (saLen == 0) return Collections.emptyList(); + if (saLen == 0) + return Collections.emptyList(); List ret = new ArrayList(saLen); for (int i = sa.getLBound(); i <= sa.getUBound(); i++) { - Variant v = sa.getVariant(i); - ret.add((T)wrapVariant(wrapperClass, v)); + Variant v = sa.getVariant(i); + ret.add((T)wrapVariant(wrapperClass, v)); } return ret; } - public static List wrapEnum(Class wrapperClass, SafeArray sa) { - try { - if (sa==null) return null; - - int saLen = sa.getUBound() - sa.getLBound() + 1; - if (saLen == 0) return Collections.emptyList(); - List ret = new ArrayList(saLen); - Constructor c = wrapperClass.getConstructor(int.class); - for (int i = sa.getLBound(); i <= sa.getUBound(); i++) - { - Variant v = sa.getVariant(i); - ret.add(c.newInstance(v.getInt())); - } - return ret; - } catch (NoSuchMethodException e) { + public static List wrapEnum(Class wrapperClass, SafeArray sa) + { + try + { + if (sa == null) + return null; + + int saLen = sa.getUBound() - sa.getLBound() + 1; + if (saLen == 0) + return Collections.emptyList(); + List ret = new ArrayList(saLen); + Constructor c = wrapperClass.getConstructor(int.class); + for (int i = sa.getLBound(); i <= sa.getUBound(); i++) + { + Variant v = sa.getVariant(i); + ret.add(c.newInstance(v.getInt())); + } + return ret; + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (InstantiationException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } - public static SafeArray unwrapInt(List vals) { - if (vals==null) return null; - SafeArray ret = new SafeArray(Variant.VariantInt, vals.size()); + public static SafeArray unwrapInt(List values) + { + if (values == null) + return null; + SafeArray ret = new SafeArray(Variant.VariantInt, values.size()); int i = 0; - for (int l : vals) { - ret.setInt(i++, l); + for (int l : values) + { + ret.setInt(i++, l); } return ret; } - public static SafeArray unwrapLong(List vals) { - if (vals==null) return null; - SafeArray ret = new SafeArray(Variant.VariantLongInt, vals.size()); + public static SafeArray unwrapLong(List values) + { + if (values == null) + return null; + SafeArray ret = new SafeArray(Variant.VariantLongInt, values.size()); int i = 0; - for (long l : vals) { - ret.setLong(i++, l); + for (long l : values) + { + ret.setLong(i++, l); } return ret; } - public static SafeArray unwrapBool(List vals) { - if (vals==null) return null; + public static SafeArray unwrapBool(List values) + { + if (values == null) + return null; - SafeArray result = new SafeArray(Variant.VariantBoolean, vals.size()); + SafeArray result = new SafeArray(Variant.VariantBoolean, values.size()); int i = 0; - for (boolean l : vals) { - result.setBoolean(i++, l); + for (boolean l : values) + { + result.setBoolean(i++, l); } return result; } - public static SafeArray unwrapBytes(byte[] vals) { - if (vals==null) return null; + public static SafeArray unwrapBytes(byte[] values) + { + if (values == null) + return null; - SafeArray result = new SafeArray(Variant.VariantByte, vals.length); + SafeArray result = new SafeArray(Variant.VariantByte, values.length); int i = 0; - for (byte l : vals) { - result.setByte(i++, l); + for (byte l : values) + { + result.setByte(i++, l); } return result; } - public static > SafeArray unwrapEnum(Class enumClass, List values) { - if (values == null) return null; + public static > SafeArray unwrapEnum(Class enumClass, List values) + { + if (values == null) + return null; SafeArray result = new SafeArray(Variant.VariantInt, values.size()); - try { - java.lang.reflect.Method valueM = enumClass.getMethod("value"); - int i = 0; - for (T v : values) { - result.setInt(i++, (Integer)valueM.invoke(v)); - } - return result; - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } catch(SecurityException e) { - throw new AssertionError(e); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } catch (IllegalArgumentException e) { - throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw new AssertionError(e); + try + { + java.lang.reflect.Method valueM = enumClass.getMethod("value"); + int i = 0; + for (T v : values) + { + result.setInt(i++, (Integer)valueM.invoke(v)); + } + return result; + } + catch (NoSuchMethodException e) + { + throw new AssertionError(e); + } + catch(SecurityException e) + { + throw new AssertionError(e); + } + catch (IllegalAccessException e) + { + throw new AssertionError(e); + } + catch (IllegalArgumentException e) + { + throw new AssertionError(e); + } + catch (InvocationTargetException e) + { + throw new AssertionError(e); } } - public static SafeArray unwrapString(List vals) { - if (vals==null) - return null; - SafeArray result = new SafeArray(Variant.VariantString, vals.size()); + public static SafeArray unwrapString(List values) + { + if (values == null) + return null; + SafeArray result = new SafeArray(Variant.VariantString, values.size()); int i = 0; - for (String l : vals) { - result.setString(i++, l); + for (String l : values) + { + result.setString(i++, l); } return result; } - public static List wrap2(Class wrapperClass1, Class wrapperClass2, T2[] thisPtrs) { - try { - if (thisPtrs==null) return null; - if (thisPtrs.length == 0) return Collections.emptyList(); + public static List wrap2(Class wrapperClass1, Class wrapperClass2, T2[] values) + { + try + { + if (values == null) + return null; + if (values.length == 0) + return Collections.emptyList(); Constructor c = wrapperClass1.getConstructor(wrapperClass2); - List ret = new ArrayList(thisPtrs.length); - for (T2 thisPtr : thisPtrs) { - ret.add(c.newInstance(thisPtr)); + List ret = new ArrayList(values.length); + for (T2 v : values) + { + ret.add(c.newInstance(v)); } return ret; - } catch (NoSuchMethodException e) { + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (InstantiationException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } @SuppressWarnings("unchecked") - public static T[] unwrap(Class wrapperClass, List thisPtrs) { - if (thisPtrs==null) return null; - return (T[])thisPtrs.toArray((T[])Array.newInstance(wrapperClass, thisPtrs.size())); + public static T[] unwrap(Class wrapperClass, List values) + { + if (values == null) + return null; + return (T[])values.toArray((T[])Array.newInstance(wrapperClass, values.size())); } @SuppressWarnings("unchecked") - public static T2[] unwrap2(Class wrapperClass1, Class wrapperClass2, List thisPtrs) { - if (thisPtrs==null) return null; + public static T2[] unwrap2(Class wrapperClass1, Class wrapperClass2, List values) + { + if (values == null) + return null; - T2 ret[] = (T2[])Array.newInstance(wrapperClass2, thisPtrs.size()); + T2 ret[] = (T2[])Array.newInstance(wrapperClass2, values.size()); int i = 0; - for (T1 obj : thisPtrs) { - ret[i++] = (T2)obj.getWrapped(); + for (T1 obj : values) + { + ret[i++] = (T2)obj.getWrapped(); } return ret; } @@ -3359,18 +3691,72 @@ public class Helper { } } ]]> + + + + + + + + + + - - - + + +public class VBoxException extends RuntimeException +{ + private int resultCode; + private IVirtualBoxErrorInfo errorInfo; + + public VBoxException(String message) + { + super(message); + resultCode = -1; + errorInfo = null; + } + + public VBoxException(String message, Throwable cause) + { + super(message, cause); + if (cause instanceof com.jacob.com.ComException) + { + resultCode = ((com.jacob.com.ComException)cause).getHResult(); + // JACOB doesn't support calling GetErrorInfo, which + // means there is no way of getting an IErrorInfo reference, + // and that means no way of getting to IVirtualBoxErrorInfo. + errorInfo = null; + } + else + resultCode = -1; + } - + public int getResultCode() + { + return resultCode; + } + + public IVirtualBoxErrorInfo getVirtualBoxErrorInfo() + { + return errorInfo; + } +} + + + + + + + + + - + = end) - return false; - } - - return true; - } - - public boolean startVm(String name, String type, int timeout) - { - IMachine m = vbox.findMachine(name); - if (m == null) - return false; - ISession session = getSessionObject(); - if (type == null) - type = "gui"; - IProgress p = m.launchVMProcess(session, type, ""); - progressBar(p, timeout); - session.unlockMachine(); - return true; - } - public void waitForEvents(long tmo) { // what to do here? - try { + try + { Thread.sleep(tmo); - } catch (InterruptedException ie) { + } + catch (InterruptedException ie) + { } } } ]]> + - - - - + + + @@ -3500,55 +3862,63 @@ public class VirtualBoxManager - + + - - - + + + - - - - + + + + - + List wrap(Class wrapperClass, VboxPortType pt, List thisPtrs) { - try { - if(thisPtrs==null) return null; +public class Helper +{ + public static List wrap(Class wrapperClass, VboxPortType pt, List values) + { + try + { + if (values == null) + return null; Constructor c = wrapperClass.getConstructor(String.class, VboxPortType.class); - List ret = new ArrayList(thisPtrs.size()); - for (String thisPtr : thisPtrs) { - ret.add(c.newInstance(thisPtr,pt)); + List ret = new ArrayList(values.size()); + for (String v : values) + { + ret.add(c.newInstance(v, pt)); } return ret; - } catch (NoSuchMethodException e) { + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (InstantiationException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } - public static List wrap2(Class wrapperClass1, Class wrapperClass2, VboxPortType pt, List thisPtrs) { - try { - if(thisPtrs==null) return null; + public static List wrap2(Class wrapperClass1, Class wrapperClass2, VboxPortType pt, List values) + { + try + { + if (values == null) + return null; Constructor c = wrapperClass1.getConstructor(wrapperClass2, VboxPortType.class); - List ret = new ArrayList(thisPtrs.size()); - for (T2 thisPtr : thisPtrs) { - ret.add(c.newInstance(thisPtr,pt)); + List ret = new ArrayList(values.size()); + for (T2 v : values) + { + ret.add(c.newInstance(v, pt)); } return ret; - } catch (NoSuchMethodException e) { + } + catch (NoSuchMethodException e) + { throw new AssertionError(e); - } catch (InstantiationException e) { + } + catch (InstantiationException e) + { throw new AssertionError(e); - } catch (IllegalAccessException e) { + } + catch (IllegalAccessException e) + { throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (InvocationTargetException e) + { throw new AssertionError(e); } } - public static List unwrap(List thisPtrs) { - if (thisPtrs==null) return null; + public static List unwrap(List values) + { + if (values == null) + return null; - List ret = new ArrayList(thisPtrs.size()); - for (T obj : thisPtrs) { + List ret = new ArrayList(values.size()); + for (T obj : values) + { ret.add(obj.getWrapped()); } return ret; @@ -3614,22 +4012,25 @@ public class Helper { @SuppressWarnings("unchecked" ) public static , T2 extends Enum > List convertEnums(Class fromClass, Class toClass, - List values) { - try { - if (values==null) - return null; - java.lang.reflect.Method fromValue = toClass.getMethod("fromValue", String.class); + List values) + { + try + { + if (values == null) + return null; List ret = new ArrayList(values.size()); - for (T1 v : values) { - // static method is called with null this - ret.add((T2)fromValue.invoke(null, v.name())); + for (T1 v : values) + { + // Ordinal based enum conversion, as JAX-WS "invents" its own + // enum names and has string values with the expected content. + int enumOrdinal = v.ordinal(); + T2 convEnum = toClass.getEnumConstants()[enumOrdinal]; + ret.add(convEnum); } return ret; - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } catch (InvocationTargetException e) { + } + catch (ArrayIndexOutOfBoundsException e) + { throw new AssertionError(e); } } @@ -3645,7 +4046,7 @@ public class Helper { charToVal[i] = -1; for (int i = 0; i < valToChar.length; i++) - charToVal[valToChar[i]] = i; + charToVal[valToChar[i]] = i; charToVal['='] = 0; } @@ -3699,7 +4100,7 @@ public class Helper { break; } default: - throw new RuntimeException("bug!"); + throw new VBoxException("bug!"); } return new String(result); @@ -3735,7 +4136,7 @@ public class Helper { } if ((validChars * 3 % 4) != 0) - throw new RuntimeException("invalid encoded string "+str); + throw new VBoxException("invalid base64 encoded string " + str); int resultLength = validChars * 3 / 4 - padChars; byte[] result = new byte[resultLength]; @@ -3743,7 +4144,7 @@ public class Helper { int dataIndex = 0, stringIndex = 0; int quadraplets = validChars / 4; - for (int i=0; i + + + + + + + + + + + + + +public class VBoxException extends RuntimeException +{ + private int resultCode; + private IVirtualBoxErrorInfo errorInfo; - - - + public VBoxException(String message) + { + super(message); + resultCode = -1; + errorInfo = null; + } + + public VBoxException(String message, Throwable cause) + { + super(message, cause); + resultCode = -1; + errorInfo = null; + } + + public VBoxException(String message, Throwable cause, VboxPortType port) + { + super(message, cause); + if (cause instanceof RuntimeFaultMsg) + { + RuntimeFaultMsg m = (RuntimeFaultMsg)cause; + RuntimeFault f = m.getFaultInfo(); + resultCode = f.getResultCode(); + String retVal = f.getReturnval(); + errorInfo = (retVal.length() > 0) ? new IVirtualBoxErrorInfo(retVal, port) : null; + } + else + resultCode = -1; + } - + public int getResultCode() + { + return resultCode; + } + + public IVirtualBoxErrorInfo getVirtualBoxErrorInfo() + { + return errorInfo; + } +} + + + + + + + + - + -import java.net.URL; + + import java.net.URL; import java.math.BigInteger; import java.util.List; import java.util.Map; @@ -3788,10 +4249,10 @@ import javax.xml.ws.WebServiceException; class PortPool { - private final static String wsdlFile = ; - - known; + private final static String wsdlFile = + + known; private boolean initStarted; private VboxService svc; @@ -3801,32 +4262,35 @@ private Map known; if (usePreinit) { - new Thread(new Runnable() - { - public void run() - { - // need to sync on something else but 'this' - synchronized (known) + new Thread(new Runnable() + { + public void run() { - initStarted = true; - known.notify(); + // need to sync on something else but 'this' + synchronized (known) + { + initStarted = true; + known.notify(); + } + + preinit(); } + }).start(); - preinit(); - } - }).start(); - - synchronized (known) - { - while (!initStarted) - { - try { - known.wait(); - } catch (InterruptedException e) { - break; - } - } - } + synchronized (known) + { + while (!initStarted) + { + try + { + known.wait(); + } + catch (InterruptedException e) + { + break; + } + } + } } } @@ -3854,10 +4318,11 @@ private Map known; if (port == null) { - if (svc == null) { + if (svc == null) + { URL wsdl = PortPool.class.getClassLoader().getResource(wsdlFile); if (wsdl == null) - throw new LinkageError(wsdlFile+" not found, but it should have been in the jar"); + throw new LinkageError(wsdlFile + " not found, but it should have been in the jar"); svc = new VboxService(wsdl, new QName("http://www.virtualbox.org/Service", "vboxService")); @@ -3901,7 +4366,7 @@ public class VirtualBoxManager private static PortPool pool = new PortPool(true); protected VboxPortType port; - private IVirtualBox vbox; + private IVirtualBox vbox; private VirtualBoxManager() { @@ -3918,18 +4383,22 @@ public class VirtualBoxManager public void connect(String url, String username, String passwd) { this.port = pool.getPort(); - try { + try + { ((BindingProvider)port).getRequestContext(). put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url); String handle = port.iWebsessionManagerLogon(username, passwd); this.vbox = new IVirtualBox(handle, port); - } catch (Throwable t) { - if (this.port != null && pool != null) { + } + catch (Throwable t) + { + if (this.port != null && pool != null) + { pool.releasePort(this.port); this.port = null; } // we have to throw smth derived from RuntimeException - throw new VBoxException(t, t.getMessage()); + throw new VBoxException(t.getMessage(), t, this.port); } } @@ -3938,7 +4407,8 @@ public class VirtualBoxManager { this.port = pool.getPort(); - try { + try + { ((BindingProvider)port).getRequestContext(); if (requestContext != null) ((BindingProvider)port).getRequestContext().putAll(requestContext); @@ -3950,27 +4420,41 @@ public class VirtualBoxManager put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url); String handle = port.iWebsessionManagerLogon(username, passwd); this.vbox = new IVirtualBox(handle, port); - } catch (Throwable t) { - if (this.port != null && pool != null) { + } + catch (Throwable t) + { + if (this.port != null && pool != null) + { pool.releasePort(this.port); this.port = null; } // we have to throw smth derived from RuntimeException - throw new VBoxException(t, t.getMessage()); + throw new VBoxException(t.getMessage(), t, this.port); } } public void disconnect() { - try { - if (this.vbox != null) - port.iWebsessionManagerLogoff(this.vbox.getWrapped()); - } catch (InvalidObjectFaultMsg e) { - throw new VBoxException(e, e.getMessage()); - } catch (RuntimeFaultMsg e) { - throw new VBoxException(e, e.getMessage()); - } finally { - if (this.port != null) { + if (this.port == null) + return; + + try + { + if (this.vbox != null && port != null) + port.iWebsessionManagerLogoff(this.vbox.getWrapped()); + } + catch (InvalidObjectFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); + } + catch (RuntimeFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); + } + finally + { + if (this.port != null) + { pool.releasePort(this.port); this.port = null; } @@ -3985,14 +4469,19 @@ public class VirtualBoxManager public ISession getSessionObject() { if (this.vbox == null) - throw new RuntimeException("connect first"); - try { - String handle = port.iWebsessionManagerGetSessionObject(this.vbox.getWrapped()); - return new ISession(handle, port); - } catch (InvalidObjectFaultMsg e) { - throw new VBoxException(e, e.getMessage()); - } catch (RuntimeFaultMsg e) { - throw new VBoxException(e, e.getMessage()); + throw new VBoxException("connect first"); + try + { + String handle = port.iWebsessionManagerGetSessionObject(this.vbox.getWrapped()); + return new ISession(handle, port); + } + catch (InvalidObjectFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); + } + catch (RuntimeFaultMsg e) + { + throw new VBoxException(e.getMessage(), e, this.port); } } @@ -4016,63 +4505,40 @@ public class VirtualBoxManager public IEventListener createListener(Object sink) { - throw new RuntimeException("no active listeners here"); + throw new VBoxException("no active listeners here"); } + public void cleanup() { disconnect(); deinitPerThread(); } - public boolean progressBar(IProgress p, int wait) - { - long end = System.currentTimeMillis() + wait; - while (!p.getCompleted()) - { - p.waitForCompletion(wait); - if (System.currentTimeMillis() >= end) - return false; - } - - return true; - } - - public boolean startVm(String name, String type, int timeout) - { - IMachine m = vbox.findMachine(name); - if (m == null) - return false; - ISession session = getSessionObject(); - - if (type == null) - type = "gui"; - IProgress p = m.launchVMProcess(session, type, ""); - progressBar(p, timeout); - session.unlockMachine(); - return true; - } - public void waitForEvents(long tmo) { } - - protected void finalize() throws Throwable + + protected void finalize() throws Throwable { - try { + try + { cleanup(); - } catch(Exception e) { } - finally { + catch(Exception e) + { + } + finally + { super.finalize(); } } } ]]> + - - - - + + + @@ -4084,6 +4550,10 @@ public class VirtualBoxManager + + + + @@ -4122,7 +4592,7 @@ public class VirtualBoxManager - + @@ -4142,5 +4612,10 @@ public class VirtualBoxManager + + + + + diff --git a/src/VBox/Main/glue/initterm.cpp b/src/VBox/Main/glue/initterm.cpp index 6e9e1c6e..dbc493c8 100644 --- a/src/VBox/Main/glue/initterm.cpp +++ b/src/VBox/Main/glue/initterm.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,20 +20,10 @@ # include -#else /* !defined (VBOX_WITH_XPCOM) */ +#else /* !defined(VBOX_WITH_XPCOM) */ # include - /* XPCOM_GLUE is defined when the client uses the standalone glue - * (i.e. dynamically picks up the existing XPCOM shared library installation). - * This is not the case for VirtualBox XPCOM clients (they are always - * distributed with the self-built XPCOM library, and therefore have a binary - * dependency on it) but left here for clarity. - */ -# if defined(XPCOM_GLUE) -# include -# endif - # include # include # include @@ -48,7 +38,7 @@ #include "VBox/com/com.h" #include "VBox/com/assert.h" -#include "VBox/com/EventQueue.h" +#include "VBox/com/NativeEventQueue.h" #include "VBox/com/AutoLock.h" #include "../include/Logging.h" @@ -182,7 +172,7 @@ DirectoryServiceProvider::GetFile(const char *aProp, if (NS_FAILED(rv)) return rv; - return localFile->QueryInterface(NS_GET_IID (nsIFile), (void **)aRetval); + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void **)aRetval); } /** @@ -196,7 +186,7 @@ static bool volatile gIsXPCOMInitialized = false; */ static unsigned int gXPCOMInitCount = 0; -#else /* !defined (VBOX_WITH_XPCOM) */ +#else /* !defined(VBOX_WITH_XPCOM) */ /** * The COM main thread handle. (The first caller of com::Initialize().) @@ -208,7 +198,7 @@ static RTTHREAD volatile gCOMMainThread = NIL_RTTHREAD; */ static uint32_t gCOMMainInitCount = 0; -#endif /* !defined (VBOX_WITH_XPCOM) */ +#endif /* !defined(VBOX_WITH_XPCOM) */ /** @@ -304,7 +294,7 @@ HRESULT Initialize(bool fGui) if (SUCCEEDED(rc)) gCOMMainInitCount = 1; -#else /* !defined (VBOX_WITH_XPCOM) */ +#else /* !defined(VBOX_WITH_XPCOM) */ /* Unused here */ NOREF(fGui); @@ -345,33 +335,34 @@ HRESULT Initialize(bool fGui) if (vrc == VERR_ACCESS_DENIED) return NS_ERROR_FILE_ACCESS_DENIED; AssertRCReturn(vrc, NS_ERROR_FAILURE); - strcpy(szXptiDat, szCompReg); - + vrc = RTStrCopy(szXptiDat, sizeof(szXptiDat), szCompReg); + AssertRCReturn(vrc, NS_ERROR_FAILURE); +#ifdef VBOX_IN_32_ON_64_MAIN_API + vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg-x86.dat"); + AssertRCReturn(vrc, NS_ERROR_FAILURE); + vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti-x86.dat"); + AssertRCReturn(vrc, NS_ERROR_FAILURE); +#else vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); +#endif LogFlowFunc(("component registry : \"%s\"\n", szCompReg)); LogFlowFunc(("XPTI data file : \"%s\"\n", szXptiDat)); -#if defined (XPCOM_GLUE) - XPCOMGlueStartup(nsnull); -#endif - static const char *kAppPathsToProbe[] = { NULL, /* 0: will use VBOX_APP_HOME */ - NULL, /* 1: will try RTPathAppPrivateArch() */ -#ifdef RT_OS_LINUX - "/usr/lib/virtualbox", - "/opt/VirtualBox", -#elif RT_OS_SOLARIS - "/opt/VirtualBox/amd64", - "/opt/VirtualBox/i386", -#elif RT_OS_DARWIN - "/Application/VirtualBox.app/Contents/MacOS", -#endif + NULL, /* 1: will try RTPathAppPrivateArch(), correctly installed release builds will never go further */ + NULL, /* 2: will try parent directory of RTPathAppPrivateArch(), only for testcases in non-hardened builds */ + /* There used to be hard coded paths, but they only caused trouble + * because they often led to mixing of builds or even versions. + * If you feel tempted to add anything here, think again. They would + * only be used if option 1 would not work, which is a sign of a big + * problem, as it returns a fixed location defined at compile time. + * It is better to fail than blindly trying to cover the problem. */ }; /* Find out the directory where VirtualBox binaries are located */ @@ -393,11 +384,26 @@ HRESULT Initialize(bool fGui) vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir)); AssertRC(vrc); } + else if (i == 2) + { +#ifdef VBOX_WITH_HARDENING + continue; +#else /* !VBOX_WITH_HARDENING */ + /* Use parent of RTPathAppPrivateArch() if ends with "testcase" */ + vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir)); + AssertRC(vrc); + vrc = RTPathStripTrailingSlash(szAppHomeDir); + AssertRC(vrc); + char *filename = RTPathFilename(szAppHomeDir); + if (!filename || strcmp(filename, "testcase")) + continue; + RTPathStripFilename(szAppHomeDir); +#endif /* !VBOX_WITH_HARDENING */ + } else { /* Iterate over all other paths */ - szAppHomeDir[RTPATH_MAX - 1] = '\0'; - strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1); + RTStrCopy(szAppHomeDir, sizeof(szAppHomeDir), kAppPathsToProbe[i]); vrc = VINF_SUCCESS; } if (RT_FAILURE(vrc)) @@ -405,9 +411,14 @@ HRESULT Initialize(bool fGui) rc = NS_ERROR_FAILURE; continue; } - char szCompDir[RTPATH_MAX]; - vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components"); + vrc = RTStrCopy(szCompDir, sizeof(szCompDir), szAppHomeDir); + if (RT_FAILURE(vrc)) + { + rc = NS_ERROR_FAILURE; + continue; + } + vrc = RTPathAppend(szCompDir, sizeof(szCompDir), "components"); if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; @@ -476,7 +487,9 @@ HRESULT Initialize(bool fGui) } /* clean up before the new try */ - rc = NS_ShutdownXPCOM(nsnull); + HRESULT rc2 = NS_ShutdownXPCOM(nsnull); + if (SUCCEEDED(rc)) + rc = rc2; if (i == 0) { @@ -485,20 +498,20 @@ HRESULT Initialize(bool fGui) } } -#endif /* !defined (VBOX_WITH_XPCOM) */ +#endif /* !defined(VBOX_WITH_XPCOM) */ + + AssertComRCReturnRC(rc); // for both COM and XPCOM, we only get here if this is the main thread; // only then initialize the autolock system (AutoLock.cpp) Assert(RTThreadIsMain(RTThreadSelf())); util::InitAutoLockSystem(); - AssertComRC(rc); - /* * Init the main event queue (ASSUMES it cannot fail). */ if (SUCCEEDED(rc)) - EventQueue::init(); + NativeEventQueue::init(); return rc; } @@ -516,14 +529,14 @@ HRESULT Shutdown() { if (-- gCOMMainInitCount == 0) { - EventQueue::uninit(); + NativeEventQueue::uninit(); ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD); } } CoUninitialize(); -#else /* !defined (VBOX_WITH_XPCOM) */ +#else /* !defined(VBOX_WITH_XPCOM) */ nsCOMPtr eventQ; rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); @@ -555,7 +568,7 @@ HRESULT Shutdown() * init counter drops to zero */ if (--gXPCOMInitCount == 0) { - EventQueue::uninit(); + NativeEventQueue::uninit(); rc = NS_ShutdownXPCOM(nsnull); /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to @@ -563,10 +576,6 @@ HRESULT Shutdown() bool wasInited = ASMAtomicXchgBool(&gIsXPCOMInitialized, false); Assert(wasInited == true); NOREF(wasInited); - -# if defined (XPCOM_GLUE) - XPCOMGlueShutdown(); -# endif } } } diff --git a/src/VBox/Main/glue/string.cpp b/src/VBox/Main/glue/string.cpp index dc15bddc..a5b95a1e 100644 --- a/src/VBox/Main/glue/string.cpp +++ b/src/VBox/Main/glue/string.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,7 +57,7 @@ void Bstr::copyFromN(const char *a_pszSrc, size_t a_cchMax) throw std::bad_alloc(); } - m_bstr = ::SysAllocStringByteLen(NULL, cwc * sizeof(OLECHAR)); + m_bstr = ::SysAllocStringByteLen(NULL, (unsigned)(cwc * sizeof(OLECHAR))); if (RT_UNLIKELY(!m_bstr)) throw std::bad_alloc(); diff --git a/src/VBox/Main/glue/tests/Makefile b/src/VBox/Main/glue/tests/Makefile index e1f0cb20..0b6f9096 100644 --- a/src/VBox/Main/glue/tests/Makefile +++ b/src/VBox/Main/glue/tests/Makefile @@ -2,7 +2,7 @@ # Makefile for a sample/testcase using the 'glue' Java API bindings # -# Copyright (C) 2010-2011 Oracle Corporation +# Copyright (C) 2010-2012 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/glue/tests/TestVBox.java b/src/VBox/Main/glue/tests/TestVBox.java index 0a703831..ce823720 100644 --- a/src/VBox/Main/glue/tests/TestVBox.java +++ b/src/VBox/Main/glue/tests/TestVBox.java @@ -4,7 +4,7 @@ * be used to connect to the webservice and (XP)COM APIs. */ /* - * Copyright (C) 2010-2011 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -14,7 +14,7 @@ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -import org.virtualbox_4_2.*; +import org.virtualbox_4_3.*; import java.util.List; import java.util.Arrays; import java.math.BigInteger; @@ -25,7 +25,7 @@ public class TestVBox { System.out.println("got event: " + ev); VBoxEventType type = ev.getType(); - System.out.println("type = "+type); + System.out.println("type = " + type); switch (type) { case OnMachineStateChanged: @@ -34,7 +34,7 @@ public class TestVBox if (mcse == null) System.out.println("Cannot query an interface"); else - System.out.println("mid="+mcse.getMachineId()); + System.out.println("mid=" + mcse.getMachineId()); break; } } @@ -63,7 +63,7 @@ public class TestVBox es.registerListener(listener, Arrays.asList(VBoxEventType.Any), false); try { - for (int i=0; i<50; i++) + for (int i = 0; i < 50; i++) { System.out.print("."); IEvent ev = es.getEvent(listener, 500); @@ -97,6 +97,8 @@ public class TestVBox hwvirtEnabled = m.getHWVirtExProperty(HWVirtExPropertyType.Enabled); hwvirtNestedPaging = m.getHWVirtExProperty(HWVirtExPropertyType.NestedPaging); paeEnabled = m.getCPUProperty(CPUPropertyType.PAE); + String osType = m.getOSTypeId(); + IGuestOSType foo = vbox.getGuestOSType(osType); } catch (VBoxException e) { @@ -114,11 +116,29 @@ public class TestVBox } } + static boolean progressBar(VirtualBoxManager mgr, IProgress p, long waitMillis) + { + long end = System.currentTimeMillis() + waitMillis; + while (!p.getCompleted()) + { + mgr.waitForEvents(0); + p.waitForCompletion(200); + if (System.currentTimeMillis() >= end) + return false; + } + return true; + } + static void testStart(VirtualBoxManager mgr, IVirtualBox vbox) { - String m = vbox.getMachines().get(0).getName(); - System.out.println("\nAttempting to start VM '" + m + "'"); - mgr.startVm(m, null, 7000); + IMachine m = vbox.getMachines().get(0); + String name = m.getName(); + System.out.println("\nAttempting to start VM '" + name + "'"); + + ISession session = mgr.getSessionObject(); + IProgress p = m.launchVMProcess(session, "gui", ""); + progressBar(mgr, p, 10000); + session.unlockMachine(); } static void testMultiServer() @@ -130,11 +150,18 @@ public class TestVBox mgr1.connect("http://i7:18083", "", ""); mgr2.connect("http://main:18083", "", ""); - String mach1 = mgr1.getVBox().getMachines().get(0).getName(); - String mach2 = mgr2.getVBox().getMachines().get(0).getName(); - - mgr1.startVm(mach1, null, 7000); - mgr2.startVm(mach2, null, 7000); + IMachine m1 = mgr1.getVBox().getMachines().get(0); + IMachine m2 = mgr2.getVBox().getMachines().get(0); + String name1 = m1.getName(); + String name2 = m2.getName(); + ISession session1 = mgr1.getSessionObject(); + ISession session2 = mgr2.getSessionObject(); + IProgress p1 = m1.launchVMProcess(session1, "gui", ""); + IProgress p2 = m2.launchVMProcess(session2, "gui", ""); + progressBar(mgr1, p1, 10000); + progressBar(mgr2, p2, 10000); + session1.unlockMachine(); + session2.unlockMachine(); } finally { mgr1.cleanup(); mgr2.cleanup(); @@ -157,6 +184,23 @@ public class TestVBox } } + static void printErrorInfo(VBoxException e) + { + System.out.println("VBox error: " + e.getMessage()); + System.out.println("Error cause message: " + e.getCause()); + System.out.println("Overall result code: " + Integer.toHexString(e.getResultCode())); + int i = 1; + for (IVirtualBoxErrorInfo ei = e.getVirtualBoxErrorInfo(); ei != null; ei = ei.getNext(), i++) + { + System.out.println("Detail information #" + i); + System.out.println("Error mesage: " + ei.getText()); + System.out.println("Result code: " + Integer.toHexString(ei.getResultCode())); + // optional, usually provides little additional information: + System.out.println("Component: " + ei.getComponent()); + System.out.println("Interface ID: " + ei.getInterfaceID()); + } + } + public static void main(String[] args) { @@ -167,15 +211,15 @@ public class TestVBox String user = null; String passwd = null; - for (int i = 0; i portForward = nat.getRedirects(); + String pf = null; + Iterator itPortForward = portForward.iterator(); + for (;itPortForward.hasNext();) + { + pf = itPortForward.next(); + System.out.println(name + ":NIC" + n.getSlot() /* name:NIC*/ + + " pf: " + pf); /* port-forward rule */ + } + if (pf != null) + { + String pfAttributes[] = pf.split(","); + /* name,proto,hostip,host,hostport,guestip,guestport */ + nat.removeRedirect(pfAttributes[0]); + nat.addRedirect("", + NATProtocol.fromValue(new Integer(pfAttributes[1]).longValue()), + pfAttributes[2], + new Integer( + new Integer(pfAttributes[3]).intValue() + 1), + pfAttributes[4], + new Integer(pfAttributes[5])); + } + + } + } + + } + catch (VBoxException e) + { + name = ""; + inaccessible = true; + } + } + + static void testStart(VirtualBoxManager mgr, IVirtualBox vbox, IMachine vm) + { + System.out.println("\nAttempting to start VM '" + vm.getName() + "'"); + mgr.startVm(vm.getName(), null, 7000); + } + + public TestVBoxNATEngine(String[] args) + { + VirtualBoxManager mgr = VirtualBoxManager.createInstance(null); + + boolean ws = false; + String url = null; + String user = null; + String passwd = null; + String vmname = null; + IMachine vm = null; + + for (int i = 0; i 0x7fffffff and hrStatus <= 0xffffffff and hrXcpt < 0: + if (hrStatus - 0x100000000) == hrXcpt: + return True; + return False; + + def xcptGetMessage(self, oXcpt): + """ + Returns the best error message found in the COM-like exception. + Returns None to fall back on xcptToString. + Raises exception if oXcpt isn't our kind of exception object. + """ + return None; + + def xcptGetBaseXcpt(self): + """ + Returns the base exception class. + """ + return None; + + def xcptSetupConstants(self, oDst): + """ + Copy/whatever all error constants onto oDst. + """ + return oDst; + + @staticmethod + def xcptCopyErrorConstants(oDst, oSrc): + """ + Copy everything that looks like error constants from oDst to oSrc. + """ + for sAttr in dir(oSrc): + if sAttr[0].isupper() and (sAttr[1].isupper() or sAttr[1] == '_'): + oAttr = getattr(oSrc, sAttr); + if type(oAttr) is int: + setattr(oDst, sAttr, oAttr); + return oDst; + + + +class PlatformMSCOM(PlatformBase): + """ + Platform specific code for MS COM. + """ + + ## @name VirtualBox COM Typelib definitions (should be generate) + # + # @remarks Must be updated when the corresponding VirtualBox.xidl bits + # are changed. Fortunately this isn't very often. + # @{ + VBOX_TLB_GUID = '{D7569351-1750-46F0-936E-BD127D5BC264}' + VBOX_TLB_LCID = 0 + VBOX_TLB_MAJOR = 1 + VBOX_TLB_MINOR = 3 + ## @} + + + class ConstantFake(object): + """ Class to fake access to constants in style of foo.bar.boo """ -class PlatformMSCOM: - # Class to fake access to constants in style of foo.bar.boo - class ConstantFake: def __init__(self, parent, name): self.__dict__['_parent'] = parent self.__dict__['_name'] = name @@ -172,7 +425,7 @@ class PlatformMSCOM: else: name = attr return win32com.client.constants.__getattr__(name) - except AttributeError,e: + except AttributeError, e: fake = PlatformMSCOM.ConstantFake(self, attr) consts[attr] = fake return fake @@ -189,39 +442,90 @@ class PlatformMSCOM: raise AttributeError try: return win32com.client.constants.__getattr__(a) - except AttributeError,e: + except AttributeError, e: return self.__dict__['_rootFake'].__getattr__(a) - VBOX_TLB_GUID = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}' - VBOX_TLB_LCID = 0 - VBOX_TLB_MAJOR = 1 - VBOX_TLB_MINOR = 0 + def __init__(self, dParams): + PlatformBase.__init__(self, dParams); - def __init__(self, params): - from win32com import universal - from win32com.client import gencache, DispatchBaseClass - from win32com.client import constants, getevents - import win32com - import pythoncom - import win32api - from win32con import DUPLICATE_SAME_ACCESS - from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess - import threading - pid = GetCurrentProcess() - self.tid = GetCurrentThreadId() - handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS) - self.handles = [] - self.handles.append(handle) - _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__'] - DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr - _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__'] - DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr - win32com.client.gencache.EnsureDispatch('VirtualBox.Session') - win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox') - self.oIntCv = threading.Condition() - self.fInterrupted = False; - - def getSessionObject(self, vbox): + # + # Since the code runs on all platforms, we have to do a lot of + # importing here instead of at the top of the file where it's normally located. + # + from win32com import universal + from win32com.client import gencache, DispatchBaseClass + from win32com.client import constants, getevents + import win32com + import pythoncom + import win32api + import winerror + from win32con import DUPLICATE_SAME_ACCESS + from win32api import GetCurrentThread, GetCurrentThreadId, DuplicateHandle, GetCurrentProcess + import threading + + self.winerror = winerror; + + pid = GetCurrentProcess() + self.tid = GetCurrentThreadId() + handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS) + self.handles = [] + self.handles.append(handle) + + # Hack the COM dispatcher base class so we can modify method and + # attribute names to match those in xpcom. + if _g_dCOMForward['setattr'] is None: + _g_dCOMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__'] + DispatchBaseClass.__dict__['__getattr__'] = _CustomGetAttr + _g_dCOMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__'] + DispatchBaseClass.__dict__['__setattr__'] = _CustomSetAttr + + # Hack the exception base class so the users doesn't need to check for + # XPCOM or COM and do different things. + ## @todo + + # + # Make sure the gencache is correct (we don't quite follow the COM + # versioning rules). + # + self.flushGenPyCache(win32com.client.gencache); + win32com.client.gencache.EnsureDispatch('VirtualBox.Session'); + win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox'); + + self.oIntCv = threading.Condition() + self.fInterrupted = False; + + _ = dParams; + + def flushGenPyCache(self, oGenCache): + """ + Flushes VBox related files in the win32com gen_py cache. + + This is necessary since we don't follow the typelib versioning rules + that everyeone else seems to subscribe to. + """ + # + # The EnsureModule method have broken validation code, it doesn't take + # typelib module directories into account. So we brute force them here. + # (It's possible the directory approach is from some older pywin + # version or the result of runnig makepy or gencache manually, but we + # need to cover it as well.) + # + sName = oGenCache.GetGeneratedFileName(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID, + self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR); + sGenPath = oGenCache.GetGeneratePath(); + if len(sName) > 36 and len(sGenPath) > 5: + sTypelibPath = os.path.join(sGenPath, sName); + if os.path.isdir(sTypelibPath): + import shutil; + shutil.rmtree(sTypelibPath, ignore_errors = True); + + # + # Ensure that our typelib is valid. + # + return oGenCache.EnsureModule(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID, self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR); + + def getSessionObject(self, oIVBox): + _ = oIVBox import win32com from win32com.client import Dispatch return win32com.client.Dispatch("VirtualBox.Session") @@ -234,11 +538,8 @@ class PlatformMSCOM: def getType(self): return 'MSCOM' - def getRemote(self): - return False - - def getArray(self, obj, field): - return obj.__getattr__(field) + def getArray(self, oInterface, sAttrib): + return oInterface.__getattr__(sAttrib) def initPerThread(self): import pythoncom @@ -248,11 +549,18 @@ class PlatformMSCOM: import pythoncom pythoncom.CoUninitialize() - def createListener(self, impl, arg): + def createListener(self, oImplClass, dArgs): + if True: + raise Exception('no active listeners on Windows as PyGatewayBase::QueryInterface() ' + 'returns new gateway objects all the time, thus breaking EventQueue ' + 'assumptions about the listener interface pointer being constants between calls '); + # Did this code ever really work? d = {} - d['BaseClass'] = impl - d['arg'] = arg - d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID + d['BaseClass'] = oImplClass + d['dArgs'] = dArgs + d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID + d['tlb_major'] = PlatformMSCOM.VBOX_TLB_MAJOR + d['tlb_minor'] = PlatformMSCOM.VBOX_TLB_MINOR str = "" str += "import win32com.server.util\n" str += "import pythoncom\n" @@ -260,16 +568,16 @@ class PlatformMSCOM: str += "class ListenerImpl(BaseClass):\n" str += " _com_interfaces_ = ['IEventListener']\n" str += " _typelib_guid_ = tlb_guid\n" - str += " _typelib_version_ = 1, 0\n" + str += " _typelib_version_ = tlb_major, tlb_minor\n" str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n" # Maybe we'd better implement Dynamic invoke policy, to be more flexible here str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n" # capitalized version of listener method str += " HandleEvent=BaseClass.handleEvent\n" - str += " def __init__(self): BaseClass.__init__(self, arg)\n" + str += " def __init__(self): BaseClass.__init__(self, dArgs)\n" str += "result = win32com.server.util.wrap(ListenerImpl())\n" - exec (str,d,d) + exec(str, d, d) return d['result'] def waitForEvents(self, timeout): @@ -285,8 +593,10 @@ class PlatformMSCOM: if (self.tid != GetCurrentThreadId()): raise Exception("wait for events from the same thread you inited!") - if timeout < 0: cMsTimeout = INFINITE - else: cMsTimeout = timeout + if timeout < 0: + cMsTimeout = INFINITE + else: + cMsTimeout = timeout rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT) if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles): # is it possible? @@ -310,7 +620,7 @@ class PlatformMSCOM: def interruptWaitEvents(self): """ - Basically a python implementation of EventQueue::postEvent(). + Basically a python implementation of NativeEventQueue::postEvent(). The magic value must be in sync with the C++ implementation or this won't work. @@ -340,18 +650,83 @@ class PlatformMSCOM: pythoncom.CoUninitialize() pass - def queryInterface(self, obj, klazzName): + def queryInterface(self, oIUnknown, sClassName): from win32com.client import CastTo - return CastTo(obj, klazzName) + return CastTo(oIUnknown, sClassName) + + def xcptGetStatus(self, oXcpt): + # The DISP_E_EXCEPTION + excptinfo fun needs checking up, only + # empirical info on it so far. + hrXcpt = oXcpt.hresult + if hrXcpt == self.winerror.DISP_E_EXCEPTION: + try: hrXcpt = oXcpt.excepinfo[5]; + except: pass; + return hrXcpt; + + def xcptIsDeadInterface(self, oXcpt): + return self.xcptGetStatus(oXcpt) in [ + 0x800706ba, -2147023174, # RPC_S_SERVER_UNAVAILABLE. + 0x800706be, -2147023170, # RPC_S_CALL_FAILED. + 0x800706bf, -2147023169, # RPC_S_CALL_FAILED_DNE. + 0x80010108, -2147417848, # RPC_E_DISCONNECTED. + 0x800706b5, -2147023179, # RPC_S_UNKNOWN_IF + ]; + + + def xcptGetMessage(self, oXcpt): + if hasattr(oXcpt, 'excepinfo'): + try: + if len(oXcpt.excepinfo) >= 3: + sRet = oXcpt.excepinfo[2]; + if len(sRet) > 0: + return sRet[0:]; + except: + pass; + if hasattr(oXcpt, 'strerror'): + try: + sRet = oXcpt.strerror; + if len(sRet) > 0: + return sRet; + except: + pass; + return None; + + def xcptGetBaseXcpt(self): + import pythoncom; + return pythoncom.com_error; + + def xcptSetupConstants(self, oDst): + import winerror; + oDst = self.xcptCopyErrorConstants(oDst, winerror); + + # XPCOM compatability constants. + oDst.NS_OK = oDst.S_OK; + oDst.NS_ERROR_FAILURE = oDst.E_FAIL; + oDst.NS_ERROR_ABORT = oDst.E_ABORT; + oDst.NS_ERROR_NULL_POINTER = oDst.E_POINTER; + oDst.NS_ERROR_NO_INTERFACE = oDst.E_NOINTERFACE; + oDst.NS_ERROR_INVALID_ARG = oDst.E_INVALIDARG; + oDst.NS_ERROR_OUT_OF_MEMORY = oDst.E_OUTOFMEMORY; + oDst.NS_ERROR_NOT_IMPLEMENTED = oDst.E_NOTIMPL; + oDst.NS_ERROR_UNEXPECTED = oDst.E_UNEXPECTED; + return oDst; + + +class PlatformXPCOM(PlatformBase): + """ + Platform specific code for XPCOM. + """ -class PlatformXPCOM: - def __init__(self, params): - sys.path.append(VboxSdkDir+'/bindings/xpcom/python/') + def __init__(self, dParams): + PlatformBase.__init__(self, dParams); + sys.path.append(VBoxSdkDir+'/bindings/xpcom/python/') import xpcom.vboxxpcom import xpcom import xpcom.components + _ = dParams; - def getSessionObject(self, vbox): + def getSessionObject(self, oIVBox): + _ = oIVBox; import xpcom.components return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance() @@ -362,11 +737,8 @@ class PlatformXPCOM: def getType(self): return 'XPCOM' - def getRemote(self): - return False - - def getArray(self, obj, field): - return obj.__getattr__('get'+ComifyName(field))() + def getArray(self, oInterface, sAttrib): + return oInterface.__getattr__('get'+ComifyName(sAttrib))() def initPerThread(self): import xpcom @@ -376,17 +748,17 @@ class PlatformXPCOM: import xpcom xpcom._xpcom.DetachThread() - def createListener(self, impl, arg): + def createListener(self, oImplClass, dArgs): d = {} - d['BaseClass'] = impl - d['arg'] = arg + d['BaseClass'] = oImplClass + d['dArgs'] = dArgs str = "" str += "import xpcom.components\n" str += "class ListenerImpl(BaseClass):\n" str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n" - str += " def __init__(self): BaseClass.__init__(self, arg)\n" + str += " def __init__(self): BaseClass.__init__(self, dArgs)\n" str += "result = ListenerImpl()\n" - exec (str,d,d) + exec (str, d, d) return d['result'] def waitForEvents(self, timeout): @@ -401,33 +773,126 @@ class PlatformXPCOM: import xpcom xpcom._xpcom.DeinitCOM() - def queryInterface(self, obj, klazzName): + def queryInterface(self, oIUnknown, sClassName): import xpcom.components - return obj.queryInterface(getattr(xpcom.components.interfaces, klazzName)) + return oIUnknown.queryInterface(getattr(xpcom.components.interfaces, sClassName)) + + def xcptGetStatus(self, oXcpt): + return oXcpt.errno; -class PlatformWEBSERVICE: - def __init__(self, params): - sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib')) - #import VirtualBox_services + def xcptIsDeadInterface(self, oXcpt): + return self.xcptGetStatus(oXcpt) in [ + 0x80004004, -2147467260, # NS_ERROR_ABORT + 0x800706be, -2147023170, # NS_ERROR_CALL_FAILED (RPC_S_CALL_FAILED) + ]; + + def xcptGetMessage(self, oXcpt): + if hasattr(oXcpt, 'msg'): + try: + sRet = oXcpt.msg; + if len(sRet) > 0: + return sRet; + except: + pass; + return None; + + def xcptGetBaseXcpt(self): + import xpcom; + return xpcom.Exception; + + def xcptSetupConstants(self, oDst): + import xpcom; + oDst = self.xcptCopyErrorConstants(oDst, xpcom.nsError); + + # COM compatability constants. + oDst.E_ACCESSDENIED = -2147024891; # see VBox/com/defs.h + oDst.S_OK = oDst.NS_OK; + oDst.E_FAIL = oDst.NS_ERROR_FAILURE; + oDst.E_ABORT = oDst.NS_ERROR_ABORT; + oDst.E_POINTER = oDst.NS_ERROR_NULL_POINTER; + oDst.E_NOINTERFACE = oDst.NS_ERROR_NO_INTERFACE; + oDst.E_INVALIDARG = oDst.NS_ERROR_INVALID_ARG; + oDst.E_OUTOFMEMORY = oDst.NS_ERROR_OUT_OF_MEMORY; + oDst.E_NOTIMPL = oDst.NS_ERROR_NOT_IMPLEMENTED; + oDst.E_UNEXPECTED = oDst.NS_ERROR_UNEXPECTED; + oDst.DISP_E_EXCEPTION = -2147352567; # For COM compatability only. + return oDst; + + +class PlatformWEBSERVICE(PlatformBase): + """ + VirtualBox Web Services API specific code. + """ + + def __init__(self, dParams): + PlatformBase.__init__(self, dParams); + # Import web services stuff. Fix the sys.path the first time. + sWebServLib = os.path.join(VBoxSdkDir, 'bindings', 'webservice', 'python', 'lib'); + if sWebServLib not in sys.path: + sys.path.append(sWebServLib); import VirtualBox_wrappers from VirtualBox_wrappers import IWebsessionManager2 - if params is not None: - self.user = params.get("user", "") - self.password = params.get("password", "") - self.url = params.get("url", "") + # Initialize instance variables from parameters. + if dParams is not None: + self.user = dParams.get("user", "") + self.password = dParams.get("password", "") + self.url = dParams.get("url", "") else: - self.user = "" + self.user = "" self.password = "" - self.url = None - self.vbox = None + self.url = None + self.vbox = None + self.wsmgr = None; + + # + # Base class overrides. + # - def getSessionObject(self, vbox): - return self.wsmgr.getSessionObject(vbox) + def getSessionObject(self, oIVBox): + return self.wsmgr.getSessionObject(oIVBox) def getVirtualBox(self): return self.connect(self.url, self.user, self.password) + def getType(self): + return 'WEBSERVICE' + + def isRemote(self): + """ Returns True if remote VBox host, False if local. """ + return True + + def getArray(self, oInterface, sAttrib): + return oInterface.__getattr__(sAttrib) + + def waitForEvents(self, timeout): + # Webservices cannot do that yet + return 2; + + def interruptWaitEvents(self, timeout): + # Webservices cannot do that yet + return False; + + def deinit(self): + try: + disconnect() + except: + pass + + def queryInterface(self, oIUnknown, sClassName): + d = {} + d['oIUnknown'] = oIUnknown + str = "" + str += "from VirtualBox_wrappers import "+sClassName+"\n" + str += "result = "+sClassName+"(oIUnknown.mgr, oIUnknown.handle)\n" + # wrong, need to test if class indeed implements this interface + exec (str, d, d) + return d['result'] + + # + # Web service specific methods. + # + def connect(self, url, user, passwd): if self.vbox is not None: self.disconnect() @@ -449,164 +914,310 @@ class PlatformWEBSERVICE: def disconnect(self): if self.vbox is not None and self.wsmgr is not None: - self.wsmgr.logoff(self.vbox) - self.vbox = None - self.wsmgr = None + self.wsmgr.logoff(self.vbox) + self.vbox = None + self.wsmgr = None - def getType(self): - return 'WEBSERVICE' - def getRemote(self): - return True +## The current (last) exception class. +# This is reinitalized whenever VirtualBoxManager is called, so it will hold +# the reference to the error exception class for the last platform/style that +# was used. Most clients does talk to multiple VBox instance on different +# platforms at the same time, so this should be sufficent for most uses and +# be way simpler to use than VirtualBoxManager::oXcptClass. +CurXctpClass = None; - def getArray(self, obj, field): - return obj.__getattr__(field) - def initPerThread(self): - pass - - def deinitPerThread(self): - pass - - def createListener(self, impl, arg): - raise Exception("no active listeners for webservices") - - def waitForEvents(self, timeout): - # Webservices cannot do that yet - return 2; - - def interruptWaitEvents(self, timeout): - # Webservices cannot do that yet - return False; - - def deinit(self): - try: - disconnect() - except: - pass +class VirtualBoxManager(object): + """ + VirtualBox API manager class. - def queryInterface(self, obj, klazzName): - d = {} - d['obj'] = obj - str = "" - str += "from VirtualBox_wrappers import "+klazzName+"\n" - str += "result = "+klazzName+"(obj.mgr,obj.handle)\n" - # wrong, need to test if class indeed implements this interface - exec (str,d,d) - return d['result'] + The API users will have to instantiate this. If no parameters are given, + it will default to interface with the VirtualBox running on the local + machine. sStyle can be None (default), MSCOM, XPCOM or WEBSERVICES. Most + users will either be specifying None or WEBSERVICES. -class SessionManager: - def __init__(self, mgr): - self.mgr = mgr + The dPlatformParams is an optional dictionary for passing parameters to the + WEBSERVICE backend. + """ - def getSessionObject(self, vbox): - return self.mgr.platform.getSessionObject(vbox) + class Statuses(object): + def __init__(self): + pass; -class VirtualBoxManager: - def __init__(self, style, platparams): - if style is None: + def __init__(self, sStyle = None, dPlatformParams = None): + if sStyle is None: if sys.platform == 'win32': - style = "MSCOM" + sStyle = "MSCOM" else: - style = "XPCOM" - - - exec "self.platform = Platform"+style+"(platparams)" - # for webservices, enums are symbolic - self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE") - self.type = self.platform.getType() - self.remote = self.platform.getRemote() - self.style = style - self.mgr = SessionManager(self) - + sStyle = "XPCOM" + if sStyle == 'XPCOM': + self.platform = PlatformXPCOM(dPlatformParams); + elif sStyle == 'MSCOM': + self.platform = PlatformMSCOM(dPlatformParams); + elif sStyle == 'WEBSERVICE': + self.platform = PlatformWEBSERVICE(dPlatformParams); + else: + raise Exception('Unknown sStyle=%s' % (sStyle,)); + self.style = sStyle + self.type = self.platform.getType() + self.remote = self.platform.isRemote() + ## VirtualBox API constants (for webservices, enums are symbolic). + self.constants = VirtualBoxReflectionInfo(sStyle == "WEBSERVICE") + + ## Status constants. + self.statuses = self.platform.xcptSetupConstants(VirtualBoxManager.Statuses()); + ## @todo Add VBOX_E_XXX to statuses? They're already in constants... + ## Dictionary for errToString, built on demand. + self._dErrorValToName = None; + + ## The exception class for the selected platform. + self.oXcptClass = self.platform.xcptGetBaseXcpt(); + global CurXcptClass; + CurXcptClass = self.oXcptClass; + + # Get the virtualbox singleton. try: self.vbox = self.platform.getVirtualBox() - except NameError,ne: + except NameError, ne: print "Installation problem: check that appropriate libs in place" traceback.print_exc() raise ne - except Exception,e: - print "init exception: ",e + except Exception, e: + print "init exception: ", e traceback.print_exc() if self.remote: self.vbox = None else: raise e + ## @deprecated + # This used to refer to a session manager class with only one method + # called getSessionObject. The method has moved into this call. + self.mgr = self; + + def __del__(self): + self.deinit() - def getArray(self, obj, field): - return self.platform.getArray(obj, field) + def getPythonApiRevision(self): + """ + Returns a Python API revision number. + This will be incremented when features are added to this file. + """ + return 3; + + + # + # Wrappers for self.platform methods. + # def getVirtualBox(self): - return self.platform.getVirtualBox() + """ See PlatformBase::getVirtualBox(). """ + return self.platform.getVirtualBox() - def __del__(self): - self.deinit() + def getSessionObject(self, oIVBox): + """ See PlatformBase::getSessionObject(). """ + return self.platform.getSessionObject(oIVBox); + + def getArray(self, oInterface, sAttrib): + """ See PlatformBase::getArray(). """ + return self.platform.getArray(oInterface, sAttrib) + + def createListener(self, oImplClass, dArgs = None): + """ See PlatformBase::createListener(). """ + return self.platform.createListener(oImplClass, dArgs) + + def waitForEvents(self, cMsTimeout): + """ See PlatformBase::waitForEvents(). """ + return self.platform.waitForEvents(cMsTimeout) + + def interruptWaitEvents(self): + """ See PlatformBase::interruptWaitEvents(). """ + return self.platform.interruptWaitEvents() + + def queryInterface(self, oIUnknown, sClassName): + """ See PlatformBase::queryInterface(). """ + return self.platform.queryInterface(oIUnknown, sClassName) + + + # + # Init and uninit. + # + + def initPerThread(self): + """ See PlatformBase::deinitPerThread(). """ + self.platform.initPerThread() + + def deinitPerThread(self): + """ See PlatformBase::deinitPerThread(). """ + return self.platform.deinitPerThread() def deinit(self): + """ + For unitializing the manager. + Do not access it after calling this method. + """ if hasattr(self, "vbox"): del self.vbox self.vbox = None if hasattr(self, "platform"): self.platform.deinit() self.platform = None + return True; - def initPerThread(self): - self.platform.initPerThread() - def openMachineSession(self, mach, permitSharing = True): - session = self.mgr.getSessionObject(self.vbox) - if permitSharing: - type = self.constants.LockType_Shared - else: - type = self.constants.LockType_Write - mach.lockMachine(session, type) - return session + # + # Utility methods. + # - def closeMachineSession(self, session): - if session is not None: - session.unlockMachine() + def openMachineSession(self, oIMachine, fPermitSharing = True): + """ + Attemts to open the a session to the machine. + Returns a session object on success. + Raises exception on failure. + """ + oSession = self.mgr.getSessionObject(self.vbox); + if fPermitSharing: + type = self.constants.LockType_Shared; + else: + type = self.constants.LockType_Write; + oIMachine.lockMachine(oSession, type); + return oSession; - def deinitPerThread(self): - self.platform.deinitPerThread() + def closeMachineSession(self, oSession): + """ + Closes a session opened by openMachineSession. + Ignores None parameters. + """ + if oSession is not None: + oSession.unlockMachine() + return True; - def createListener(self, impl, arg = None): - return self.platform.createListener(impl, arg) + def getPerfCollector(self, oIVBox): + """ + Returns a helper class (PerfCollector) for accessing performance + collector goodies. See PerfCollector for details. + """ + return PerfCollector(self, oIVBox) - def waitForEvents(self, timeout): + def getBinDir(self): """ - Wait for events to arrive and process them. + Returns the VirtualBox binary directory. + """ + global VBoxBinDir + return VBoxBinDir - The timeout is in milliseconds. A negative value means waiting for - ever, while 0 does not wait at all. + def getSdkDir(self): + """ + Returns the VirtualBox SDK directory. + """ + global VBoxSdkDir + return VBoxSdkDir - Returns 0 if events was processed. - Returns 1 if timed out or interrupted in some way. - Returns 2 on error (like not supported for web services). - Raises an exception if the calling thread is not the main thread (the one - that initialized VirtualBoxManager) or if the time isn't an integer. + # + # Error code utilities. + # + + ## @todo port to webservices! + + def xcptGetStatus(self, oXcpt = None): + """ + Gets the status code from an exception. If the exception parameter + isn't specified, the current exception is examined. """ - return self.platform.waitForEvents(timeout) + if oXcpt is None: + oXcpt = sys.exc_info()[1]; + return self.platform.xcptGetStatus(oXcpt); - def interruptWaitEvents(self): + def xcptIsDeadInterface(self, oXcpt = None): """ - Interrupt a waitForEvents call. - This is normally called from a worker thread. + Returns True if the exception indicates that the interface is dead, + False if not. If the exception parameter isn't specified, the current + exception is examined. + """ + if oXcpt is None: + oXcpt = sys.exc_info()[1]; + return self.platform.xcptIsDeadInterface(oXcpt); - Returns True on success, False on failure. + def xcptIsOurXcptKind(self, oXcpt = None): """ - return self.platform.interruptWaitEvents() + Checks if the exception is one that could come from the VBox API. If + the exception parameter isn't specified, the current exception is + examined. + """ + if self.oXcptClass is None: ## @todo find the exception class for web services! + return False; + if oXcpt is None: + oXcpt = sys.exc_info()[1]; + return isinstance(oXcpt, self.oXcptClass); - def getPerfCollector(self, vbox): - return PerfCollector(self, vbox) + def xcptIsEqual(self, oXcpt, hrStatus): + """ + Checks if the exception oXcpt is equal to the COM/XPCOM status code + hrStatus. - def getBinDir(self): - global VboxBinDir - return VboxBinDir + The oXcpt parameter can be any kind of object, we'll just return True + if it doesn't behave like a our exception class. If it's None, we'll + query the current exception and examine that. - def getSdkDir(self): - global VboxSdkDir - return VboxSdkDir + Will not raise any exception as long as hrStatus and self are not bad. + """ + if oXcpt is None: + oXcpt = sys.exc_info()[1]; + return self.platform.xcptIsEqual(oXcpt, hrStatus); + + def xcptIsNotEqual(self, oXcpt, hrStatus): + """ + Negated xcptIsEqual. + """ + return not self.xcptIsEqual(oXcpt, hrStatus); + + def xcptToString(self, hrStatusOrXcpt = None): + """ + Converts the specified COM status code, or the status code of the + specified exception, to a C constant string. If the parameter isn't + specified (is None), the current exception is examined. + """ + + # Deal with exceptions. + if hrStatusOrXcpt is None or self.xcptIsOurXcptKind(hrStatusOrXcpt): + hrStatus = self.xcptGetStatus(hrStatusOrXcpt); + else: + hrStatus = hrStatusOrXcpt; + + # Build the dictionary on demand. + if self._dErrorValToName is None: + dErrorValToName = dict(); + for sKey in dir(self.statuses): + if sKey[0].isupper(): + oValue = getattr(self.statuses, sKey); + if type(oValue) is int: + dErrorValToName[oValue] = sKey; + self._dErrorValToName = dErrorValToName; + + # Do the lookup, falling back on formatting the status number. + try: + sStr = self._dErrorValToName[int(hrStatus)]; + except KeyError: + hrLong = long(hrStatus); + sStr = '%#x (%d)' % (hrLong, hrLong); + return sStr; + + def xcptGetMessage(self, oXcpt = None): + """ + Returns the best error message found in the COM-like exception. If the + exception parameter isn't specified, the current exception is examined. + """ + if oXcpt is None: + oXcpt = sys.exc_info()[1]; + sRet = self.platform.xcptGetMessage(oXcpt); + if sRet is None: + sRet = self.xcptToString(oXcpt); + return sRet; + + # Legacy, remove in a day or two. + errGetStatus = xcptGetStatus + errIsDeadInterface = xcptIsDeadInterface + errIsOurXcptKind = xcptIsOurXcptKind + errGetMessage = xcptGetMessage - def queryInterface(self, obj, klazzName): - return self.platform.queryInterface(obj, klazzName) diff --git a/src/VBox/Main/glue/xpcom/helpers.cpp b/src/VBox/Main/glue/xpcom/helpers.cpp index 38ce7129..53f0ab5f 100644 --- a/src/VBox/Main/glue/xpcom/helpers.cpp +++ b/src/VBox/Main/glue/xpcom/helpers.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -139,6 +139,8 @@ int SysReAllocString(BSTR *pbstr, const OLECHAR *psz) return 1; } +#if 0 +/* Does not work -- we ignore newBuffer! */ /** * Changes the length of a previous created BSTR * @param pbstr string to change the length of @@ -167,6 +169,7 @@ int SysReAllocStringLen(BSTR *pbstr, const OLECHAR *psz, unsigned int cch) } return 1; } +#endif /** * Returns the string length in bytes without the terminator diff --git a/src/VBox/Main/idl/VirtualBox.dtd b/src/VBox/Main/idl/VirtualBox.dtd index a62540e0..0af06e2c 100644 --- a/src/VBox/Main/idl/VirtualBox.dtd +++ b/src/VBox/Main/idl/VirtualBox.dtd @@ -5,7 +5,7 @@ It is still the only sort-of-documentation available about what is valid XIDL syntax. - Copyright (C) 2008-2010 Oracle Corporation + Copyright (C) 2008-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -15,26 +15,32 @@ VirtualBox OSE distribution. VirtualBox OSE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. --> - + - - - + + + + + + + + + + + - - - - + + + @@ -42,7 +48,7 @@ - + - + + + + + + + + + - + + + - + + + + - + + + -]> diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl index aa096271..6f2739c1 100644 --- a/src/VBox/Main/idl/VirtualBox.xidl +++ b/src/VBox/Main/idl/VirtualBox.xidl @@ -1,8 +1,8 @@ - + Settings version of VirtualBox settings files. This is written to @@ -401,35 +441,35 @@ file XML and indicates which VirtualBox version wrote the file. - + Null value, indicates invalid version. - + Legacy settings version, not currently supported. - + Legacy settings version, not currently supported. - + Legacy settings version, not currently supported. - + Legacy settings version, not currently supported. - + Settings version "1.3", written by VirtualBox 2.0.12. - + Intermediate settings version, understood by VirtualBox 2.1.x. - + Intermediate settings version, understood by VirtualBox 2.1.x. - + Settings version "1.6", written by VirtualBox 2.1.4 (at least). - + Settings version "1.7", written by VirtualBox 2.2.x and 3.0.x. - + Intermediate settings version "1.8", understood by VirtualBox 3.1.x. - + Settings version "1.9", written by VirtualBox 3.1.x. - + Settings version "1.10", written by VirtualBox 3.2.x. - + Settings version "1.11", written by VirtualBox 4.0.x. - + Settings version "1.12", written by VirtualBox 4.1.x. - + Settings version "1.13", written by VirtualBox 4.2.x. + + Settings version "1.14", written by VirtualBox 4.3.x. + + - + Settings version greater than "1.13", written by a future VirtualBox version. @@ -515,8 +561,8 @@ Access mode for opening files. - - + + - + Null value (never used by the API). - + The machine is not running and has no saved execution state; it has either never been started or been shut down successfully. - + The machine is not currently running, but the execution state of the machine has been saved to an external file when it was running, from where it can be resumed. - + The machine was teleported to a different host (or process) and then - powered off. Take care when powering it on again may corrupt resources + powered off. Take care when powering it on again may corrupt resources it shares with the teleportation target (e.g. disk and network). - + The process running the machine has terminated abnormally. This may indicate a crash of the VM process in host execution context, or the VM process has been terminated externally. - + The machine is currently being executed. @@ -689,7 +735,7 @@ - + Execution of the machine has been paused. @@ -700,7 +746,7 @@ - + Execution of the machine has reached the "Guru Meditation" condition. This indicates a severe error in the hypervisor itself. @@ -711,7 +757,7 @@ - + The machine is about to be teleported to a different host or process. It is possible to pause a machine in this state, but it will go to the @@ -719,81 +765,81 @@ possible to resume it again unless the teleportation fails. - + - A live snapshot is being taken. The machine is running normally, but - some of the runtime configuration options are inaccessible. Also, if + A live snapshot is being taken. The machine is running normally, but + some of the runtime configuration options are inaccessible. Also, if paused while in this state it will transition to @c Saving and it will not be resume the execution until the snapshot operation has completed. - + Machine is being started after powering it on from a zero execution state. - + Machine is being normally stopped powering it off, or after the guest OS has initiated a shutdown sequence. - + Machine is saving its execution state to a file, or an online snapshot of the machine is being taken. - + Execution state of the machine is being restored from a file after powering it on from the saved execution state. - + The machine is being teleported to another host or process, but it is - not running. This is the paused variant of the + not running. This is the paused variant of the @c state. - + Teleporting the machine state in from another host or process. - + The machine is being synced with a fault tolerant VM running elsewhere. - + Like @c DeletingSnapshot, but the merging of media is ongoing in the background while the machine is running. - + Like @c DeletingSnapshotOnline, but the machine was paused when the merging of differencing media was started. - + A machine snapshot is being restored; this typically does not take long. - + A machine snapshot is being deleted; this can take a long time since this may require merging differencing media. This value indicates that the machine is not running while the snapshot is being deleted. - + Lengthy setup operation is in progress. @@ -804,7 +850,7 @@ Pseudo-state: first online state (for use in relational expressions). - + Pseudo-state: last online state (for use in relational expressions). @@ -815,7 +861,7 @@ Pseudo-state: first transient state (for use in relational expressions). - + Pseudo-state: last transient state (for use in relational expressions). @@ -874,7 +920,7 @@ Virtual CPU property type. This enumeration represents possible values of the @@ -896,50 +942,60 @@ teleporting between host systems that differ significantly. + + + This setting determines whether VirtualBox will advertise long mode + (i.e. 64-bit guest support) and let the guest enter it. + + + + + This setting determines whether a triple fault within a guest will trigger an internal + error condition and stop the VM (default) or reset the virtual CPU and continue execution. + + Hardware virtualization property type. This enumeration represents possible values for the and methods. - + Null value (never used by the API). - + Whether hardware virtualization (VT-x/AMD-V) is enabled at all. If such extensions are not available, they will not be used. - + - Whether hardware virtualization is used exclusively by VirtualBox. When enabled, - VirtualBox assumes it can acquire full and exclusive access to the VT-x or AMD-V - feature of the host. To share these with other hypervisors, you must disable this property. + Whether VT-x VPID is enabled. If this extension is not available, it will not be used. - + - Whether VT-x VPID is enabled. If this extension is not available, it will not be used. + Whether Nested Paging is enabled. If this extension is not available, it will not be used. - + - Whether Nested Paging is enabled. If this extension is not available, it will not be used. + Whether VT-x unrestricted execution is enabled. If this feature is not available, it will not be used. - + - Whether large page allocation is enabled; requires nested paging and a 64 bits host. + Whether large page allocation is enabled; requires nested paging and a 64-bit host. - + Whether the VM should fail to start if hardware virtualization (VT-x/AMD-V) cannot be used. If not set, there will be an automatic fallback to software virtualization. @@ -973,10 +1029,16 @@ Used with . - Lock the machine for writing. + Lock the machine for writing. This requests an exclusive lock, i.e. + there cannot be any other API client holding any type of lock for this + VM concurrently. Remember that a VM process counts as an API client + which implicitly holds the equivalent of a shared lock during the + entire VM runtime. - Request only a shared read lock for remote-controlling the machine. + Request only a shared lock for remote-controlling the machine. + Such a lock allows changing certain VM settings which can be safely + modified for a running VM. Lock the machine for writing, and create objects necessary for @@ -1128,10 +1190,10 @@ CPU features. - - - - + + + + Firmware type. - + BIOS Firmware. - + EFI Firmware, bitness detected basing on OS type. - - Efi firmware, 32-bit. + + EFI firmware, 32-bit. - - Efi firmware, 64-bit. + + EFI firmware, 64-bit. - - Efi firmware, combined 32 and 64-bit. + + EFI firmware, combined 32 and 64-bit. Type of pointing device used in a virtual machine. - + No mouse. - + PS/2 auxiliary device, a.k.a. mouse. - + USB mouse (relative pointer). - - USB tablet (absolute pointer). + + + USB tablet (absolute pointer). Also enables a relative USB mouse in + addition. + + + + + Combined device, working as PS/2 or USB mouse, depending on guest + behavior. Using this device can have negative performance implications. + - - Combined device, working as PS/2 or USB mouse, depending on guest behavior. - Using of such device can have negative performance implications. + + + USB multi-touch device. Also enables the USB tablet and mouse devices. + @@ -1201,7 +1273,7 @@ Combined device, working as PS/2 or USB keyboard, depending on guest behavior. - Using of such device can have negative performance implications. + Using of such device can have negative performance implications. @@ -1212,7 +1284,7 @@ @@ -1262,6 +1334,13 @@ + + + Optional result data of this error. This will vary depending on the + actual error usage. By default this attribute is not being used. + + + UUID of the interface that defined the error. @@ -1310,18 +1389,193 @@ ///////////////////////////////////////////////////////////////////////// --> + + + + TBD: the idea, technically we can start any number of the NAT networks, + but we should expect that at some point we will get collisions because of + port-forwanding rules. so perhaps we should support only single instance of NAT + network. + + + + + + This is CIDR IPv4 string. Specifying it user defines IPv4 addresses + of gateway (low address + 1) and DHCP server (= low address + 2). + Note: If there are defined IPv4 port-forward rules update of network + will be ignored (because new assignment could break existing rules). + + + + + This attribute is read-only. It's recalculated on changing + network attribute (low address of network + 1). + + + + + This attribute define whether gateway will support IPv6 or not. + + + + + This a CIDR IPv6 defining prefix for link-local addresses + autoconfiguration within network. Note: ignored if attribute + IPv6Enabled is false. + + + + + + + Array of NAT port-forwarding rules in string representation, + in the following format: + "name:protocolid:[host ip]:host port:[guest ip]:guest port". + + + + Array of mappings (address,offset),e.g. ("127.0.1.1=4") maps 127.0.1.1 to networkid + 4. + + + + + + + + + + + + Offset in ipv6 network from network id for address mapped into loopback6 interface of the host. + + + + + Array of NAT port-forwarding rules in string representation, in the + following format: "name:protocolid:[host ip]:host port:[guest ip]:guest port". + + + + + + + Protocol handled with the rule. + + + IP of the host interface to which the rule should apply. + An empty ip address is acceptable, in which case the NAT engine + binds the handling socket to any interface. + + + + The port number to listen on. + + + The IP address of the guest which the NAT engine will forward + matching packets to. An empty IP address is not acceptable. + + + The port number to forward. + + + + + + + + + + Type of internal network trunk. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - The IDHCPServer interface represents the vbox DHCP server configuration. + The IDHCPServer interface represents the VirtualBox DHCP server configuration. To enumerate all the DHCP servers on the host, use the attribute. - + + specifies if the DHCP server is enabled @@ -1358,6 +1612,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + configures the server @@ -1423,7 +1733,7 @@ @@ -1448,8 +1758,8 @@ last number represents the build number and will frequently change. This may be followed by a _ALPHA[0-9]*, _BETA[0-9]* or _RC[0-9]* tag - in prerelease builds. Non-Oracle builds may (/shall) also have a - publisher tag, at the end. The publisher tag starts with an underscore + in prerelease builds. Non-Oracle builds may (/shall) also have a + publisher tag, at the end. The publisher tag starts with an underscore just like the prerelease build type tag. @@ -1591,6 +1901,8 @@ DHCP servers. + + @@ -1725,6 +2037,12 @@ guest OS types listed in the array. + + will return + @c false for the created machine, until any of machine settings + are changed. + + There is no way to change the name of the settings file or subfolder of the created machine directly. @@ -1784,6 +2102,12 @@ The file must exist and be a valid machine XML settings file whose contents will be used to construct the machine object. + + will return + @c false for the opened machine, until any of machine settings + are changed. + + Settings file name invalid, not found or sharing violation. @@ -1796,11 +2120,6 @@ Opened machine object. - - will return - @c false for the created machine, until any of machine settings - are changed. - @@ -2110,7 +2429,7 @@ Returns an array representing the global extra data keys which currently have values defined. - + Array of extra data keys. @@ -2268,6 +2587,30 @@ + + + + + + + + + + + + + + + + @@ -2344,7 +2687,7 @@ @@ -2367,7 +2710,7 @@ current directory level. Use to get the full list after a call to this method. - + Progress object to track the operation completion. @@ -2375,11 +2718,11 @@ Change the current directory level. - + The name of the directory to go in. - + Progress object to track the operation completion. @@ -2387,7 +2730,7 @@ Go one directory upwards from the current directory level. - + Progress object to track the operation completion. @@ -2397,19 +2740,19 @@ to="#update" />. The user is responsible for keeping this internal list up do date. - + The list of names for the entries. - + The list of types for the entries. - + The list of sizes (in bytes) for the entries. - + The list of file modes (in octal form) for the entries. @@ -2418,11 +2761,11 @@ Checks if the given file list exists in the current directory level. - + The names to check. - + The names which exist. @@ -2430,11 +2773,11 @@ Deletes the given files in the current directory level. - + The names to remove. - + Progress object to track the operation completion. @@ -2442,7 +2785,7 @@ @@ -2450,15 +2793,47 @@ Import options, used with . - + Don't generate new MAC addresses of the attached network adapters. - + Don't generate new MAC addresses of the attached network adapters when they are using NAT. + + + + Export options, used with . + + + + Write the optional manifest file (.mf) which is used for integrity + checks prior import. + + + Export DVD images. Default is not to export them as it is rarely + needed for typical VMs. + + + Do not export any MAC address information. Default is to keep them + to avoid losing information which can cause trouble after import, at the + price of risking duplicate MAC addresses, if the import options are used + to keep them. + + + Do not export any MAC address information, except for adapters + using NAT. Default is to keep them to avoid losing information which can + cause trouble after import, at the price of risking duplicate MAC + addresses, if the import options are used to keep them. + + + + + + + Changes the location of this medium. Some medium types may support + changing the storage unit location by simply changing the value of the + associated property. In this case the operation is performed + immediately, and @a progress is returning a @c null reference. + Otherwise on success there is a progress object returned, which + signals progress and completion of the operation. This distinction is + necessary because for some formats the operation is very fast, while + for others it can be very slow (moving the image file by copying all + data), and in the former case it'd be a waste of resources to create + a progress object which will immediately signal completion. + + When setting a location for a medium which corresponds to a/several + regular file(s) in the host's file system, the given file name may be + either relative to the VirtualBox + home folder or absolute. Note that if the given location + specification does not contain the file extension part then a proper + default extension will be automatically appended by the implementation + depending on the medium type. + + + The operation is not implemented yet. + + + Medium format does not support changing the location. + + + + New location. + + + Progress object to track the operation completion. + + + Starts compacting of this medium. This means that the medium is @@ -13411,7 +14531,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) @@ -13459,9 +14579,9 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - + - Capabilities of the format as a set of bit flags. + Capabilities of the format as an array of the flags. For the meaning of individual capability flags see . @@ -13480,10 +14600,10 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - + The array of supported extensions. - + The array which indicates the device type for every given extension. @@ -13507,7 +14627,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Array of property names. - + Array of property descriptions. @@ -13524,6 +14644,46 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + + + The IToken interface represents a token passed to an API client, which + triggers cleanup actions when it is explicitly released by calling the + method (preferred, as it is accurately defined + when the release happens), or when the object reference count drops + to 0. The latter way is implicitly used when an API client crashes, + however the discovery that there was a crash can take rather long, + depending on the platform (COM needs 6 minutes). So better don't rely + on the crash behavior too much. + + + + Releases this token. Cannot be undone in any way, and makes the + token object unusable (even the method will return + an error), ready for releasing. It is a more defined way than just + letting the reference count drop to 0, because the latter (depending + on the platform) can trigger asynchronous cleanup activity. + + + + + Purely a NOOP. Useful when using proxy type API bindings (e.g. the + webservice) which manage objects on behalf of the actual client, using + an object reference expiration time based garbage collector. + + + + + + - - - Flag whether the USB controller is present in the - guest system. If disabled, the virtual guest hardware will - not contain any USB controller. Can only be changed when - the VM is powered off. - - - - - - Flag whether the USB EHCI controller is present in the - guest system. If disabled, the virtual guest hardware will - not contain a USB EHCI controller. Can only be changed when - the VM is powered off. - - - - - - Flag whether there is an USB proxy available. - - - - - - USB standard version which the controller implements. - This is a BCD which means that the major version is in the - high byte and minor version is in the low byte. - - @@ -15582,6 +16846,56 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + + + The USB controller type. . + + + @c null value. Never used by the API. + + + + + Last element (invalid). Used for parameter checks. + + + + + + + + The USB Controller name. + + + + + + The USB Controller type. + + + + + + USB standard version which the controller implements. + This is a BCD which means that the major version is in the + high byte and minor version is in the low byte. + + + + + + + + Internal event reason type. + + + + Null value, means "no known reason". + + + Host is being suspended (power management event). + + + Host is being resumed (power management event). + + + Host is running low on battery (power management event). + + + @@ -16338,6 +17675,27 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + + Assigns the machine object associated with this direct-type + session or informs the session that it will be a remote one + (if @a machine == @c null). + + + Session state prevents operation. + + + Session type prevents operation. + + + + + + + + + Assigns the machine object associated with this direct-type @@ -16354,7 +17712,9 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + @@ -16384,7 +17744,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - + @@ -16506,6 +17866,10 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) TRUE if the device is removed, FALSE if it was added. + + TRUE if the device is is silently reconfigured without + notifying the guest about it. + @@ -16565,6 +17929,12 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + Triggered when video capture settings have changed. + + + Triggered when settings of the USB controller object of the @@ -16709,30 +18079,30 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) The patterns to match the properties against as a comma-separated - string. If this is empty, all properties currently set will be + string. If this is empty, all properties currently set will be returned. - + The key names of the properties returned. - + - The values of the properties returned. The array entries match the + The values of the properties returned. The array entries match the corresponding entries in the @a key array. - + - The time stamps of the properties returned. The array entries match + The time stamps of the properties returned. The array entries match the corresponding entries in the @a key array. - The flags of the properties returned. The array entries match the + The flags of the properties returned. The array entries match the corresponding entries in the @a key array. @@ -16762,22 +18132,6 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) The index of the target image in the chain. Redundant, but drastically reduces IPC. - - Merge source medium. - - - Merge target medium. - - - Merge direction. - - - For forward merges: new parent for target medium. - - - For backward merges: list of media which need their parent UUID - updated. - Progress object for this operation. @@ -16802,6 +18156,69 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + Internal method for triggering a VM pause with a specified reason code. + The reason code can be interpreted by device/drivers and thus it might + behave slightly differently than a normal VM pause. + + + Virtual machine not in Running state. + + + Virtual machine error in suspend operation. + + + + + + Specify the best matching reason code please. + + + + + + Internal method for triggering a VM resume with a specified reason code. + The reason code can be interpreted by device/drivers and thus it might + behave slightly differently than a normal VM resume. + + + Virtual machine not in Paused state. + + + Virtual machine error in resume operation. + + + + + + Specify the best matching reason code please. + + + + + + Internal method for triggering a VM save state with a specified reason + code. The reason code can be interpreted by device/drivers and thus it + might behave slightly differently than a normal VM save state. + + + Virtual machine state neither Running nor Paused. + + + Failed to create directory for saved state file. + + + + + + Specify the best matching reason code please. + + + Progress object to track the operation completion. + + + When using the COM API directly, an object of the Session class from the VirtualBox type library needs to be created. In regular COM C++ client code, this can be done by calling createLocalObject(), a standard COM API. - This object will then act as a local session object in further calls to open + This object will then act as a local session object in further calls to open a session. @@ -16930,7 +18347,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) The bus type of the storage controller (IDE, SATA, SCSI, SAS or Floppy); see . - + @c null value. Never used by the API. @@ -16949,31 +18366,31 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) to the guest; see . - + @c null value. Never used by the API. - + A SCSI controller of the LsiLogic variant. - + A SCSI controller of the BusLogic variant. - + An Intel AHCI SATA controller; this is the only variant for SATA. - + An IDE controller of the PIIX3 variant. - + An IDE controller of the PIIX4 variant. - + An IDE controller of the ICH6 variant. - + A floppy disk controller; this is the only variant for floppy drives. - + A variant of the LsiLogic controller using SAS. @@ -16986,10 +18403,10 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Type of emulated chipset (mostly southbridge). - + @c null value. Never used by the API. - + A PIIX3 (PCI IDE ISA Xcelerator) chipset. @@ -17026,7 +18443,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Name of the storage controller, as originally specified with . This then uniquely identifies this controller with other method calls such as - and . + and . @@ -17128,7 +18545,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Behind each managed object reference, there is a COM object that lives in the webservice server's address space. The COM object is not freed until the managed object reference is released, either by an explicit - call to or by logging off from + call to or by logging off from the webservice (), which releases all objects created during the webservice session. @@ -17285,7 +18702,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) and stores performance metrics data. Performance metrics are associated with objects of interfaces like IHost - and IMachine. Each object has a distinct set of performance metrics. The + and IMachine. Each object has a distinct set of performance metrics. The set can be obtained with . Metric data is collected at the specified intervals and is retained @@ -17307,7 +18724,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) the smallest unit for which a sampling interval and the number of retained samples can be set. Only base metrics can be enabled and disabled. All sub-metrics are collected when their base metric is - collected. Collected values for any set of sub-metrics can be queried + collected. Collected values for any set of sub-metrics can be queried with . For example "CPU/Load/User:avg" metric name stands for the "CPU" @@ -17551,14 +18968,15 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) form metric/object pairs. - Data collection continues behind the scenes after call to @c - queryMetricsData. The return data can be seen as the snapshot of the - current state at the time of @c queryMetricsData call. The internally - kept metric values are not cleared by the call. This makes possible - querying different subsets of metrics or aggregates with subsequent - calls. If periodic querying is needed it is highly suggested to query - the values with @c interval*count period to avoid confusion. This way - a completely new set of data values will be provided by each query. + Data collection continues behind the scenes after call to + @c queryMetricsData. The return data can be seen as the snapshot of + the current state at the time of @c queryMetricsData call. The + internally kept metric values are not cleared by the call. This + allows querying different subsets of metrics or aggregates with + subsequent calls. If periodic querying is needed it is highly + suggested to query the values with @c interval*count period to avoid + confusion. This way a completely new set of data values will be + provided by each query. @@ -17805,17 +19223,17 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) accessing COM objects within it. - The extension pack name. This is unique. + The extension pack name. This is unique. The extension pack description. - The extension pack version string. This is restricted to the dotted - version number and optionally a build indicator. No tree revision or + The extension pack version string. This is restricted to the dotted + version number and optionally a build indicator. No tree revision or tag will be included in the string as those things are available as - separate properties. An optional publisher tag may be present like for + separate properties. An optional publisher tag may be present like for . Examples: "1.2.3", "1.2.3_BETA1" and "1.2.3_RC2". @@ -17826,11 +19244,11 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - Edition indicator. This is usually empty. + Edition indicator. This is usually empty. - Can for instance be used to help distinguishing between two editions - of the same extension pack where only the license, service contract or - something differs. + Can for instance be used to help distinguishing between two editions + of the same extension pack where only the license, service contract or + something differs. @@ -17850,7 +19268,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - String indicating why the extension pack is not usable. This is an + String indicating why the extension pack is not usable. This is an empty string if usable and always a non-empty string if not usable. @@ -17859,7 +19277,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - The default HTML license text for the extension pack. Same as + The default HTML license text for the extension pack. Same as calling queryLicense with preferredLocale and preferredLanguage as empty strings and format set to html. @@ -17908,11 +19326,11 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Queries the IUnknown interface to an object in the extension pack - main module. This allows plug-ins and others to talk directly to an + main module. This allows plug-ins and others to talk directly to an extension pack. - The object ID. What exactly this is + The object ID. What exactly this is The queried interface. @@ -17927,7 +19345,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) > Extension pack file (aka tarball, .vbox-extpack) representation returned - by . This provides the base + by . This provides the base extension pack information with the addition of the file name. @@ -17948,7 +19366,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - Platform specific display information. Reserved for future hacks. + Platform specific display information. Reserved for future hacks. @@ -17999,7 +19417,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) installation. - The path of the extension pack tarball. This can optionally be + The path of the extension pack tarball. This can optionally be followed by a "::SHA-256=hex-digit" of the tarball. @@ -18014,13 +19432,13 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - Forced removal of the extension pack. This means that the uninstall + Forced removal of the extension pack. This means that the uninstall hook will not be called. - Platform specific display information. Reserved for future hacks. + Platform specific display information. Reserved for future hacks. @@ -18113,7 +19531,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - How many devices/medium attachements use this group. + How many devices/medium attachments use this group. @@ -18201,7 +19619,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) @@ -18231,6 +19649,18 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + Perform error checking before using an object. + Generally useful before starting a VM and all other uses. If anything + is not as it should be then this method will return an appropriate + error. + + + + The machine object to check. + + @@ -18507,9 +19937,120 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) See IDragAndDropModeChangedEvent. + + + See INATNetworkChangedEvent. + + + + + See INATNetworkStartStopEvent. + + + + + See INATNetworkAlterEvent. + + + + + See INATNetworkCreationDeletionEvent. + + + + + See INATNetworkSettingEvent. + + + + + See INATNetworkPortForwardEvent. + + + + + See IGuestSessionStateChangedEvent. + + + + + See IGuestSessionRegisteredEvent. + + + + + See IGuestProcessRegisteredEvent. + + + + + See IGuestProcessStateChangedEvent. + + + + + See IGuestProcessInputNotifyEvent. + + + + + See IGuestProcessOutputEvent. + + + + + See IGuestFileRegisteredEvent. + + + + + See IGuestFileStateChangedEvent. + + + + + See IGuestFileOffsetChangedEvent. + + + + + See IGuestFileReadEvent. + + For performance reasons this is a separate event to + not unnecessarily overflow the event queue. + + + + + See IGuestFileWriteEvent. + For performance reasons this is a separate event to + not unnecessarily overflow the event queue. + + + + + See IVideoCapturedChangeEvent. + + + + + See IGuestUserStateChangedEvent. + + + + + See IGuestMouseEvent. + + + + + See IHostNameResolutionConfigurationChangeEvent. + + + - + Must be last event, used for iterations and structures relying on numerical event values. @@ -18547,7 +20088,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - Subordinate event source this one aggregatres. + Subordinate event source this one aggregates. @@ -18747,7 +20288,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) consumers may register event listeners with this event source. To register a listener, an object implementing the interface must be provided. For active listeners, such an object is typically created by the consumer, while for - passive listeners should be used. Please + passive listeners should be used. Please note that a listener created with must not be used as an active listener. Once created, the listener must be registered to listen for the desired events @@ -18803,7 +20344,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - Maximum time to wait for event processeing, in ms; + Maximum time to wait for event processing, in ms; 0 = no wait, -1 = indefinite wait. @@ -19065,9 +20606,9 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) The @a shape buffer contains a 1-bpp (bits per pixel) AND mask followed by a 32-bpp XOR (color) mask. - For pointers without alpha channel the XOR mask pixels are 32 - bit values: (lsb)BGR0(msb). For pointers with alpha channel - the XOR mask consists of (lsb)BGRA(msb) 32 bit values. + For pointers without alpha channel the XOR mask pixels are + 32-bit values: (lsb)BGR0(msb). For pointers with alpha channel + the XOR mask consists of (lsb)BGRA(msb) 32-bit values. An AND mask is used for pointers with alpha channel, so if the callback does not support alpha, the pointer could be @@ -19093,7 +20634,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) @@ -19110,6 +20651,11 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Supports relative coordinates. + + + Supports multi-touch events coordinates. + + If host cursor is needed. @@ -19179,7 +20725,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Notification when a property of one of the virtual network adapters - changes. Interested callees should use INetworkAdapter methods and + changes. Interested callees should use INetworkAdapter methods and attributes to find out what has changed. @@ -19215,7 +20761,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Notification when a property of one of the virtual parallel ports - changes. Interested callees should use ISerialPort methods and + changes. Interested callees should use ISerialPort methods and attributes to find out what has changed. @@ -19327,25 +20873,51 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Notification when guest keyboard event happens. - + Array of scancodes. + + + + The mode (relative, absolute, multi-touch) of a pointer event. + TODO: a clear pattern seems to be emerging that we should usually have + multiple input devices active for different types of reporting, so we + should really have different event types for relative (including wheel), + absolute (not including wheel) and multi-touch events. + + + + + Relative event. + + + + + + Absolute event. + + + + Notification when guest mouse event happens. - + - If this event is relative or absolute. + If this event is relative, absolute or multi-touch. @@ -19381,16 +20953,365 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) - - Notification when a property of the - VRDE server changes. - Interested callees should use IVRDEServer methods and attributes to + Notification when guest touch screen event happens. + + + + Number of contacts in the event. + + + + + X positions. + + + + + Y positions. + + + + + Contact identifiers. + + + + + Contact state. + Bit 0: in contact. + Bit 1: in range. + + + + + Timestamp of the event in milliseconds. Only relative time between events is important. + + + + + + Base abstract interface for all guest session events. + + + Guest session that is subject to change. + + + + + + + Notification when a guest session changed its state. + + + + + Session ID of guest session which was changed. + + + + + New session status. + + + + + Error information in case of new session status is indicating an error. + + The attribute will contain + the runtime (IPRT) error code from the guest. See include/iprt/err.h and + include/VBox/err.h for details. + + + + + + + + Notification when a guest session was registered or unregistered. + + + + + If @c true, the guest session was registered, otherwise it was + unregistered. + + + + + + + Base abstract interface for all guest process events. + + + + Guest process object which is related to this event. + + + + + Guest process ID (PID). + + + + + + + + Notification when a guest process was registered or unregistered. + + + + + If @c true, the guest process was registered, otherwise it was + unregistered. + + + + + + + + Notification when a guest process changed its state. + + + + + New guest process status. + + + + + Error information in case of new session status is indicating an error. + + The attribute will contain + the runtime (IPRT) error code from the guest. See include/iprt/err.h and + include/VBox/err.h for details. + + + + + + + + Base abstract interface for all guest process input/output (IO) events. + + + + + Input/output (IO) handle involved in this event. Usually 0 is stdin, + 1 is stdout and 2 is stderr. + + + + + + Processed input or output (in bytes). + + + + + + + + Notification when a guest process' stdin became available. + This event is right now not implemented! + + + + + Current process input status. + + + + + + + + Notification when there is guest process output available for reading. + + + + + Actual output data. + + + + + + + Base abstract interface for all guest file events. + + + + Guest file object which is related to this event. + + + + + + + + Notification when a guest file was registered or unregistered. + + + + + If @c true, the guest file was registered, otherwise it was + unregistered. + + + + + + + + Notification when a guest file changed its state. + + + + + New guest file status. + + + + + Error information in case of new session status is indicating an error. + + The attribute will contain + the runtime (IPRT) error code from the guest. See include/iprt/err.h and + include/VBox/err.h for details. + + + + + + + + + Base abstract interface for all guest file input/output (IO) events. + + + + + Current offset (in bytes). + + + + + Processed input or output (in bytes). + + + + + + + + Notification when a guest file changed its current offset. + + + + + + + Notification when data has been read from a guest file. + + + + + Actual data read. + + + + + + + + Notification when data has been written to a guest file. + + + + + + + Notification when a property of the + VRDE server changes. + Interested callees should use IVRDEServer methods and attributes to find out what has changed. @@ -19407,6 +21328,16 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + Notification when video capture settings have changed. + + + Notification when a property of the virtual - USB controller changes. + USB controllers changes. Interested callees should use IUSBController methods and attributes to find out what has changed. @@ -19654,7 +21585,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) name="IExtraDataCanChangeEvent" extends="IVetoEvent" uuid="245d88bd-800a-40f8-87a6-170d02249a55" wsmap="managed" autogen="VBoxEvent" id="OnExtraDataCanChange" - waitable="true" + waitable="yes" > Notification when someone tries to change extra data for @@ -19683,7 +21614,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) name="ICanShowWindowEvent" extends="IVetoEvent" uuid="adf292b0-92c9-4a77-9d35-e058b39fe0b9" wsmap="managed" autogen="VBoxEvent" id="OnCanShowWindow" - waitable="true" + waitable="yes" > Notification when a call to @@ -19702,7 +21633,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) name="IShowWindowEvent" extends="IEvent" uuid="B0A0904D-2F05-4D28-855F-488F96BAD2B2" wsmap="managed" autogen="VBoxEvent" id="OnShowWindow" - waitable="true" + waitable="yes" > Notification when a call to @@ -19749,42 +21680,42 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Notification when NAT redirect rule added or removed. - + Adapter which NAT attached to. - + Whether rule remove or add. - + Name of the rule. - + Protocol (TCP or UDP) of the redirect rule. - + Host ip address to bind socket on. - + Host port to bind socket on. - + Guest ip address to redirect to. - + Guest port to redirect to. @@ -19944,9 +21875,43 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) + + + Notification when a guest user changed its state. + + + + + Name of the guest user whose state changed. + + + + + Name of the FQDN (fully qualified domain name) this user is bound + to. Optional. + + + + + What was changed for this guest user. See for + more information. + + + + + Optional state details, depending on the attribute. + + + + + @@ -19964,6 +21929,69 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) Flag whether the device was removed or added to the VM. + + + Flag whether the guest should be notified about the change. + + + + + + + + + + + + + IsStartEvent is true when NAT network is started and false on stopping. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VBox/Main/idl/apiwrap-server.xsl b/src/VBox/Main/idl/apiwrap-server.xsl new file mode 100644 index 00000000..2f08e714 --- /dev/null +++ b/src/VBox/Main/idl/apiwrap-server.xsl @@ -0,0 +1,1394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /** @file + * + + + + * + * DO NOT EDIT! This is a generated file. + * Generated from: src/VBox/Main/idl/VirtualBox.xidl + * Generator: src/VBox/Main/idl/apiwrap-server.xsl + */ + +/** + * Copyright (C) 2010-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + + + + + + + + + + + + + + + + + + + + + +#include "VirtualBoxBase.h" +#include "Wrapper.h" + + + + + public VirtualBoxBase, + + + { + Q_OBJECT + +public: + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + + + COM_INTERFACE_ENTRY(ISupportErrorInfo) + + + + + + END_COM_MAP() + + + + + + + }; + + + + + + + + + #include "Logging.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #ifdef VBOX_WITH_XPCOM + + + + + + + + + + + #endif // VBOX_WITH_XPCOM + + + + + + + + + + + + + + + + + + + + + + + + + + + + IN_BSTR + + + BSTR + + + + + + + + + + + IUnknown * + + + + + + + + + + + + + + + + + + + + + + + + + const + + com::Utf8Str & + + + + const + + com::Guid & + + + + + + + + + + const + + ComPtr<IUnknown> & + + + + + + const + + + + + + + + + + + + + + + + + + + + + + %p + + + %zu + + + + + + %RU32 + + + %p + + + %p + + + + + + + + + + + + + + + + + + + + + + + ComSafeArrayIn( + + + ComSafeArrayOut( + + + + + + + , + + + + + + + + + + + + + + + a + + + + + + + + + + + + + + + + + + + + + + + const + + std::vector< + + + + + + + + + + + + + + + + + + + + + + + > & + + + + + + + + + + + + + + + + + + a + + + + + + + + + + + * + + a + + + + = + + + + + + + + + + + + + + + ComSafeArraySize( + + * + + + + * + + + a + + + + + + ) + + + + + + + + + + + + + + + + + + + Array + + + + ComTypeInConverter<IUnknown>( + + + ComTypeOutConverter<IUnknown>( + + + + + + ComSafeArrayInArg( + + + ComSafeArrayOutArg( + + + + + + + Array + + + + + ComTypeInConverter + + + ComTypeOutConverter + + + + + + + ComSafeArrayInArg( + + + ComSafeArrayOutArg( + + + + + + + Array + + + + BSTRInConverter( + + + BSTROutConverter( + + + + + + ComSafeArrayInArg( + + + ComSafeArrayOutArg( + + + + + + + Array + + + + UuidInConverter( + + + UuidOutConverter( + + + + + + ComSafeArrayInArg( + + + ComSafeArrayOutArg( + + + + + + + Array + + + InConverter + + + OutConverter + + + + + + ComSafeArrayInArg( + + + ComSafeArrayOutArg( + + + + + + a + + + + + + + + )).array() + + + ).ptr() + + + + + + + )).array() + + + ).str() + + + + + + + )).array() + + + ).uuid() + + + + + + )).array() + + + + + + + + + + + + + + + + + + + ); + + + + + + + + ); + + + + + + + + + + + + + + + + + + + + AutoCaller &aAutoCaller, + + + + + ) = 0; + + + + + + AutoCaller &aAutoCaller, + + + + + ) = 0; + + + + + + + + + + + + + + + + + + ) +{ + LogRelFlow(("{%p} %s: enter + + + + + \n", this, + + + + + + )); + + VirtualBoxBase::clearError(); + + HRESULT hrc; + + try + { + CheckComArgOutPointerValidThrow(a + + ); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + throw autoCaller.rc(); + + + + + + + + + + + autoCaller, + + + + + ); + } + catch (HRESULT hrc2) + { + hrc = hrc2; + } + catch (...) + { + hrc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); + } + + LogRelFlow(("{%p} %s: leave + + + + hrc=%Rhrc\n", this, + + + + + , hrc)); + return hrc; +} + + + + + + + + + ) +{ + LogRelFlow(("{%p} %s: enter + + + + \n", this, + + + + + )); + + VirtualBoxBase::clearError(); + + HRESULT hrc; + + try + { + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + throw autoCaller.rc(); + + + + + autoCaller, + + + + + ); + } + catch (HRESULT hrc2) + { + hrc = hrc2; + } + catch (...) + { + hrc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); + } + + LogRelFlow(("{%p} %s: leave hrc=%Rhrc\n", this, + + hrc)); + return hrc; +} + + + + + + + + + + + + + + + + + + + + + + + + // + + + +// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + STDMETHOD( + + + + )( + + + + + + , + + + + + ); + + + + + + + + + + + virtual HRESULT + + + + ( + + + + + + + + AutoCaller &aAutoCaller + + , + + + + + + + + + + , + + + + + ) = 0; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + ) +{ + LogRelFlow(("{%p} %s:enter + + + + + + + + \n", this + + + , + + + + + + )); + + VirtualBoxBase::clearError(); + + HRESULT hrc; + + try + { + + + + + CheckComArgOutPointerValidThrow(a + + + + ); + + + + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + throw autoCaller.rc(); + + + + + + + + + + + autoCaller + + , + + + + + + + + + + , + + + + + ); + } + catch (HRESULT hrc2) + { + hrc = hrc2; + } + catch (...) + { + hrc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); + } + + LogRelFlow(("{%p} %s: leave + + + + + + + + + hrc=%Rhrc\n", this + + + + , + + + + + + , hrc)); + return hrc; +} + + + + + + + + + + + + + + + + + + + + + + + // + + + +// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +private: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VBox/Main/idl/comimpl.xsl b/src/VBox/Main/idl/comimpl.xsl index 58889cbd..59ae42b8 100644 --- a/src/VBox/Main/idl/comimpl.xsl +++ b/src/VBox/Main/idl/comimpl.xsl @@ -13,7 +13,7 @@ rather trivial container classes for their read-only attributes. Further extension to other interfaces is possible and anticipated. - Copyright (C) 2010-2012 Oracle Corporation + Copyright (C) 2010-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -30,7 +30,7 @@ encoding="utf-8" indent="no"/> - + @@ -46,7 +46,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -149,6 +149,12 @@ + + + + + + @@ -189,7 +195,7 @@ - + @@ -212,7 +218,7 @@ - + @@ -293,14 +299,14 @@ - - + + - - - + + + - + @@ -321,10 +327,10 @@ - + - + @@ -332,7 +338,7 @@ - + @@ -585,7 +591,7 @@ private: - + diff --git a/src/VBox/Main/idl/docstrip.xsl b/src/VBox/Main/idl/docstrip.xsl index 0cbdac4a..9efb49ae 100644 --- a/src/VBox/Main/idl/docstrip.xsl +++ b/src/VBox/Main/idl/docstrip.xsl @@ -9,7 +9,7 @@ original XIDL should not cause a full recompile of nearly all of VirtualBox. - Copyright (C) 2009-2010 Oracle Corporation + Copyright (C) 2009-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/idl/doxygen.xsl b/src/VBox/Main/idl/doxygen.xsl index bc55d3d9..df12cd20 100644 --- a/src/VBox/Main/idl/doxygen.xsl +++ b/src/VBox/Main/idl/doxygen.xsl @@ -5,7 +5,7 @@ * definition expressed in XML. The generated file is intended solely to * generate the documentation using Doxygen. - Copyright (C) 2006-2010 Oracle Corporation + Copyright (C) 2006-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/idl/midl.xsl b/src/VBox/Main/idl/midl.xsl index 0ded778f..5ee2c302 100644 --- a/src/VBox/Main/idl/midl.xsl +++ b/src/VBox/Main/idl/midl.xsl @@ -5,7 +5,7 @@ * A template to generate a MS IDL compatible interface definition file * from the generic interface definition expressed in XML. - Copyright (C) 2006-2012 Oracle Corporation + Copyright (C) 2006-2014 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -206,7 +206,6 @@ : IDispatch - IDispatch IErrorInfo diff --git a/src/VBox/Main/idl/typemap-shared.inc.xsl b/src/VBox/Main/idl/typemap-shared.inc.xsl new file mode 100644 index 00000000..845f8fad --- /dev/null +++ b/src/VBox/Main/idl/typemap-shared.inc.xsl @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _USCORE + + + + + + diff --git a/src/VBox/Main/idl/xpidl.xsl b/src/VBox/Main/idl/xpidl.xsl index 18796ba6..8a8597b1 100644 --- a/src/VBox/Main/idl/xpidl.xsl +++ b/src/VBox/Main/idl/xpidl.xsl @@ -5,7 +5,7 @@ * A template to generate a XPCOM IDL compatible interface definition file * from the generic interface definition expressed in XML. - Copyright (C) 2006-2009 Oracle Corporation + Copyright (C) 2006-2014 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -102,19 +102,6 @@ #include "nsISupports.idl" #include "nsIException.idl" -%{C++ -/** - * For escaping compound expression so they don't cause trouble when -pedantic - * is used. - * @internal - */ -#if defined(__cplusplus) && defined(__GNUC__) -# define VBOX_GCC_EXTENSION __extension__ -#endif -#ifndef VBOX_GCC_EXTENSION -# define VBOX_GCC_EXTENSION -#endif -%} @@ -199,8 +186,16 @@ * libraries --> - %{C++ + #ifndef VBOX_EXTERN_C + # ifdef __cplusplus + # define VBOX_EXTERN_C extern "C" + # else // !__cplusplus + # define VBOX_EXTERN_C extern + # endif // !__cplusplus + #endif // !VBOX_EXTERN_C + + // result codes declared in API spec @@ -248,7 +243,6 @@ : nsISupports - nsISupports nsIException @@ -289,8 +283,12 @@ _TO_BASE(base) COM_FORWARD_ - _TO (base::) + _TO (base::) + // for compatibility with Win32 + VBOX_EXTERN_C const nsID IID_ + + ; %} @@ -660,6 +658,11 @@ %{C++ + // Definitions for module + + , class + + : #define NS_ @@ -690,13 +693,9 @@ ;1" // for compatibility with Win32 - #define CLSID_ + VBOX_EXTERN_C const nsCID CLSID_ - VBOX_GCC_EXTENSION (nsCID) NS_ - - - - _CID + ; %} diff --git a/src/VBox/Main/idl/xpidl_iid.xsl b/src/VBox/Main/idl/xpidl_iid.xsl new file mode 100644 index 00000000..1e216085 --- /dev/null +++ b/src/VBox/Main/idl/xpidl_iid.xsl @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + +/* + * DO NOT EDIT! This is a generated file. + * + * XPCOM C definitions for VirtualBox Main API (IIDs for COM interfaces) + * generated from XIDL (XML interface definition). + * + * Source : src/VBox/Main/idl/VirtualBox.xidl + * Generator : src/VBox/Main/idl/xpidl_iid.xsl + */ + +#ifndef nsID_h__ +struct nsID +{ + unsigned int m0; + unsigned short m1; + unsigned short m2; + unsigned char m3[8]; +}; + +typedef struct nsID nsID; +typedef struct nsID nsIID; +typedef struct nsID nsCID; +#endif /* nsID_h__ */ + +#ifdef __cplusplus +extern "C" { +#endif + + + + + +#ifdef __cplusplus +} +#endif + + + + + + + + + + + + + + + + + + + + + + + const nsID IID_ + + = { + 0x + , 0x + , 0x + , \ + { 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + } \ }; + + + + + + + + + + + + const nsCID CLSID_ + + = { + 0x + , 0x + , 0x + , \ + { 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + , 0x + } \ }; + + + + diff --git a/src/VBox/Main/include/ApplianceImpl.h b/src/VBox/Main/include/ApplianceImpl.h index 16c96893..937ebbfd 100644 --- a/src/VBox/Main/include/ApplianceImpl.h +++ b/src/VBox/Main/include/ApplianceImpl.h @@ -1,12 +1,10 @@ /* $Id: ApplianceImpl.h $ */ - /** @file - * * VirtualBox COM class implementation */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,6 +24,12 @@ /* Todo: This file needs massive cleanup. Split IAppliance in a public and * private classes. */ #include +#include +#include +#include + +#include "ovfreader.h" +#include /* VBox forward declarations */ class Progress; @@ -36,12 +40,15 @@ typedef struct VDINTERFACE *PVDINTERFACE; typedef struct VDINTERFACEIO *PVDINTERFACEIO; typedef struct SHASTORAGE *PSHASTORAGE; +typedef enum applianceIOName { applianceIOTar, applianceIOFile, applianceIOSha } APPLIANCEIONAME; + namespace ovf { struct HardDiskController; struct VirtualSystem; class OVFReader; struct DiskImage; + struct EnvelopeData; } namespace xml @@ -72,13 +79,7 @@ public: DECLARE_EMPTY_CTOR_DTOR (Appliance) - enum OVFFormat - { - unspecified, - OVF_0_9, - OVF_1_0, - OVF_2_0 - }; + // public initializer/uninitializer for internal purposes only HRESULT FinalConstruct() { return BaseFinalConstruct(); } @@ -100,7 +101,7 @@ public: STDMETHOD(ImportMachines)(ComSafeArrayIn(ImportOptions_T, options), IProgress **aProgress); /* Export methods */ STDMETHOD(CreateVFSExplorer)(IN_BSTR aURI, IVFSExplorer **aExplorer); - STDMETHOD(Write)(IN_BSTR format, BOOL fManifest, IN_BSTR path, IProgress **aProgress); + STDMETHOD(Write)(IN_BSTR format, ComSafeArrayIn(ExportOptions_T, options), IN_BSTR path, IProgress **aProgress); STDMETHOD(GetWarnings)(ComSafeArrayOut(BSTR, aWarnings)); @@ -141,6 +142,16 @@ private: static DECLCALLBACK(int) taskThreadImportOrExport(RTTHREAD aThread, void *pvUser); + HRESULT initSetOfSupportedStandardsURI(); + + Utf8Str typeOfVirtualDiskFormatFromURI(Utf8Str type) const; + + std::set URIFromTypeOfVirtualDiskFormat(Utf8Str type); + + HRESULT initApplianceIONameMap(); + + Utf8Str applianceIOName(APPLIANCEIONAME type) const; + /******************************************************************************* * Read stuff ******************************************************************************/ @@ -164,8 +175,19 @@ private: HRESULT importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock); HRESULT importS3(TaskOVF *pTask); - HRESULT readManifestFile(const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage); - HRESULT readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage); + HRESULT readFileToBuf(const Utf8Str &strFile, + void **ppvBuf, + size_t *pcbSize, + bool fCreateDigest, + PVDINTERFACEIO pCallbacks, + PSHASTORAGE pStorage); + HRESULT readTarFileToBuf(RTTAR tar, + const Utf8Str &strFile, + void **ppvBuf, + size_t *pcbSize, + bool fCreateDigest, + PVDINTERFACEIO pCallbacks, + PSHASTORAGE pStorage); HRESULT verifyManifestFile(const Utf8Str &strFile, ImportStack &stack, void *pvBuf, size_t cbSize); void convertDiskAttachmentValues(const ovf::HardDiskController &hdc, @@ -175,11 +197,12 @@ private: int32_t &lDevice); void importOneDiskImage(const ovf::DiskImage &di, - const Utf8Str &strTargetPath, + Utf8Str *strTargetPath, ComObjPtr &pTargetHD, ImportStack &stack, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage); + void importMachineGeneric(const ovf::VirtualSystem &vsysThis, ComObjPtr &vsdescThis, ComPtr &pNewMachine, @@ -199,7 +222,7 @@ private: * Write stuff ******************************************************************************/ - HRESULT writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, ComObjPtr &aProgress); + HRESULT writeImpl(ovf::OVFVersion_T aFormat, const LocationInfo &aLocInfo, ComObjPtr &aProgress); HRESULT writeFS(TaskOVF *pTask); HRESULT writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock); @@ -208,14 +231,21 @@ private: HRESULT writeS3(TaskOVF *pTask); struct XMLStack; - void buildXML(AutoWriteLockBase& writeLock, xml::Document &doc, XMLStack &stack, const Utf8Str &strPath, OVFFormat enFormat); + + void buildXML(AutoWriteLockBase& writeLock, + xml::Document &doc, + XMLStack &stack, + const Utf8Str &strPath, + ovf::OVFVersion_T enFormat); void buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, xml::ElementNode &elmToAddVirtualSystemsTo, std::list *pllElementsWithUuidAttributes, ComObjPtr &vsdescThis, - OVFFormat enFormat, + ovf::OVFVersion_T enFormat, XMLStack &stack); + HRESULT preCheckImageAvailability(PSHASTORAGE pSHAStorage, + RTCString &availableImage); friend class Machine; }; @@ -228,12 +258,13 @@ struct VirtualSystemDescriptionEntry VirtualSystemDescriptionType_T type; // type of this entry Utf8Str strRef; // reference number (hard disk controllers only) Utf8Str strOvf; // original OVF value (type-dependent) - Utf8Str strVboxSuggested; // configuration value (type-dependent); original value suggested by interpret() - Utf8Str strVboxCurrent; // configuration value (type-dependent); current value, either from interpret() or setFinalValue() + Utf8Str strVBoxSuggested; // configuration value (type-dependent); original value suggested by interpret() + Utf8Str strVBoxCurrent; // configuration value (type-dependent); current value, either from interpret() or setFinalValue() Utf8Str strExtraConfigSuggested; // extra configuration key=value strings (type-dependent); original value suggested by interpret() Utf8Str strExtraConfigCurrent; // extra configuration key=value strings (type-dependent); current value, either from interpret() or setFinalValue() uint32_t ulSizeMB; // hard disk images only: a copy of ovf::DiskImage::ulSuggestedSizeMB + bool skipIt; ///< used during export to skip some parts if it's needed }; class ATL_NO_VTABLE VirtualSystemDescription : @@ -269,14 +300,14 @@ public: STDMETHOD(GetDescription)(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes), ComSafeArrayOut(BSTR, aRefs), ComSafeArrayOut(BSTR, aOvfValues), - ComSafeArrayOut(BSTR, aVboxValues), + ComSafeArrayOut(BSTR, aVBoxValues), ComSafeArrayOut(BSTR, aExtraConfigValues)); STDMETHOD(GetDescriptionByType)(VirtualSystemDescriptionType_T aType, ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes), ComSafeArrayOut(BSTR, aRefs), ComSafeArrayOut(BSTR, aOvfValues), - ComSafeArrayOut(BSTR, aVboxValues), + ComSafeArrayOut(BSTR, aVBoxValues), ComSafeArrayOut(BSTR, aExtraConfigValues)); STDMETHOD(GetValuesByType)(VirtualSystemDescriptionType_T aType, @@ -284,28 +315,29 @@ public: ComSafeArrayOut(BSTR, aValues)); STDMETHOD(SetFinalValues)(ComSafeArrayIn(BOOL, aEnabled), - ComSafeArrayIn(IN_BSTR, aVboxValues), + ComSafeArrayIn(IN_BSTR, aVBoxValues), ComSafeArrayIn(IN_BSTR, aExtraConfigValues)); STDMETHOD(AddDescription)(VirtualSystemDescriptionType_T aType, - IN_BSTR aVboxValue, + IN_BSTR aVBoxValue, IN_BSTR aExtraConfigValue); /* public methods only for internal purposes */ - void addEntry(VirtualSystemDescriptionType_T aType, const Utf8Str &strRef, const Utf8Str &aOvfValue, - const Utf8Str &aVboxValue, + const Utf8Str &aVBoxValue, uint32_t ulSizeMB = 0, const Utf8Str &strExtraConfig = ""); std::list findByType(VirtualSystemDescriptionType_T aType); const VirtualSystemDescriptionEntry* findControllerFromID(uint32_t id); - void importVboxMachineXML(const xml::ElementNode &elmMachine); + void importVBoxMachineXML(const xml::ElementNode &elmMachine); const settings::MachineConfigFile* getMachineConfig() const; + void removeByType(VirtualSystemDescriptionType_T aType); + /* private instance data */ private: struct Data; @@ -314,5 +346,5 @@ private: friend class Machine; }; -#endif // ____H_APPLIANCEIMPL +#endif // !____H_APPLIANCEIMPL /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/ApplianceImplPrivate.h b/src/VBox/Main/include/ApplianceImplPrivate.h index ee2f39d8..d36754a3 100644 --- a/src/VBox/Main/include/ApplianceImplPrivate.h +++ b/src/VBox/Main/include/ApplianceImplPrivate.h @@ -1,10 +1,9 @@ /** @file - * * VirtualBox Appliance private data definitions */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,6 +20,7 @@ class VirtualSystemDescription; #include "ovfreader.h" +#include //////////////////////////////////////////////////////////////////////////////// // @@ -47,11 +47,13 @@ struct LocationInfo struct Appliance::Data { enum ApplianceState { ApplianceIdle, ApplianceImporting, ApplianceExporting }; + enum digest_T {SHA1, SHA256}; Data() : state(ApplianceIdle) , fManifest(true) , fSha256(false) + , fExportISOImages(false) , pReader(NULL) , ulWeightForXmlOperation(0) , ulWeightForManifestOperation(0) @@ -74,7 +76,12 @@ struct Appliance::Data LocationInfo locInfo; // location info for the currently processed OVF bool fManifest; // Create a manifest file on export bool fSha256; // true = SHA256 (OVF 2.0), false = SHA1 (OVF 1.0) - RTCList optList; + Utf8Str strOVFSHADigest;//SHA digest of OVf file. It is stored here after reading OVF file (before import) + + bool fExportISOImages;// when 1 the ISO images are exported + + RTCList optListImport; + RTCList optListExport; ovf::OVFReader *pReader; @@ -87,7 +94,6 @@ struct Appliance::Data ULONG ulWeightForManifestOperation; ULONG ulTotalDisksMB; ULONG cDisks; - Utf8Str strOVFSHADigest; std::list llGuidsMachinesCreated; }; @@ -115,7 +121,7 @@ struct Appliance::TaskOVF taskType(aType), locInfo(aLocInfo), pProgress(aProgress), - enFormat(unspecified), + enFormat(ovf::OVFVersion_unknown), rc(S_OK) {} @@ -128,7 +134,7 @@ struct Appliance::TaskOVF const LocationInfo locInfo; ComObjPtr pProgress; - OVFFormat enFormat; + ovf::OVFVersion_T enFormat; HRESULT rc; }; @@ -221,10 +227,11 @@ struct VirtualSystemDescription::Data void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr); -ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox); +ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVBox, BOOL fLongMode); Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type); + typedef struct SHASTORAGE { PVDINTERFACE pVDImageIfaces; @@ -238,6 +245,7 @@ PVDINTERFACEIO FileCreateInterface(); PVDINTERFACEIO TarCreateInterface(); int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser); int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser); - -#endif // ____H_APPLIANCEIMPLPRIVATE +int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser); +int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser); +#endif // !____H_APPLIANCEIMPLPRIVATE diff --git a/src/VBox/Main/include/AudioAdapterImpl.h b/src/VBox/Main/include/AudioAdapterImpl.h index d2c91b30..157664fa 100644 --- a/src/VBox/Main/include/AudioAdapterImpl.h +++ b/src/VBox/Main/include/AudioAdapterImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/AudioSnifferInterface.h b/src/VBox/Main/include/AudioSnifferInterface.h index 3c467bc7..e7461f5f 100644 --- a/src/VBox/Main/include/AudioSnifferInterface.h +++ b/src/VBox/Main/include/AudioSnifferInterface.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/AutoCaller.h b/src/VBox/Main/include/AutoCaller.h index 207d3589..9b155c5b 100644 --- a/src/VBox/Main/include/AutoCaller.h +++ b/src/VBox/Main/include/AutoCaller.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/BIOSSettingsImpl.h b/src/VBox/Main/include/BIOSSettingsImpl.h index dffff1d0..660ff0d3 100644 --- a/src/VBox/Main/include/BIOSSettingsImpl.h +++ b/src/VBox/Main/include/BIOSSettingsImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -71,6 +71,7 @@ public: STDMETHOD(COMSETTER(PXEDebugEnabled))(BOOL enable); STDMETHOD(COMGETTER)(TimeOffset)(LONG64 *offset); STDMETHOD(COMSETTER)(TimeOffset)(LONG64 offset); + STDMETHOD(COMGETTER)(NonVolatileStorageFile)(BSTR *pbstrPath); // public methods only for internal purposes diff --git a/src/VBox/Main/include/BandwidthGroupImpl.h b/src/VBox/Main/include/BandwidthGroupImpl.h index 98a6b86c..dbcf1591 100644 --- a/src/VBox/Main/include/BandwidthGroupImpl.h +++ b/src/VBox/Main/include/BandwidthGroupImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/ClientToken.h b/src/VBox/Main/include/ClientToken.h new file mode 100644 index 00000000..d452269d --- /dev/null +++ b/src/VBox/Main/include/ClientToken.h @@ -0,0 +1,105 @@ +/* $Id: ClientToken.h $ */ + +/** @file + * + * VirtualBox API client session token abstraction + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_CLIENTTOKEN +#define ____H_CLIENTTOKEN + +#include +#include + +#include "MachineImpl.h" +#ifdef VBOX_WITH_GENERIC_SESSION_WATCHER +# include "TokenImpl.h" +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + +#if defined(RT_OS_WINDOWS) +# define CTTOKENARG NULL +# define CTTOKENTYPE HANDLE +#elif defined(RT_OS_OS2) +# define CTTOKENARG NULLHANDLE +# define CTTOKENTYPE HMTX +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) +# define CTTOKENARG -1 +# define CTTOKENTYPE int +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) +# define CTTOKENARG NULL +# define CTTOKENTYPE MachineToken * +#else +# error "Port me!" +#endif + +/** + * Class which represents a token which can be used to check for client + * crashes and similar purposes. + */ +class Machine::ClientToken +{ +public: + /** + * Constructor which creates a usable instance + * + * @param pMachine Reference to Machine object + * @param pSessionMachine Reference to corresponding SessionMachine object + */ + ClientToken(const ComObjPtr &pMachine, SessionMachine *pSessionMachine); + + /** + * Default destructor. Cleans everything up. + */ + ~ClientToken(); + + /** + * Check if object contains a usable token. + */ + bool isReady(); + + /** + * Query token ID, which is a unique string value for this token. Do not + * assume any specific content/format, it is opaque information. + */ + void getId(Utf8Str &strId); + + /** + * Query token, which is platform dependent. + */ + CTTOKENTYPE getToken(); + +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + /** + * Release token now. Returns information if the client has terminated. + */ + bool release(); +#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */ + +private: + /** + * Default constructor. Don't use, will not create a sensible instance. + */ + ClientToken(); + + Machine *mMachine; + CTTOKENTYPE mClientToken; + Utf8Str mClientTokenId; +#ifdef VBOX_WITH_GENERIC_SESSION_WATCHER + bool mClientTokenPassed; +#endif +}; + +#endif /* !____H_CLIENTTOKEN */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/ClientTokenHolder.h b/src/VBox/Main/include/ClientTokenHolder.h new file mode 100644 index 00000000..30a2e51c --- /dev/null +++ b/src/VBox/Main/include/ClientTokenHolder.h @@ -0,0 +1,99 @@ +/* $Id: ClientTokenHolder.h $ */ + +/** @file + * + * VirtualBox API client session token holder (in the client process) + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_CLIENTTOKENHOLDER +#define ____H_CLIENTTOKENHOLDER + +#include "SessionImpl.h" + +#if defined(RT_OS_WINDOWS) +# define CTHSEMARG NULL +# define CTHSEMTYPE HANDLE +/* this second semaphore is only used on Windows */ +# define CTHTHREADSEMARG NULL +# define CTHTHREADSEMTYPE HANDLE +#elif defined(RT_OS_OS2) +# define CTHSEMARG NIL_RTSEMEVENT +# define CTHSEMTYPE RTSEMEVENT +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) +# define CTHSEMARG -1 +# define CTHSEMTYPE int +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) +/* the token object based implementation needs no semaphores */ +#else +# error "Port me!" +#endif + + +/** + * Class which holds a client token. + */ +class Session::ClientTokenHolder +{ +public: +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + /** + * Constructor which creates a usable instance + * + * @param strTokenId String with identifier of the token + */ + ClientTokenHolder(const Utf8Str &strTokenId); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + /** + * Constructor which creates a usable instance + * + * @param aToken Reference to token object + */ + ClientTokenHolder(IToken *aToken); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + + /** + * Default destructor. Cleans everything up. + */ + ~ClientTokenHolder(); + + /** + * Check if object contains a usable token. + */ + bool isReady(); + +private: + /** + * Default constructor. Don't use, will not create a sensible instance. + */ + ClientTokenHolder(); + +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + Utf8Str mClientTokenId; +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + ComPtr mToken; +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +#ifdef CTHSEMTYPE + CTHSEMTYPE mSem; +#endif +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + RTTHREAD mThread; +#endif +#ifdef RT_OS_WINDOWS + CTHTHREADSEMTYPE mThreadSem; +#endif +}; + +#endif /* !____H_CLIENTTOKENHOLDER */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/ClientWatcher.h b/src/VBox/Main/include/ClientWatcher.h new file mode 100644 index 00000000..6e9d26b6 --- /dev/null +++ b/src/VBox/Main/include/ClientWatcher.h @@ -0,0 +1,88 @@ +/* $Id: ClientWatcher.h $ */ + +/** @file + * + * VirtualBox API client session watcher + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_CLIENTWATCHER +#define ____H_CLIENTWATCHER + +#include +#include +#include + +#include "VirtualBoxImpl.h" + +#if defined(RT_OS_WINDOWS) +# define CWUPDATEREQARG NULL +# define CWUPDATEREQTYPE HANDLE +#elif defined(RT_OS_OS2) +# define CWUPDATEREQARG NIL_RTSEMEVENT +# define CWUPDATEREQTYPE RTSEMEVENT +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER) +# define CWUPDATEREQARG NIL_RTSEMEVENT +# define CWUPDATEREQTYPE RTSEMEVENT +#else +# error "Port me!" +#endif + +/** + * Class which checks for API clients which have crashed/exited, and takes + * the necessary cleanup actions. Singleton. + */ +class VirtualBox::ClientWatcher +{ +public: + /** + * Constructor which creates a usable instance + * + * @param pVirtualBox Reference to VirtualBox object + */ + ClientWatcher(const ComObjPtr &pVirtualBox); + + /** + * Default destructor. Cleans everything up. + */ + ~ClientWatcher(); + + bool isReady(); + + void update(); + void addProcess(RTPROCESS pid); + +private: + /** + * Default constructor. Don't use, will not create a sensible instance. + */ + ClientWatcher(); + + static DECLCALLBACK(int) worker(RTTHREAD /* thread */, void *pvUser); + + VirtualBox *mVirtualBox; + RTTHREAD mThread; + CWUPDATEREQTYPE mUpdateReq; + util::RWLockHandle mLock; + + typedef std::list ProcessList; + ProcessList mProcesses; + +#if defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + uint8_t mUpdateAdaptCtr; +#endif +}; + +#endif /* !____H_CLIENTWATCHER */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/ConsoleEvents.h b/src/VBox/Main/include/ConsoleEvents.h index 8e82338c..a4718acd 100644 --- a/src/VBox/Main/include/ConsoleEvents.h +++ b/src/VBox/Main/include/ConsoleEvents.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h index 72066ad5..5e5cb696 100644 --- a/src/VBox/Main/include/ConsoleImpl.h +++ b/src/VBox/Main/include/ConsoleImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2012 Oracle Corporation + * Copyright (C) 2005-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,11 +32,9 @@ class OUSBDevice; class RemoteUSBDevice; class SharedFolder; class VRDEServerInfo; +class EmulatedUSB; class AudioSniffer; class Nvram; -#ifdef VBOX_WITH_USB_VIDEO -class UsbWebcamInterface; -#endif #ifdef VBOX_WITH_USB_CARDREADER class UsbCardReader; #endif @@ -48,6 +46,8 @@ COM_STRUCT_OR_CLASS(IEventListener); #ifdef VBOX_WITH_EXTPACK class ExtPackManager; #endif +class VMMDevMouseInterface; +class DisplayMouseInterface; #include #include @@ -88,10 +88,21 @@ typedef struct VUSBIRHCONFIG *PVUSBIRHCONFIG; // Console /////////////////////////////////////////////////////////////////////////////// +class ConsoleMouseInterface +{ +public: + virtual VMMDevMouseInterface *getVMMDevMouseInterface() = 0; + virtual DisplayMouseInterface *getDisplayMouseInterface() = 0; + virtual void onMouseCapabilityChange(BOOL supportsAbsolute, + BOOL supportsRelative, + BOOL supportsMT, + BOOL needsHostCursor) = 0; +}; + /** IConsole implementation class */ class ATL_NO_VTABLE Console : public VirtualBoxBase, - VBOX_SCRIPTABLE_IMPL(IConsole) + VBOX_SCRIPTABLE_IMPL(IConsole), public ConsoleMouseInterface { Q_OBJECT @@ -133,6 +144,7 @@ public: STDMETHOD(COMGETTER(AttachedPCIDevices))(ComSafeArrayOut(IPCIDeviceAttachment *, aAttachments)); STDMETHOD(COMGETTER(UseHostClipboard))(BOOL *aUseHostClipboard); STDMETHOD(COMSETTER(UseHostClipboard))(BOOL aUseHostClipboard); + STDMETHOD(COMGETTER(EmulatedUSB))(IEmulatedUSB **aEmulatedUSB); // IConsole methods STDMETHOD(PowerUp)(IProgress **aProgress); @@ -200,12 +212,15 @@ public: HRESULT onClipboardModeChange(ClipboardMode_T aClipboardMode); HRESULT onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode); HRESULT onVRDEServerChange(BOOL aRestart); + HRESULT onVideoCaptureChange(); HRESULT onUSBControllerChange(); HRESULT onSharedFolderChange(BOOL aGlobal); HRESULT onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError, ULONG aMaskedIfs); HRESULT onUSBDeviceDetach(IN_BSTR aId, IVirtualBoxErrorInfo *aError); HRESULT onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup); - HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove); + HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent); + HRESULT onExtraDataChange(IN_BSTR aMachineId, IN_BSTR aKey, IN_BSTR aVal); + HRESULT getGuestProperty(IN_BSTR aKey, BSTR *aValue, LONG64 *aTimestamp, BSTR *aFlags); HRESULT setGuestProperty(IN_BSTR aKey, IN_BSTR aValue, IN_BSTR aFlags); HRESULT enumerateGuestProperties(IN_BSTR aPatterns, @@ -215,10 +230,8 @@ public: ComSafeArrayOut(BSTR, aFlags)); HRESULT onlineMergeMedium(IMediumAttachment *aMediumAttachment, ULONG aSourceIdx, ULONG aTargetIdx, - IMedium *aSource, IMedium *aTarget, - BOOL aMergeForward, IMedium *aParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent), IProgress *aProgress); + int hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName); VMMDev *getVMMDev() { return m_pVMMDev; } AudioSniffer *getAudioSniffer() { return mAudioSniffer; } #ifdef VBOX_WITH_EXTPACK @@ -238,28 +251,34 @@ public: void VRDPInterceptClipboard(uint32_t u32ClientId); void processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *pDevList, uint32_t cbDevList, bool fDescExt); - void reportGuestStatistics(ULONG aValidStats, ULONG aCpuUser, + void reportVmStatistics(ULONG aValidStats, ULONG aCpuUser, ULONG aCpuKernel, ULONG aCpuIdle, ULONG aMemTotal, ULONG aMemFree, ULONG aMemBalloon, ULONG aMemShared, ULONG aMemCache, ULONG aPageTotal, ULONG aAllocVMM, ULONG aFreeVMM, - ULONG aBalloonedVMM, ULONG aSharedVMM) + ULONG aBalloonedVMM, ULONG aSharedVMM, + ULONG aVmNetRx, ULONG aVmNetTx) { - mControl->ReportGuestStatistics(aValidStats, aCpuUser, aCpuKernel, aCpuIdle, - aMemTotal, aMemFree, aMemBalloon, aMemShared, - aMemCache, aPageTotal, aAllocVMM, aFreeVMM, - aBalloonedVMM, aSharedVMM); + mControl->ReportVmStatistics(aValidStats, aCpuUser, aCpuKernel, aCpuIdle, + aMemTotal, aMemFree, aMemBalloon, aMemShared, + aMemCache, aPageTotal, aAllocVMM, aFreeVMM, + aBalloonedVMM, aSharedVMM, aVmNetRx, aVmNetTx); } void enableVMMStatistics(BOOL aEnable); + HRESULT pause(Reason_T aReason); + HRESULT resume(Reason_T aReason); + HRESULT saveState(Reason_T aReason, IProgress **aProgress); + // callback callers (partly; for some events console callbacks are notified // directly from IInternalSessionControl event handlers declared above) void onMousePointerShapeChange(bool fVisible, bool fAlpha, uint32_t xHot, uint32_t yHot, uint32_t width, uint32_t height, ComSafeArrayIn(uint8_t, aShape)); - void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, BOOL needsHostCursor); + void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, + BOOL supportsMT, BOOL needsHostCursor); void onStateChange(MachineState_T aMachineState); void onAdditionsStateChange(); void onAdditionsOutdated(); @@ -281,10 +300,16 @@ public: HRESULT onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove, NATProtocol_T aProto, IN_BSTR aHostIp, LONG aHostPort, IN_BSTR aGuestIp, LONG aGuestPort); + // Mouse interface + VMMDevMouseInterface *getVMMDevMouseInterface(); + DisplayMouseInterface *getDisplayMouseInterface(); + + EmulatedUSB *getEmulatedUSB(void) { return mEmulatedUSB; } + private: /** - * Base template for AutoVMCaller and SaveVMPtr. Template arguments + * Base template for AutoVMCaller and SafeVMPtr. Template arguments * have the same meaning as arguments of Console::addVMCaller(). */ template @@ -328,15 +353,15 @@ private: #if 0 /** - * Helper class that protects sections of code using the mpVM pointer by + * Helper class that protects sections of code using the mpUVM pointer by * automatically calling addVMCaller() on construction and * releaseVMCaller() on destruction. Intended for Console methods dealing - * with mpVM. The usage pattern is: + * with mpUVM. The usage pattern is: * * AutoVMCaller autoVMCaller(this); * if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); * ... - * VMR3ReqCall (mpVM, ... + * VMR3ReqCall (mpUVM, ... * * * @note Temporarily locks the argument for writing. @@ -375,56 +400,52 @@ private: typedef AutoVMCallerBase AutoVMCallerQuietWeak; /** - * Base template for SaveVMPtr and SaveVMPtrQuiet. + * Base template for SafeVMPtr and SafeVMPtrQuiet. */ template class SafeVMPtrBase : public AutoVMCallerBase { typedef AutoVMCallerBase Base; public: - SafeVMPtrBase(Console *aThat) : Base(aThat), mpVM(NULL), mpUVM(NULL) + SafeVMPtrBase(Console *aThat) : Base(aThat), mpUVM(NULL) { if (SUCCEEDED(Base::mRC)) - Base::mRC = aThat->safeVMPtrRetainer(&mpVM, &mpUVM, taQuiet); + Base::mRC = aThat->safeVMPtrRetainer(&mpUVM, taQuiet); } ~SafeVMPtrBase() { if (SUCCEEDED(Base::mRC)) release(); } - /** Smart SaveVMPtr to PVM cast operator */ - operator PVM() const { return mpVM; } - /** Direct PVM access for printf()-like functions */ - PVM raw() const { return mpVM; } - /** Direct PUVM access for printf()-like functions */ + /** Direct PUVM access. */ PUVM rawUVM() const { return mpUVM; } /** Release the handles. */ void release() { AssertReturnVoid(SUCCEEDED(Base::mRC)); - Base::mThat->safeVMPtrReleaser(&mpVM, &mpUVM); + Base::mThat->safeVMPtrReleaser(&mpUVM); Base::releaseCaller(); } private: - PVM mpVM; PUVM mpUVM; DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeVMPtrBase) }; public: - /** - * Helper class that safely manages the Console::mpVM pointer + /* + * Helper class that safely manages the Console::mpUVM pointer * by calling addVMCaller() on construction and releaseVMCaller() on * destruction. Intended for Console children. The usage pattern is: * - * Console::SaveVMPtr pVM(mParent); - * if (FAILED(pVM.rc())) return pVM.rc(); + * Console::SafeVMPtr ptrVM(mParent); + * if (!ptrVM.isOk()) + * return ptrVM.rc(); * ... - * VMR3ReqCall(pVM, ... + * VMR3ReqCall(ptrVM.rawUVM(), ... * ... - * printf("%p\n", pVM.raw()); + * printf("%p\n", ptrVM.rawUVM()); * * * @note Temporarily locks the argument for writing. @@ -434,11 +455,11 @@ public: typedef SafeVMPtrBase SafeVMPtr; /** - * A deviation of SaveVMPtr that doesn't set the error info on failure. + * A deviation of SafeVMPtr that doesn't set the error info on failure. * Intended for pieces of code that don't need to return the VM access * failure to the caller. The usage pattern is: * - * Console::SaveVMPtrQuiet pVM(mParent); + * Console::SafeVMPtrQuiet pVM(mParent); * if (pVM.rc()) * VMR3ReqCall(pVM, ... * return S_OK; @@ -487,8 +508,8 @@ private: HRESULT addVMCaller(bool aQuiet = false, bool aAllowNullVM = false); void releaseVMCaller(); - HRESULT safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool aQuiet); - void safeVMPtrReleaser(PVM *a_ppVM, PUVM *a_ppUVM); + HRESULT safeVMPtrRetainer(PUVM *a_ppUVM, bool aQuiet); + void safeVMPtrReleaser(PUVM *a_ppUVM); HRESULT consoleInitReleaseLog(const ComPtr aMachine); @@ -519,10 +540,20 @@ private: HRESULT createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData); HRESULT removeSharedFolder(const Utf8Str &strName); - static DECLCALLBACK(int) configConstructor(PVM pVM, void *pvConsole); - int configConstructorInner(PVM pVM, AutoWriteLock *pAlock); - int configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMachine); + HRESULT suspendBeforeConfigChange(PUVM pUVM, AutoWriteLock *pAlock, bool *pfResume); + void resumeAfterConfigChange(PUVM pUVM); + static DECLCALLBACK(int) configConstructor(PUVM pUVM, PVM pVM, void *pvConsole); + int configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock); + int configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine); + int configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine); + + int configGraphicsController(PCFGMNODE pDevices, + const GraphicsControllerType_T graphicsController, + BusAssignmentManager *pBusMgr, + const ComPtr &pMachine, + const ComPtr &biosSettings, + bool fHMEnabled); int configMediumAttachment(PCFGMNODE pCtlInst, const char *pcszDevice, unsigned uInstance, @@ -538,8 +569,9 @@ private: bool fAttachDetach, bool fForceUnmount, bool fHotplug, - PVM pVM, - DeviceType_T *paLedDevType); + PUVM pUVM, + DeviceType_T *paLedDevType, + PCFGMNODE *ppLunL0); int configMedium(PCFGMNODE pLunL0, bool fPassthrough, DeviceType_T enmType, @@ -553,8 +585,8 @@ private: IMedium *pMedium, MachineState_T aMachineState, HRESULT *phrc); - static DECLCALLBACK(int) reconfigureMediumAttachment(Console *pConsole, - PVM pVM, + static DECLCALLBACK(int) reconfigureMediumAttachment(Console *pThis, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, @@ -567,7 +599,7 @@ private: MachineState_T aMachineState, HRESULT *phrc); static DECLCALLBACK(int) changeRemovableMedium(Console *pThis, - PVM pVM, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, @@ -575,7 +607,7 @@ private: IMediumAttachment *aMediumAtt, bool fForce); - HRESULT attachRawPCIDevices(PVM pVM, BusAssignmentManager *BusMgr, PCFGMNODE pDevices); + HRESULT attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *BusMgr, PCFGMNODE pDevices); void attachStatusDriver(PCFGMNODE pCtlInst, PPDMLED *papLeds, uint64_t uFirst, uint64_t uLast, Console::MediumAttachmentMap *pmapMediumAttachments, @@ -586,19 +618,18 @@ private: PCFGMNODE pLunL0, PCFGMNODE pInst, bool fAttachDetach, bool fIgnoreConnectFailure); - static DECLCALLBACK(int) configGuestProperties(void *pvConsole, PVM pVM); + static DECLCALLBACK(int) configGuestProperties(void *pvConsole, PUVM pUVM); static DECLCALLBACK(int) configGuestControl(void *pvConsole); - static DECLCALLBACK(void) vmstateChangeCallback(PVM aVM, VMSTATE aState, - VMSTATE aOldState, void *aUser); - static DECLCALLBACK(int) unplugCpu(Console *pThis, PVM pVM, unsigned uCpu); - static DECLCALLBACK(int) plugCpu(Console *pThis, PVM pVM, unsigned uCpu); - HRESULT doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PVM pVM); - HRESULT doCPURemove(ULONG aCpu, PVM pVM); - HRESULT doCPUAdd(ULONG aCpu, PVM pVM); - - HRESULT doNetworkAdapterChange(PVM pVM, const char *pszDevice, unsigned uInstance, + static DECLCALLBACK(void) vmstateChangeCallback(PUVM pUVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser); + static DECLCALLBACK(int) unplugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu); + static DECLCALLBACK(int) plugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu); + HRESULT doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PUVM pUVM); + HRESULT doCPURemove(ULONG aCpu, PUVM pUVM); + HRESULT doCPUAdd(ULONG aCpu, PUVM pUVM); + + HRESULT doNetworkAdapterChange(PUVM pUVM, const char *pszDevice, unsigned uInstance, unsigned uLun, INetworkAdapter *aNetworkAdapter); - static DECLCALLBACK(int) changeNetworkAttachment(Console *pThis, PVM pVM, const char *pszDevice, + static DECLCALLBACK(int) changeNetworkAttachment(Console *pThis, PUVM pUVM, const char *pszDevice, unsigned uInstance, unsigned uLun, INetworkAdapter *aNetworkAdapter); @@ -609,40 +640,41 @@ private: HRESULT attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs); HRESULT detachUSBDevice(const ComObjPtr &aHostDevice); - static DECLCALLBACK(int) usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, + static DECLCALLBACK(int) usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs); - static DECLCALLBACK(int) usbDetachCallback(Console *that, PVM pVM, PCRTUUID aUuid); + static DECLCALLBACK(int) usbDetachCallback(Console *that, PUVM pUVM, PCRTUUID aUuid); #endif static DECLCALLBACK(int) attachStorageDevice(Console *pThis, - PVM pVM, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, bool fUseHostIOCache, - IMediumAttachment *aMediumAtt); + IMediumAttachment *aMediumAtt, + bool fSilent); static DECLCALLBACK(int) detachStorageDevice(Console *pThis, - PVM pVM, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, - IMediumAttachment *aMediumAtt); - HRESULT doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM); - HRESULT doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM); + IMediumAttachment *aMediumAtt, + bool fSilent); + HRESULT doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent); + HRESULT doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent); static DECLCALLBACK(int) fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser); - static DECLCALLBACK(int) stateProgressCallback(PVM pVM, unsigned uPercent, void *pvUser); + static DECLCALLBACK(int) stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser); - static DECLCALLBACK(void) genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, + static DECLCALLBACK(void) genericVMSetErrorCallback(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszErrorFmt, va_list va); - static void setVMRuntimeErrorCallbackF(PVM pVM, void *pvUser, uint32_t fFatal, - const char *pszErrorId, const char *pszFormat, ...); - static DECLCALLBACK(void) setVMRuntimeErrorCallback(PVM pVM, void *pvUser, uint32_t fFatal, + void setVMRuntimeErrorCallbackF(uint32_t fFatal, const char *pszErrorId, const char *pszFormat, ...); + static DECLCALLBACK(void) setVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFatal, const char *pszErrorId, const char *pszFormat, va_list va); - HRESULT captureUSBDevices(PVM pVM); + HRESULT captureUSBDevices(PUVM pUVM); void detachAllUSBDevices(bool aDone); static DECLCALLBACK(int) powerUpThread(RTTHREAD Thread, void *pvUser); @@ -654,6 +686,7 @@ private: static DECLCALLBACK(void) vmm2User_NotifyEmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu); static DECLCALLBACK(void) vmm2User_NotifyPdmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM); static DECLCALLBACK(void) vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM); + static DECLCALLBACK(void) vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM); static DECLCALLBACK(void *) drvStatus_QueryInterface(PPDMIBASE pInterface, const char *pszIID); static DECLCALLBACK(void) drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN); @@ -695,6 +728,8 @@ private: void guestPropertiesVRDPUpdateDisconnect(uint32_t u32ClientId); #endif + bool isResetTurnedIntoPowerOff(void); + /** @name Teleporter support * @{ */ static DECLCALLBACK(int) teleporterSrcThreadWrapper(RTTHREAD hThread, void *pvUser); @@ -714,6 +749,8 @@ private: const ComPtr mVRDEServer; ConsoleVRDPServer * const mConsoleVRDPServer; + bool mfVRDEChangeInProcess; + bool mfVRDEChangePending; const ComObjPtr mGuest; const ComObjPtr mKeyboard; @@ -728,6 +765,7 @@ private: #ifdef VBOX_WITH_EXTPACK const ComObjPtr mptrExtPackManager; #endif + const ComObjPtr mEmulatedUSB; USBDeviceList mUSBDevices; RemoteUSBDeviceList mRemoteUSBDevices; @@ -738,13 +776,13 @@ private: /** The user mode VM handle. */ PUVM mpUVM; - /** Holds the number of "readonly" mpVM callers (users) */ + /** Holds the number of "readonly" mpUVM callers (users). */ uint32_t mVMCallers; - /** Semaphore posted when the number of mpVM callers drops to zero */ + /** Semaphore posted when the number of mpUVM callers drops to zero. */ RTSEMEVENT mVMZeroCallersSem; - /** true when Console has entered the mpVM destruction phase */ + /** true when Console has entered the mpUVM destruction phase. */ bool mVMDestroying : 1; - /** true when power down is initiated by vmstateChangeCallback (EMT) */ + /** true when power down is initiated by vmstateChangeCallback (EMT). */ bool mVMPoweredOff : 1; /** true when vmstateChangeCallback shouldn't initiate a power down. */ bool mVMIsAlreadyPoweringOff : 1; @@ -754,6 +792,10 @@ private: bool mfSnapshotFolderExt4WarningShown : 1; /** true if we already listed the disk type of the snapshot folder. */ bool mfSnapshotFolderDiskTypeShown : 1; + /** true if a USB controller is available (i.e. USB devices can be attached). */ + bool mfVMHasUsbController : 1; + /** true if the VM power off was caused by reset. */ + bool mfPowerOffCausedByReset : 1; /** Pointer to the VMM -> User (that's us) callbacks. */ struct MYVMM2USERMETHODS : public VMM2USERMETHODS @@ -772,9 +814,6 @@ private: VMMDev * m_pVMMDev; AudioSniffer * const mAudioSniffer; Nvram * const mNvram; -#ifdef VBOX_WITH_USB_VIDEO - UsbWebcamInterface * const mUsbWebcamInterface; -#endif #ifdef VBOX_WITH_USB_CARDREADER UsbCardReader * const mUsbCardReader; #endif diff --git a/src/VBox/Main/include/ConsoleVRDPServer.h b/src/VBox/Main/include/ConsoleVRDPServer.h index e8e774ef..ee87367c 100644 --- a/src/VBox/Main/include/ConsoleVRDPServer.h +++ b/src/VBox/Main/include/ConsoleVRDPServer.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -27,6 +27,9 @@ #include #include #include +#define VRDE_VIDEOIN_WITH_VRDEINTERFACE /* Get the VRDE interface definitions. */ +#include +#include #include #include @@ -36,6 +39,8 @@ // ConsoleVRDPServer /////////////////////////////////////////////////////////////////////////////// +class EmWebcam; + typedef struct _VRDPInputSynch { int cGuestNumLockAdaptions; @@ -123,7 +128,7 @@ public: * Forwarders to VRDP server library. */ void SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const; - void SendResize (void) const; + void SendResize (void); void SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const; void SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format) const; @@ -140,13 +145,17 @@ public: uint32_t cBits); void SendAudioInputEnd(void *pvUserCtx); -#ifdef VBOX_WITH_USB_VIDEO - int GetVideoFrameDimensions(uint16_t *pu16Heigh, uint16_t *pu16Width); - int SendVideoSreamOn(bool fFetch); -#endif int SCardRequest(void *pvUser, uint32_t u32Function, const void *pvData, uint32_t cbData); + int VideoInDeviceAttach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, void *pvDeviceCtx); + int VideoInDeviceDetach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle); + int VideoInGetDeviceDesc(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle); + int VideoInControl(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + const VRDEVIDEOINCTRLHDR *pReq, uint32_t cbReq); + + Console *getConsole(void) { return mConsole; } + private: /* Note: This is not a ComObjPtr here, because the ConsoleVRDPServer object * is actually just a part of the Console. @@ -156,6 +165,8 @@ private: HVRDESERVER mhServer; int mServerInterfaceVersion; + int32_t volatile mcInResize; /* Do not Stop the server if this is not 0. */ + static int loadVRDPLibrary (const char *pszLibraryName); /** Static because will never load this more than once! */ @@ -237,19 +248,21 @@ private: uint32_t volatile mu32AudioInputClientId; + int32_t volatile mcClients; + static DECLCALLBACK(void) H3DORBegin(const void *pvContext, void **ppvInstance, const char *pszFormat); static DECLCALLBACK(void) H3DORGeometry(void *pvInstance, int32_t x, int32_t y, uint32_t w, uint32_t h); static DECLCALLBACK(void) H3DORVisibleRegion(void *pvInstance, - uint32_t cRects, RTRECT *paRects); + uint32_t cRects, const RTRECT *paRects); static DECLCALLBACK(void) H3DORFrame(void *pvInstance, void *pvData, uint32_t cbData); static DECLCALLBACK(void) H3DOREnd(void *pvInstance); static DECLCALLBACK(int) H3DORContextProperty(const void *pvContext, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut); - void remote3DRedirect(void); + void remote3DRedirect(bool fEnable); /* * VRDE server optional interfaces. @@ -301,6 +314,49 @@ private: static DECLCALLBACK(int) tsmfHostChannelControl(void *pvInstance, uint32_t u32Code, const void *pvParm, uint32_t cbParm, const void *pvData, uint32_t cbData, uint32_t *pcbDataReturned); + int tsmfLock(void); + void tsmfUnlock(void); + RTCRITSECT mTSMFLock; + + /* Video input interface. */ + VRDEVIDEOININTERFACE m_interfaceVideoIn; + VRDEVIDEOINCALLBACKS m_interfaceCallbacksVideoIn; + static DECLCALLBACK(void) VRDECallbackVideoInNotify(void *pvCallback, + uint32_t u32Id, + const void *pvData, + uint32_t cbData); + static DECLCALLBACK(void) VRDECallbackVideoInDeviceDesc(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, + uint32_t cbDevice); + static DECLCALLBACK(void) VRDECallbackVideoInControl(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, + uint32_t cbControl); + static DECLCALLBACK(void) VRDECallbackVideoInFrame(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, + uint32_t cbFrame); + EmWebcam *mEmWebcam; + + /* Input interface. */ + VRDEINPUTINTERFACE m_interfaceInput; + VRDEINPUTCALLBACKS m_interfaceCallbacksInput; + static DECLCALLBACK(void) VRDECallbackInputSetup(void *pvCallback, + int rcRequest, + uint32_t u32Method, + const void *pvResult, + uint32_t cbResult); + static DECLCALLBACK(void) VRDECallbackInputEvent(void *pvCallback, + uint32_t u32Method, + const void *pvEvent, + uint32_t cbEvent); + uint64_t mu64TouchInputTimestampMCS; }; diff --git a/src/VBox/Main/include/DHCPServerImpl.h b/src/VBox/Main/include/DHCPServerImpl.h index 0773d7bf..f326405e 100644 --- a/src/VBox/Main/include/DHCPServerImpl.h +++ b/src/VBox/Main/include/DHCPServerImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,7 +29,47 @@ struct NETIFINFO; namespace settings { struct DHCPServer; + struct VmNameSlotKey; } +#ifdef RT_OS_WINDOWS +# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP.exe" +#else +# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP" +#endif + +class DHCPServerRunner: public NetworkServiceRunner +{ +public: + DHCPServerRunner():NetworkServiceRunner(DHCP_EXECUTABLE_NAME){} + virtual ~DHCPServerRunner(){}; + + static const std::string kDsrKeyGateway; + static const std::string kDsrKeyLowerIp; + static const std::string kDsrKeyUpperIp; +}; + +/** + * for server configuration needs, it's perhaps better to use (VM,slot) pair + * (vm-name, slot) <----> (MAC) + * + * but for client configuration, when server will have MACs at hand, it'd be + * easier to requiest options by MAC. + * (MAC) <----> (option-list) + * + * Doubts: What should be done if MAC changed for (vm-name, slot), when syncing should? + * XML: serialization of dependecy (DHCP options) - (VM,slot) shouldn't be done via MAC in + * the middle. + */ + +typedef std::map DhcpOptionMap; +typedef DhcpOptionMap::value_type DhcpOptValuePair; +typedef DhcpOptionMap::const_iterator DhcpOptConstIterator; +typedef DhcpOptionMap::iterator DhcpOptIterator; + +typedef std::map VmSlot2OptionsMap; +typedef VmSlot2OptionsMap::value_type VmSlot2OptionsPair; +typedef VmSlot2OptionsMap::iterator VmSlot2OptionsIterator; + class ATL_NO_VTABLE DHCPServer : public VirtualBoxBase, @@ -69,30 +109,29 @@ public: STDMETHOD(COMGETTER(LowerIP))(BSTR *aIPAddress); STDMETHOD(COMGETTER(UpperIP))(BSTR *aIPAddress); + STDMETHOD(AddGlobalOption)(DhcpOpt_T aOption, IN_BSTR aValue); + STDMETHOD(COMGETTER(GlobalOptions))(ComSafeArrayOut(BSTR, aValue)); + STDMETHOD(COMGETTER(VmConfigs))(ComSafeArrayOut(BSTR, aValue)); + STDMETHOD(AddVmSlotOption)(IN_BSTR aVmName, LONG aSlot, DhcpOpt_T aOption, IN_BSTR aValue); + STDMETHOD(RemoveVmSlotOptions)(IN_BSTR aVmName, LONG aSlot); + STDMETHOD(GetVmSlotOptions)(IN_BSTR aVmName, LONG aSlot, ComSafeArrayOut(BSTR, aValues)); + STDMETHOD(GetMacOptions)(IN_BSTR aMAC, ComSafeArrayOut(BSTR, aValues)); + STDMETHOD(COMGETTER(EventSource))(IEventSource **aEventSource); + STDMETHOD(SetConfiguration)(IN_BSTR aIPAddress, IN_BSTR aNetworkMask, IN_BSTR aFromIPAddress, IN_BSTR aToIPAddress); STDMETHOD(Start)(IN_BSTR aNetworkName, IN_BSTR aTrunkName, IN_BSTR aTrunkType); STDMETHOD(Stop)(); private: + struct Data; + Data *m; /** weak VirtualBox parent */ VirtualBox * const mVirtualBox; - const Bstr mName; - struct Data - { - Data() : enabled(FALSE) {} - - Bstr IPAddress; - Bstr networkMask; - Bstr lowerIP; - Bstr upperIP; - BOOL enabled; - - DHCPServerRunner dhcp; - } m; - + DhcpOptionMap& findOptMapByVmNameSlot(const com::Utf8Str& aVmName, + LONG Slot); }; #endif // ____H_H_DHCPSERVERIMPL diff --git a/src/VBox/Main/include/DHCPServerRunner.h b/src/VBox/Main/include/DHCPServerRunner.h deleted file mode 100644 index b1308455..00000000 --- a/src/VBox/Main/include/DHCPServerRunner.h +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id: DHCPServerRunner.h $ */ -/** @file - * VirtualBox Main - interface for VBox DHCP server - */ - -/* - * Copyright (C) 2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ -#include -#include -#include -#include -#include - -typedef enum -{ - DHCPCFG_NAME = 1, - DHCPCFG_NETNAME, - DHCPCFG_TRUNKTYPE, - DHCPCFG_TRUNKNAME, - DHCPCFG_MACADDRESS, - DHCPCFG_IPADDRESS, - DHCPCFG_LEASEDB, - DHCPCFG_VERBOSE, - DHCPCFG_GATEWAY, - DHCPCFG_LOWERIP, - DHCPCFG_UPPERIP, - DHCPCFG_NETMASK, - DHCPCFG_HELP, - DHCPCFG_VERSION, - DHCPCFG_BEGINCONFIG, - DHCPCFG_NOTOPT_MAXVAL -}DHCPCFG; - -#define TRUNKTYPE_WHATEVER "whatever" -#define TRUNKTYPE_NETFLT "netflt" -#define TRUNKTYPE_NETADP "netadp" -#define TRUNKTYPE_SRVNAT "srvnat" - -class DHCPServerRunner -{ -public: - DHCPServerRunner(); - ~DHCPServerRunner() { stop(); /* don't leave abandoned servers */} - - int setOption(DHCPCFG opt, const char *val, bool enabled) - { - if(opt == 0 || opt >= DHCPCFG_NOTOPT_MAXVAL) - return VERR_INVALID_PARAMETER; - if(isRunning()) - return VERR_INVALID_STATE; - - mOptions[opt] = val; - mOptionEnabled[opt] = enabled; - return VINF_SUCCESS; - } - - int setOption(DHCPCFG opt, const com::Utf8Str &val, bool enabled) - { - return setOption(opt, val.c_str(), enabled); - } - - int start(); - int stop(); - bool isRunning(); - - void detachFromServer(); -private: - com::Utf8Str mOptions[DHCPCFG_NOTOPT_MAXVAL]; - bool mOptionEnabled[DHCPCFG_NOTOPT_MAXVAL]; - RTPROCESS mProcess; -}; diff --git a/src/VBox/Main/include/DisplayImpl.h b/src/VBox/Main/include/DisplayImpl.h index 1f783700..4bc1415a 100644 --- a/src/VBox/Main/include/DisplayImpl.h +++ b/src/VBox/Main/include/DisplayImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,10 +26,15 @@ #include #include +#ifdef VBOX_WITH_CROGL +# include +#endif + class Console; struct VIDEORECCONTEXT; -enum { +enum +{ ResizeStatus_Void, ResizeStatus_InProgress, ResizeStatus_UpdateDisplayData @@ -56,6 +61,10 @@ typedef struct _DISPLAYFBINFO uint16_t flags; + /* for saving the rectangles arrived during fb resize is in progress. */ + PRTRECT mpSavedVisibleRegion; + uint32_t mcSavedVisibleRegion; + VBOXVIDEOINFOHOSTEVENTS *pHostEvents; volatile uint32_t u32ResizeStatus; @@ -63,7 +72,8 @@ typedef struct _DISPLAYFBINFO /* The Framebuffer has default format and must be updates immediately. */ bool fDefaultFormat; - struct { + struct + { /* The rectangle that includes all dirty rectangles. */ int32_t xLeft; int32_t xRight; @@ -71,21 +81,23 @@ typedef struct _DISPLAYFBINFO int32_t yBottom; } dirtyRect; - struct { + struct + { bool fPending; ULONG pixelFormat; void *pvVRAM; uint32_t bpp; uint32_t cbLine; - int w; - int h; + uint32_t w; + uint32_t h; uint16_t flags; } pendingResize; #ifdef VBOX_WITH_HGSMI bool fVBVAEnabled; uint32_t cVBVASkipUpdate; - struct { + struct + { int32_t xLeft; int32_t yTop; int32_t xRight; @@ -93,12 +105,35 @@ typedef struct _DISPLAYFBINFO } vbvaSkippedRect; PVBVAHOSTFLAGS pVBVAHostFlags; #endif /* VBOX_WITH_HGSMI */ + +#ifdef VBOX_WITH_CROGL + struct + { + bool fPending; + ULONG x; + ULONG y; + ULONG width; + ULONG height; + } pendingViewportInfo; +#endif /* VBOX_WITH_CROGL */ } DISPLAYFBINFO; +class DisplayMouseInterface +{ +public: + virtual int getScreenResolution(uint32_t cScreen, ULONG *pcx, + ULONG *pcy, ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin) = 0; + virtual void getFramebufferDimensions(int32_t *px1, int32_t *py1, + int32_t *px2, int32_t *py2) = 0; +}; + +class VMMDev; + class ATL_NO_VTABLE Display : public VirtualBoxBase, VBOX_SCRIPTABLE_IMPL(IEventListener), - VBOX_SCRIPTABLE_IMPL(IDisplay) + VBOX_SCRIPTABLE_IMPL(IDisplay), + public DisplayMouseInterface { public: @@ -113,52 +148,74 @@ public: COM_INTERFACE_ENTRY(IEventListener) END_COM_MAP() - DECLARE_EMPTY_CTOR_DTOR (Display) + DECLARE_EMPTY_CTOR_DTOR(Display) HRESULT FinalConstruct(); void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init (Console *aParent); + HRESULT init(Console *aParent); void uninit(); - int registerSSM(PVM pVM); + int registerSSM(PUVM pUVM); // public methods only for internal purposes - int handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h, uint16_t flags); - void handleDisplayUpdateLegacy (int x, int y, int cx, int cy); - void handleDisplayUpdate (unsigned uScreenId, int x, int y, int w, int h); + int handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags); + void handleDisplayUpdateLegacy(int x, int y, int cx, int cy); + void handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h); #ifdef VBOX_WITH_VIDEOHWACCEL - void handleVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand); + int handleVHWACommandProcess(PVBOXVHWACMD pCommand); #endif #ifdef VBOX_WITH_CRHGSMI - void handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd); - void handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl); + void handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd); + void handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl); void handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); void handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); #endif + int handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion); +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + void handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); + void handleCrVRecScreenshotPerform(uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBitsPerPixel, + uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp); + bool handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp); + void handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp); + void handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); +#endif + + int notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM); + IFramebuffer *getFramebuffer() { return maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer; } - void getFramebufferDimensions(int32_t *px1, int32_t *py1, int32_t *px2, - int32_t *py2); - - int handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect); - int handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect); + void getFramebufferDimensions(int32_t *px1, int32_t *py1, int32_t *px2, int32_t *py2); + int getScreenResolution(uint32_t cScreen, ULONG *pcx, ULONG *pcy, + ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin) + { + return GetScreenResolution(cScreen, pcx, pcy, pcBPP, pXOrigin, pYOrigin); + } - int VideoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory); - void VideoAccelFlush (void); + int handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect); + int handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect); - bool VideoAccelAllowed (void); + int VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory); + void VideoAccelFlush(void); + bool VideoAccelAllowed(void); + void VideoAccelVRDP(bool fEnable); - void VideoAccelVRDP (bool fEnable); + int VideoCaptureStart(); + void VideoCaptureStop(); + int VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens)); // IEventListener methods STDMETHOD(HandleEvent)(IEvent * aEvent); // IDisplay methods - STDMETHOD(GetScreenResolution)(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel); + STDMETHOD(GetScreenResolution)(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel, LONG *aXOrigin, LONG *aYOrigin); STDMETHOD(SetFramebuffer)(ULONG aScreenId, IFramebuffer *aFramebuffer); STDMETHOD(GetFramebuffer)(ULONG aScreenId, IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin); STDMETHOD(SetVideoModeHint)(ULONG aDisplay, BOOL aEnabled, BOOL aChangeOrigin, LONG aOriginX, LONG aOriginY, ULONG aWidth, ULONG aHeight, ULONG aBitsPerPixel); @@ -178,13 +235,17 @@ public: private: - void updateDisplayData(void); + int updateDisplayData(void); #ifdef VBOX_WITH_CRHGSMI void setupCrHgsmiData(void); void destructCrHgsmiData(void); #endif +#ifdef VBOX_WITH_CROGL + void crViewportNotify(class VMMDev *pVMMDev, ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height); +#endif + static DECLCALLBACK(int) changeFramebuffer(Display *that, IFramebuffer *aFB, unsigned uScreenId); static DECLCALLBACK(void*) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); @@ -200,17 +261,21 @@ private: static DECLCALLBACK(void) displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId); #ifdef VBOX_WITH_VIDEOHWACCEL - static DECLCALLBACK(void) displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand); + static DECLCALLBACK(int) displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand); #endif #ifdef VBOX_WITH_CRHGSMI static DECLCALLBACK(void) displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd); static DECLCALLBACK(void) displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl); - static DECLCALLBACK(void) displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); - static DECLCALLBACK(void) displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); + static DECLCALLBACK(void) displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); + static DECLCALLBACK(void) displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); #endif - + static DECLCALLBACK(int) displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface, + struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion); + static DECLCALLBACK(void) displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); #ifdef VBOX_WITH_HGSMI static DECLCALLBACK(int) displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags); static DECLCALLBACK(void) displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId); @@ -221,6 +286,18 @@ private: static DECLCALLBACK(int) displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha, uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy, const void *pvShape); #endif +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + static DECLCALLBACK(void) displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen, + uint32_t x, uint32_t y, + uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp); + static DECLCALLBACK(bool) displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp); + static DECLCALLBACK(void) displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp); + + static DECLCALLBACK(void) displayVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); + static DECLCALLBACK(void) displayCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); +#endif static DECLCALLBACK(void) displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser); static DECLCALLBACK(int) displaySSMLoadScreenshot(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass); @@ -238,15 +315,13 @@ private: unsigned mcMonitors; DISPLAYFBINFO maFramebuffers[SchemaDefs::MaxGuestMonitors]; - bool mFramebufferOpened; - /* arguments of the last handleDisplayResize() call */ - void *mLastAddress; - uint32_t mLastBytesPerLine; - uint32_t mLastBitsPerPixel; - int mLastWidth; - int mLastHeight; - uint16_t mLastFlags; + void *mLastAddress; + uint32_t mLastBytesPerLine; + uint32_t mLastBitsPerPixel; + uint32_t mLastWidth; + uint32_t mLastHeight; + uint16_t mLastFlags; VBVAMEMORY *mpVbvaMemory; bool mfVideoAccelEnabled; @@ -258,59 +333,75 @@ private: VBVAMEMORY *mpPendingVbvaMemory; bool mfPendingVideoAccelEnable; bool mfMachineRunning; +#ifdef VBOX_WITH_CROGL + bool mfCrOglDataHidden; +#endif uint8_t *mpu8VbvaPartial; - uint32_t mcbVbvaPartial; + uint32_t mcbVbvaPartial; #ifdef VBOX_WITH_CRHGSMI /* for fast host hgcm calls */ HGCMCVSHANDLE mhCrOglSvc; #endif +#ifdef VBOX_WITH_CROGL + CR_MAIN_INTERFACE mCrOglCallbacks; + volatile uint32_t mfCrOglVideoRecState; + CRVBOXHGCMTAKESCREENSHOT mCrOglScreenshotData; +#endif - bool vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd); - void vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd); + bool vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd); + void vbvaReleaseCmd(VBVACMDHDR *pHdr, int32_t cbCmd); - void handleResizeCompletedEMT (void); + void handleResizeCompletedEMT(void); RTCRITSECT mVBVALock; volatile uint32_t mfu32PendingVideoAccelDisable; - int vbvaLock(void); + int vbvaLock(void); void vbvaUnlock(void); + RTCRITSECT mSaveSeamlessRectLock; + int SaveSeamlessRectLock(void); + void SaveSeamlessRectUnLock(void); + public: - static int displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height); + static int displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height); + +#ifdef VBOX_WITH_CROGL + static BOOL displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, uint32_t u32Width, uint32_t u32Height); +#endif private: - static void InvalidateAndUpdateEMT(Display *pDisplay); - static int drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height); + static void InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll); + static int drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height); - int videoAccelRefreshProcess(void); + int videoAccelRefreshProcess(void); /* Functions run under VBVA lock. */ - int videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory); - void videoAccelFlush (void); + int videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory); + void videoAccelFlush(void); + +#ifdef VBOX_WITH_CROGL + int crOglWindowsShow(bool fShow); +#endif #ifdef VBOX_WITH_HGSMI volatile uint32_t mu32UpdateVBVAFlags; #endif #ifdef VBOX_WITH_VPX - VIDEORECCONTEXT *mpVideoRecContext; + VIDEORECCONTEXT *mpVideoRecCtx; + bool maVideoRecEnabled[SchemaDefs::MaxGuestMonitors]; #endif }; -void gdImageCopyResampled (uint8_t *dst, uint8_t *src, - int dstX, int dstY, - int srcX, int srcY, - int dstW, int dstH, int srcW, int srcH); - +void gdImageCopyResampled(uint8_t *dst, uint8_t *src, + int dstX, int dstY, int srcX, int srcY, + int dstW, int dstH, int srcW, int srcH); -void BitmapScale32 (uint8_t *dst, - int dstW, int dstH, - const uint8_t *src, - int iDeltaLine, - int srcW, int srcH); +void BitmapScale32(uint8_t *dst, int dstW, int dstH, + const uint8_t *src, int iDeltaLine, int srcW, int srcH); int DisplayMakePNG(uint8_t *pu8Data, uint32_t cx, uint32_t cy, uint8_t **ppu8PNG, uint32_t *pcbPNG, uint32_t *pcxPNG, uint32_t *pcyPNG, diff --git a/src/VBox/Main/include/DisplayUtils.h b/src/VBox/Main/include/DisplayUtils.h index 6c4a9b16..7b8d9f86 100644 --- a/src/VBox/Main/include/DisplayUtils.h +++ b/src/VBox/Main/include/DisplayUtils.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/EmulatedUSBImpl.h b/src/VBox/Main/include/EmulatedUSBImpl.h new file mode 100644 index 00000000..fd8af0ab --- /dev/null +++ b/src/VBox/Main/include/EmulatedUSBImpl.h @@ -0,0 +1,85 @@ +/* $Id: EmulatedUSBImpl.h $ */ + +/** @file + * + * Emulated USB devices manager. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef EMULATEDUSB_IMPL_H_ +#define EMULATEDUSB_IMPL_H_ + +#include "EmulatedUSBWrap.h" + +class Console; +class EUSBWEBCAM; + +typedef std::map WebcamsMap; + +class ATL_NO_VTABLE EmulatedUSB : + public EmulatedUSBWrap +{ +public: + + DECLARE_EMPTY_CTOR_DTOR(EmulatedUSB) + + HRESULT FinalConstruct(); + void FinalRelease(); + + /* Public initializer/uninitializer for internal purposes only. */ + HRESULT init(ComObjPtr pConsole); + void uninit(); + + /* Public method for internal use. */ + static DECLCALLBACK(int) eusbCallback(void *pv, const char *pszId, uint32_t iEvent, + const void *pvData, uint32_t cbData); + + HRESULT webcamAttachInternal(const com::Utf8Str &aPath, + const com::Utf8Str &aSettings, + const char *pszDriver, + void *pvObject); + HRESULT webcamDetachInternal(const com::Utf8Str &aPath); + +private: + + static DECLCALLBACK(int) eusbCallbackEMT(EmulatedUSB *pThis, char *pszId, uint32_t iEvent, + void *pvData, uint32_t cbData); + + HRESULT webcamPathFromId(com::Utf8Str *pPath, const char *pszId); + + // wrapped IEmulatedUSB properties + virtual HRESULT getWebcams(std::vector &aWebcams); + + // wrapped IEmulatedUSB methods + virtual HRESULT webcamAttach(const com::Utf8Str &aPath, + const com::Utf8Str &aSettings); + virtual HRESULT webcamDetach(const com::Utf8Str &aPath); + + /* Data. */ + struct Data + { + Data() + { + } + + ComObjPtr pConsole; + WebcamsMap webcams; + }; + + Data m; +}; + +#endif // EMULATEDUSB_IMPL_H_ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/EventImpl.h b/src/VBox/Main/include/EventImpl.h index e2979ce6..414ce013 100644 --- a/src/VBox/Main/include/EventImpl.h +++ b/src/VBox/Main/include/EventImpl.h @@ -144,7 +144,7 @@ public: void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init(IUnknown *aParent); + HRESULT init(); void uninit(); // IEventSource methods diff --git a/src/VBox/Main/include/ExtPackManagerImpl.h b/src/VBox/Main/include/ExtPackManagerImpl.h index c3f9a78d..642e77b5 100644 --- a/src/VBox/Main/include/ExtPackManagerImpl.h +++ b/src/VBox/Main/include/ExtPackManagerImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,6 +22,7 @@ #include #include +#if !defined(VBOX_COM_INPROC) /** * An extension pack file. */ @@ -84,6 +85,7 @@ private: friend class ExtPackManager; }; +#endif /** @@ -146,6 +148,7 @@ public: bool callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock); HRESULT checkVrde(void); HRESULT getVrdpLibraryName(Utf8Str *a_pstrVrdeLibrary); + HRESULT getLibraryName(const char *a_pszModuleName, Utf8Str *a_pstrLibrary); bool wantsToBeDefaultVrde(void) const; HRESULT refresh(bool *pfCanDelete); /** @} */ @@ -165,6 +168,7 @@ protected: VBOXEXTPACKMODKIND enmKind, char *pszFound, size_t cbFound, bool *pfNative); static DECLCALLBACK(int) hlpGetFilePath(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath); static DECLCALLBACK(VBOXEXTPACKCTX) hlpGetContext(PCVBOXEXTPACKHLP pHlp); + static DECLCALLBACK(int) hlpLoadHGCMService(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IConsole) *pConsole, const char *pszServiceLibrary, const char *pszServiceName); static DECLCALLBACK(int) hlpReservedN(PCVBOXEXTPACKHLP pHlp); /** @} */ @@ -214,10 +218,12 @@ class ATL_NO_VTABLE ExtPackManager : /** @name Internal interfaces used by other Main classes. * @{ */ +#if !defined(VBOX_COM_INPROC) static DECLCALLBACK(int) doInstallThreadProc(RTTHREAD hThread, void *pvJob); HRESULT doInstall(ExtPackFile *a_pExtPackFile, bool a_fReplace, Utf8Str const *a_pstrDisplayInfo); static DECLCALLBACK(int) doUninstallThreadProc(RTTHREAD hThread, void *pvJob); HRESULT doUninstall(const Utf8Str *a_pstrName, bool a_fForcedRemoval, const Utf8Str *a_pstrDisplayInfo); +#endif void callAllVirtualBoxReadyHooks(void); void callAllConsoleReadyHooks(IConsole *a_pConsole); void callAllVmCreatedHooks(IMachine *a_pMachine); @@ -226,6 +232,7 @@ class ATL_NO_VTABLE ExtPackManager : void callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM); HRESULT checkVrdeExtPack(Utf8Str const *a_pstrExtPack); int getVrdeLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrVrdeLibrary); + HRESULT getLibraryPathForExtPack(const char *a_pszModuleName, Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrLibrary); HRESULT getDefaultVrdeExtPack(Utf8Str *a_pstrExtPack); bool isExtPackUsable(const char *a_pszExtPack); void dumpAllToReleaseLog(void); diff --git a/src/VBox/Main/include/ExtPackUtil.h b/src/VBox/Main/include/ExtPackUtil.h index 0fd97bf0..5b09fe6f 100644 --- a/src/VBox/Main/include/ExtPackUtil.h +++ b/src/VBox/Main/include/ExtPackUtil.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/Global.h b/src/VBox/Main/include/Global.h index bfe53af4..38d9a470 100644 --- a/src/VBox/Main/include/Global.h +++ b/src/VBox/Main/include/Global.h @@ -192,6 +192,14 @@ public: */ static const char *stringifyDeviceType(DeviceType_T aType); + /** + * Stringify a reason. + * + * @returns Pointer to a read only string. + * @param aReason The reason code. + */ + static const char *stringifyReason(Reason_T aReason); + /** * Try convert a COM status code to a VirtualBox status code (VBox/err.h). * diff --git a/src/VBox/Main/include/GuestCtrlImplPrivate.h b/src/VBox/Main/include/GuestCtrlImplPrivate.h index b8feac32..bd8a0f47 100644 --- a/src/VBox/Main/include/GuestCtrlImplPrivate.h +++ b/src/VBox/Main/include/GuestCtrlImplPrivate.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011-2012 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -18,6 +18,8 @@ #ifndef ____H_GUESTIMPLPRIVATE #define ____H_GUESTIMPLPRIVATE +#include "ConsoleImpl.h" + #include #include @@ -36,172 +38,13 @@ using namespace com; using namespace guestControl; #endif -/** Maximum number of guest sessions a VM can have. */ -#define VBOX_GUESTCTRL_MAX_SESSIONS 32 -/** Maximum number of guest objects (processes, files, ...) - * a guest session can have. */ -#define VBOX_GUESTCTRL_MAX_OBJECTS _2K -/** Maximum of callback contexts a guest process can have. */ -#define VBOX_GUESTCTRL_MAX_CONTEXTS _64K - -/** Builds a context ID out of the session ID, object ID and an - * increasing count. */ -#define VBOX_GUESTCTRL_CONTEXTID_MAKE(uSession, uObject, uCount) \ - ( (uint32_t)((uSession) & 0x1f) << 27 \ - | (uint32_t)((uObject) & 0x7ff) << 16 \ - | (uint32_t)((uCount) & 0xffff) \ - ) -/** Gets the session ID out of a context ID. */ -#define VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID) \ - ((uContextID) >> 27) -/** Gets the process ID out of a context ID. */ -#define VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID) \ - (((uContextID) >> 16) & 0x7ff) -/** Gets the conext count of a process out of a context ID. */ -#define VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID) \ - ((uContextID) & 0xffff) - /** Vector holding a process' CPU affinity. */ typedef std::vector ProcessAffinity; /** Vector holding process startup arguments. */ typedef std::vector ProcessArguments; class GuestProcessStreamBlock; - - -/** - * Base class for a all guest control callbacks/events. - */ -class GuestCtrlEvent -{ -public: - - GuestCtrlEvent(void); - - virtual ~GuestCtrlEvent(void); - - /** @todo Copy/comparison operator? */ - -public: - - int Cancel(void); - - bool Canceled(void); - - virtual void Destroy(void); - - int Init(void); - - virtual int Signal(int rc = VINF_SUCCESS); - - int GetResultCode(void) { return mRC; } - - int Wait(ULONG uTimeoutMS); - -protected: - - /** Was the callback canceled? */ - bool fCanceled; - /** Did the callback complete? */ - bool fCompleted; - /** The event semaphore for triggering - * the actual event. */ - RTSEMEVENT hEventSem; - /** The waiting mutex. */ - RTSEMMUTEX hEventMutex; - /** Overall result code. */ - int mRC; -}; - - -/* - * Class representing a guest control callback. - */ -class GuestCtrlCallback : public GuestCtrlEvent -{ -public: - - GuestCtrlCallback(void); - - GuestCtrlCallback(eVBoxGuestCtrlCallbackType enmType); - - virtual ~GuestCtrlCallback(void); - -public: - - void Destroy(void); - - int Init(eVBoxGuestCtrlCallbackType enmType); - - eVBoxGuestCtrlCallbackType GetCallbackType(void) { return mType; } - - const void* GetDataRaw(void) const { return pvData; } - - size_t GetDataSize(void) { return cbData; } - - const void* GetPayloadRaw(void) const { return pvPayload; } - - size_t GetPayloadSize(void) { return cbPayload; } - - int SetData(const void *pvCallback, size_t cbCallback); - - int SetPayload(const void *pvToWrite, size_t cbToWrite); - -protected: - - /** Pointer to actual callback data. */ - void *pvData; - /** Size of user-supplied data. */ - size_t cbData; - /** The callback type. */ - eVBoxGuestCtrlCallbackType mType; - /** Callback flags. */ - uint32_t uFlags; - /** Payload which will be available on successful - * waiting (optional). */ - void *pvPayload; - /** Size of the payload (optional). */ - size_t cbPayload; -}; -typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks; - - -/* - * Class representing a guest control process waiting - * event. - */ -class GuestProcessWaitEvent : public GuestCtrlEvent -{ -public: - - GuestProcessWaitEvent(void); - - GuestProcessWaitEvent(uint32_t uWaitFlags); - - virtual ~GuestProcessWaitEvent(void); - -public: - - void Destroy(void); - - int Init(uint32_t uWaitFlags); - - uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mFlags); } - - ProcessWaitResult_T GetWaitResult(void) { return mResult; } - - int GetWaitRc(void) { return mRC; } - - int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS); - -protected: - - /** The waiting flag(s). The specifies what to - * wait for. See ProcessWaitFlag_T. */ - uint32_t mFlags; - /** Structure containing the overall result. */ - ProcessWaitResult_T mResult; -}; +class GuestSession; /** @@ -260,6 +103,43 @@ protected: }; +/** + * Structure for keeping all the relevant guest directory + * information around. + */ +struct GuestDirectoryOpenInfo +{ + /** The directory path. */ + Utf8Str mPath; + /** Then open filter. */ + Utf8Str mFilter; + /** Opening flags. */ + uint32_t mFlags; +}; + + +/** + * Structure for keeping all the relevant guest file + * information around. + */ +struct GuestFileOpenInfo +{ + /** The filename. */ + Utf8Str mFileName; + /** Then file's opening mode. */ + Utf8Str mOpenMode; + /** The file's disposition mode. */ + Utf8Str mDisposition; + /** The file's sharing mode. + **@todo Not implemented yet.*/ + Utf8Str mSharingMode; + /** Octal creation mode. */ + uint32_t mCreationMode; + /** The initial offset on open. */ + uint64_t mInitialOffset; +}; + + /** * Structure representing information of a * file system object. @@ -269,6 +149,7 @@ struct GuestFsObjData /** Helper function to extract the data from * a certin VBoxService tool's guest stream block. */ int FromLs(const GuestProcessStreamBlock &strmBlk); + int FromMkTemp(const GuestProcessStreamBlock &strmBlk); int FromStat(const GuestProcessStreamBlock &strmBlk); int64_t mAccessTime; @@ -295,8 +176,37 @@ struct GuestFsObjData /** - * Structure for keeping all the relevant process - * starting parameters around. + * Structure for keeping all the relevant guest session + * startup parameters around. + */ +class GuestSessionStartupInfo +{ +public: + + GuestSessionStartupInfo(void) + : mIsInternal(false /* Non-internal session */), + mOpenTimeoutMS(30 * 1000 /* 30s opening timeout */), + mOpenFlags(0 /* No opening flags set */) { } + + /** The session's friendly name. Optional. */ + Utf8Str mName; + /** The session's unique ID. Used to encode + * a context ID. */ + uint32_t mID; + /** Flag indicating if this is an internal session + * or not. Internal session are not accessible by + * public API clients. */ + bool mIsInternal; + /** Timeout (in ms) used for opening the session. */ + uint32_t mOpenTimeoutMS; + /** Session opening flags. */ + uint32_t mOpenFlags; +}; + + +/** + * Structure for keeping all the relevant guest process + * startup parameters around. */ class GuestProcessStartupInfo { @@ -316,8 +226,12 @@ public: /** Process creation flags. */ uint32_t mFlags; ULONG mTimeoutMS; + /** Process priority. */ ProcessPriority_T mPriority; - ProcessAffinity mAffinity; + /** Process affinity. At the moment we + * only support 64 VCPUs. API and + * guest can do more already! */ + uint64_t mAffinity; }; @@ -371,19 +285,21 @@ public: size_t GetCount(void) const; + int GetRc(void) const; + const char* GetString(const char *pszKey) const; int GetUInt32Ex(const char *pszKey, uint32_t *puVal) const; uint32_t GetUInt32(const char *pszKey) const; - bool IsEmpty(void) { return m_mapPairs.empty(); } + bool IsEmpty(void) { return mPairs.empty(); } int SetValue(const char *pszKey, const char *pszValue); protected: - GuestCtrlStreamPairMap m_mapPairs; + GuestCtrlStreamPairMap mPairs; }; /** Vector containing multiple allocated stream pair objects. */ @@ -414,9 +330,9 @@ public: void Dump(const char *pszFile); #endif - uint32_t GetOffset(); + uint32_t GetOffset() { return m_cbOffset; } - uint32_t GetSize(); + size_t GetSize() { return m_cbSize; } int ParseBlock(GuestProcessStreamBlock &streamBlock); @@ -425,7 +341,7 @@ protected: /** Currently allocated size of internal stream buffer. */ uint32_t m_cbAllocated; /** Currently used size of allocated internal stream buffer. */ - uint32_t m_cbSize; + size_t m_cbSize; /** Current offset within the internal stream buffer. */ uint32_t m_cbOffset; /** Internal stream buffer. */ @@ -478,5 +394,282 @@ public: Utf8Str strPassword; ULONG uFlags; }; + +class GuestWaitEventPayload +{ + +public: + + GuestWaitEventPayload(void) + : uType(0), + cbData(0), + pvData(NULL) { } + + GuestWaitEventPayload(uint32_t uTypePayload, + const void *pvPayload, uint32_t cbPayload) + { + if (cbPayload) + { + pvData = RTMemAlloc(cbPayload); + if (pvData) + { + uType = uTypePayload; + + memcpy(pvData, pvPayload, cbPayload); + cbData = cbPayload; + } + else /* Throw IPRT error. */ + throw VERR_NO_MEMORY; + } + else + { + uType = uTypePayload; + + pvData = NULL; + cbData = 0; + } + } + + virtual ~GuestWaitEventPayload(void) + { + Clear(); + } + + GuestWaitEventPayload& operator=(const GuestWaitEventPayload &that) + { + CopyFromDeep(that); + return *this; + } + +public: + + void Clear(void) + { + if (pvData) + { + RTMemFree(pvData); + cbData = 0; + } + uType = 0; + } + + int CopyFromDeep(const GuestWaitEventPayload &payload) + { + Clear(); + + int rc = VINF_SUCCESS; + if (payload.cbData) + { + Assert(payload.cbData); + pvData = RTMemAlloc(payload.cbData); + if (pvData) + { + memcpy(pvData, payload.pvData, payload.cbData); + cbData = payload.cbData; + uType = payload.uType; + } + else + rc = VERR_NO_MEMORY; + } + + return rc; + } + + const void* Raw(void) const { return pvData; } + + size_t Size(void) const { return cbData; } + + uint32_t Type(void) const { return uType; } + + void* MutableRaw(void) { return pvData; } + +protected: + + /** Type of payload. */ + uint32_t uType; + /** Size (in bytes) of payload. */ + uint32_t cbData; + /** Pointer to actual payload data. */ + void *pvData; +}; + +class GuestWaitEventBase +{ + +protected: + + GuestWaitEventBase(void); + virtual ~GuestWaitEventBase(void); + +public: + + uint32_t ContextID(void) { return mCID; }; + int GuestResult(void) { return mGuestRc; } + int Result(void) { return mRc; } + GuestWaitEventPayload & Payload(void) { return mPayload; } + int SignalInternal(int rc, int guestRc, const GuestWaitEventPayload *pPayload); + int Wait(RTMSINTERVAL uTimeoutMS); + +protected: + + int Init(uint32_t uCID); + +protected: + + /* Shutdown indicator. */ + bool mfAborted; + /* Associated context ID (CID). */ + uint32_t mCID; + /** The event semaphore for triggering + * the actual event. */ + RTSEMEVENT mEventSem; + /** The event's overall result. If + * set to VERR_GSTCTL_GUEST_ERROR, + * mGuestRc will contain the actual + * error code from the guest side. */ + int mRc; + /** The event'S overall result from the + * guest side. If used, mRc must be + * set to VERR_GSTCTL_GUEST_ERROR. */ + int mGuestRc; + /** The event's payload data. Optional. */ + GuestWaitEventPayload mPayload; +}; + +/** List of public guest event types. */ +typedef std::list < VBoxEventType_T > GuestEventTypes; + +class GuestWaitEvent : public GuestWaitEventBase +{ + +public: + + GuestWaitEvent(uint32_t uCID); + GuestWaitEvent(uint32_t uCID, const GuestEventTypes &lstEvents); + virtual ~GuestWaitEvent(void); + +public: + + int Cancel(void); + const ComPtr Event(void) { return mEvent; } + int SignalExternal(IEvent *pEvent); + const GuestEventTypes Types(void) { return mEventTypes; } + size_t TypeCount(void) { return mEventTypes.size(); } + +protected: + + int Init(uint32_t uCID); + +protected: + + /** List of public event types this event should + * be signalled on. Optional. */ + GuestEventTypes mEventTypes; + /** Pointer to the actual public event, if any. */ + ComPtr mEvent; +}; +/** Map of pointers to guest events. The primary key + * contains the context ID. */ +typedef std::map < uint32_t, GuestWaitEvent* > GuestWaitEvents; +/** Map of wait events per public guest event. Nice for + * faster lookups when signalling a whole event group. */ +typedef std::map < VBoxEventType_T, GuestWaitEvents > GuestEventGroup; + +class GuestBase +{ + +public: + + GuestBase(void); + virtual ~GuestBase(void); + +public: + + /** Signals a wait event using a public guest event; also used for + * for external event listeners. */ + int signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent); + /** Signals a wait event using a guest rc. */ + int signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int guestRc, const GuestWaitEventPayload *pPayload); + /** Signals a wait event without letting public guest events know, + * extended director's cut version. */ + int signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int rc, int guestRc, const GuestWaitEventPayload *pPayload); +public: + + int baseInit(void); + void baseUninit(void); + int cancelWaitEvents(void); + int dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID); + int registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, GuestWaitEvent **ppEvent); + int registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent); + void unregisterWaitEvent(GuestWaitEvent *pEvent); + int waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, VBoxEventType_T *pType, IEvent **ppEvent); + +protected: + + /** Pointer to the console object. Needed + * for HGCM (VMMDev) communication. */ + Console *mConsole; + /** The next upcoming context ID for this object. */ + uint32_t mNextContextID; + /** Local listener for handling the waiting events + * internally. */ + ComPtr mLocalListener; + /** Critical section for wait events access. */ + RTCRITSECT mWaitEventCritSect; + /** Map of registered wait events per event group. */ + GuestEventGroup mWaitEventGroups; + /** Map of registered wait events. */ + GuestWaitEvents mWaitEvents; +}; + +/** + * Virtual class (interface) for guest objects (processes, files, ...) -- + * contains all per-object callback management. + */ +class GuestObject : public GuestBase +{ + +public: + + GuestObject(void); + virtual ~GuestObject(void); + +public: + + ULONG getObjectID(void) { return mObjectID; } + +protected: + + virtual int onRemove(void) = 0; + + /** Callback dispatcher -- must be implemented by the actual object. */ + virtual int callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) = 0; + +protected: + + int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID); + int registerWaitEvent(const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent); + int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); + +protected: + + /** + * Commom parameters for all derived objects, when then have + * an own mData structure to keep their specific data around. + */ + + /** Pointer to parent session. Per definition + * this objects *always* lives shorter than the + * parent. */ + GuestSession *mSession; + /** The object ID -- must be unique for each guest + * object and is encoded into the context ID. Must + * be set manually when initializing the object. + * + * For guest processes this is the internal PID, + * for guest files this is the internal file ID. */ + uint32_t mObjectID; +}; #endif // ____H_GUESTIMPLPRIVATE diff --git a/src/VBox/Main/include/GuestDirectoryImpl.h b/src/VBox/Main/include/GuestDirectoryImpl.h index 62981067..7c454eaf 100644 --- a/src/VBox/Main/include/GuestDirectoryImpl.h +++ b/src/VBox/Main/include/GuestDirectoryImpl.h @@ -29,6 +29,7 @@ class GuestSession; */ class ATL_NO_VTABLE GuestDirectory : public VirtualBoxBase, + public GuestObject, VBOX_SCRIPTABLE_IMPL(IGuestDirectory) { public: @@ -43,7 +44,7 @@ public: END_COM_MAP() DECLARE_EMPTY_CTOR_DTOR(GuestDirectory) - int init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags); + int init(Console *pConsole, GuestSession *pSession, ULONG uDirID, const GuestDirectoryOpenInfo &openInfo); void uninit(void); HRESULT FinalConstruct(void); void FinalRelease(void); @@ -60,6 +61,10 @@ public: public: /** @name Public internal methods. * @{ */ + int callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + static Utf8Str guestErrorToString(int guestRc); + int onRemove(void); + static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); /** @} */ private: @@ -70,10 +75,10 @@ private: struct Data { - GuestSession *mSession; - Utf8Str mName; - Utf8Str mFilter; - uint32_t mFlags; + /** The directory's open info. */ + GuestDirectoryOpenInfo mOpenInfo; + /** The directory's ID. */ + uint32_t mID; GuestProcessTool mProcessTool; } mData; }; diff --git a/src/VBox/Main/include/GuestFileImpl.h b/src/VBox/Main/include/GuestFileImpl.h index cea13081..7890cb48 100644 --- a/src/VBox/Main/include/GuestFileImpl.h +++ b/src/VBox/Main/include/GuestFileImpl.h @@ -1,11 +1,11 @@ /* $Id: GuestFileImpl.h $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest file handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,9 +20,12 @@ #define ____H_GUESTFILEIMPL #include "VirtualBoxBase.h" +#include "EventImpl.h" #include "GuestFsObjInfoImpl.h" +#include "GuestCtrlImplPrivate.h" +class Console; class GuestSession; class GuestProcess; @@ -31,6 +34,7 @@ class GuestProcess; */ class ATL_NO_VTABLE GuestFile : public VirtualBoxBase, + public GuestObject, VBOX_SCRIPTABLE_IMPL(IGuestFile) { public: @@ -45,7 +49,7 @@ public: END_COM_MAP() DECLARE_EMPTY_CTOR_DTOR(GuestFile) - int init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset, int *pGuestRc); + int init(Console *pConsole, GuestSession *pSession, ULONG uFileID, const GuestFileOpenInfo &openInfo); void uninit(void); HRESULT FinalConstruct(void); void FinalRelease(void); @@ -54,11 +58,14 @@ public: /** @name IFile interface. * @{ */ STDMETHOD(COMGETTER(CreationMode))(ULONG *aCreationMode); - STDMETHOD(COMGETTER(Disposition))(ULONG *aDisposition); + STDMETHOD(COMGETTER(Disposition))(BSTR *aDisposition); + STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); STDMETHOD(COMGETTER(FileName))(BSTR *aFileName); + STDMETHOD(COMGETTER(Id))(ULONG *aID); STDMETHOD(COMGETTER(InitialSize))(LONG64 *aInitialSize); STDMETHOD(COMGETTER(Offset))(LONG64 *aOffset); - STDMETHOD(COMGETTER(OpenMode))(ULONG *aOpenMode); + STDMETHOD(COMGETTER(OpenMode))(BSTR *aOpenMode); + STDMETHOD(COMGETTER(Status))(FileStatus_T *aStatus); STDMETHOD(Close)(void); STDMETHOD(QueryInfo)(IFsObjInfo **aInfo); @@ -73,22 +80,49 @@ public: public: /** @name Public internal methods. * @{ */ - static uint32_t getDispositionFromString(const Utf8Str &strDisposition); - static uint32_t getOpenModeFromString(const Utf8Str &strOpenMode); + int callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int closeFile(int *pGuestRc); + EventSource *getEventSource(void) { return mEventSource; } + static Utf8Str guestErrorToString(int guestRc); + int onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onRemove(void); + int openFile(uint32_t uTimeoutMS, int *pGuestRc); + int readData(uint32_t uSize, uint32_t uTimeoutMS, void* pvData, uint32_t cbData, uint32_t* pcbRead); + int readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead); + int seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, uint64_t *puOffset); + static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); + int setFileStatus(FileStatus_T fileStatus, int fileRc); + int waitForOffsetChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint64_t *puOffset); + int waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead); + int waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, FileStatus_T *pFileStatus, int *pGuestRc); + int waitForWrite(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint32_t *pcbWritten); + int writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); + int writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); /** @} */ private: + /** This can safely be used without holding any locks. + * An AutoCaller suffices to prevent it being destroy while in use and + * internally there is a lock providing the necessary serialization. */ + const ComObjPtr mEventSource; + struct Data { - /** The associate session this file belongs to. */ - GuestSession *mSession; - uint32_t mCreationMode; - uint32_t mDisposition; - Utf8Str mFileName; - int64_t mInitialSize; - uint32_t mOpenMode; - int64_t mOffset; + /** The file's open info. */ + GuestFileOpenInfo mOpenInfo; + /** The file's initial size on open. */ + uint64_t mInitialSize; + /** The file's ID. */ + uint32_t mID; + /** The current file status. */ + FileStatus_T mStatus; + /** The last returned process status + * returned from the guest side. */ + int mLastError; + /** The file's current offset. */ + uint64_t mOffCurrent; } mData; }; diff --git a/src/VBox/Main/include/GuestImpl.h b/src/VBox/Main/include/GuestImpl.h index 5ae18886..1a856eec 100644 --- a/src/VBox/Main/include/GuestImpl.h +++ b/src/VBox/Main/include/GuestImpl.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,6 +21,7 @@ #include #include #include +#include #include "AdditionsFacilityImpl.h" #include "GuestCtrlImplPrivate.h" @@ -79,6 +80,7 @@ public: STDMETHOD(COMGETTER(AdditionsRunLevel)) (AdditionsRunLevelType_T *aRunLevel); STDMETHOD(COMGETTER(AdditionsVersion))(BSTR *a_pbstrAdditionsVersion); STDMETHOD(COMGETTER(AdditionsRevision))(ULONG *a_puAdditionsRevision); + STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); STDMETHOD(COMGETTER(Facilities)) (ComSafeArrayOut(IAdditionsFacility *, aFacilities)); STDMETHOD(COMGETTER(Sessions)) (ComSafeArrayOut(IGuestSession *, aSessions)); STDMETHOD(COMGETTER(MemoryBalloonSize)) (ULONG *aMemoryBalloonSize); @@ -99,21 +101,22 @@ public: STDMETHOD(DragGHPending)(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction); STDMETHOD(DragGHDropped)(IN_BSTR strFormat, DragAndDropAction_T action, IProgress **ppProgress); STDMETHOD(DragGHGetData)(ComSafeArrayOut(BYTE, data)); + // Guest control. + STDMETHOD(CreateSession)(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, IN_BSTR aSessionName, IGuestSession **aGuestSession); + STDMETHOD(FindSession)(IN_BSTR aSessionName, ComSafeArrayOut(IGuestSession *, aSessions)); // Misc stuff STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle, ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared, ULONG *aMemCache, ULONG *aPageTotal, ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal); - STDMETHOD(UpdateGuestAdditions)(IN_BSTR aSource, ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress); - STDMETHOD(CreateSession)(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, IN_BSTR aSessionName, IGuestSession **aGuestSession); - STDMETHOD(FindSession)(IN_BSTR aSessionName, ComSafeArrayOut(IGuestSession *, aSessions)); + STDMETHOD(UpdateGuestAdditions)(IN_BSTR aSource, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress); public: /** @name Static internal methods. * @{ */ #ifdef VBOX_WITH_GUEST_CONTROL /** Static callback for handling guest control notifications. */ - static DECLCALLBACK(int) notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms); - static void staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick); + static DECLCALLBACK(int) notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, void *pvData, uint32_t cbData); + static DECLCALLBACK(void) staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick); #endif /** @} */ @@ -126,6 +129,7 @@ public: bool facilityIsActive(VBoxGuestFacilityType enmFacility); void facilityUpdate(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus, uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS); void setAdditionsStatus(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus, uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS); + void onUserStateChange(Bstr aUser, Bstr aDomain, VBoxGuestUserState enmState, const uint8_t *puDetails, uint32_t cbDetails); void setSupportedFeatures(uint32_t aCaps); HRESULT setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal); BOOL isPageFusionEnabled(); @@ -135,12 +139,11 @@ public: return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true); } #ifdef VBOX_WITH_GUEST_CONTROL - int dispatchToSession(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData); + int dispatchToSession(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); uint32_t getAdditionsVersion(void) { return mData.mAdditionsVersionFull; } Console *getConsole(void) { return mParent; } int sessionRemove(GuestSession *pSession); - int sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain, - const Utf8Str &strSessionName, ComObjPtr &pGuestSession); + int sessionCreate(const GuestSessionStartupInfo &ssInfo, const GuestCredentials &guestCreds, ComObjPtr &pGuestSession); inline bool sessionExists(uint32_t uSessionID); #endif /** @} */ @@ -149,6 +152,8 @@ private: /** @name Private internal methods. * @{ */ void updateStats(uint64_t iTick); + static int staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + STAMVISIBILITY enmVisiblity, const char *pszDesc, void *pvUser); /** @} */ typedef std::map< AdditionsFacilityType_T, ComObjPtr > FacilityMap; @@ -174,21 +179,29 @@ private: Bstr mInterfaceVersion; GuestSessions mGuestSessions; uint32_t mNextSessionID; - }; + } mData; - ULONG mMemoryBalloonSize; - ULONG mStatUpdateInterval; - ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; - ULONG mGuestValidStats; - BOOL mCollectVMMStats; - BOOL mfPageFusionEnabled; + ULONG mMemoryBalloonSize; + ULONG mStatUpdateInterval; + uint64_t mNetStatRx; + uint64_t mNetStatTx; + uint64_t mNetStatLastTs; + ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; + ULONG mVmValidStats; + BOOL mCollectVMMStats; + BOOL mfPageFusionEnabled; - Console *mParent; - Data mData; + Console *mParent; #ifdef VBOX_WITH_GUEST_CONTROL + /** + * This can safely be used without holding any locks. + * An AutoCaller suffices to prevent it being destroy while in use and + * internally there is a lock providing the necessary serialization. + */ + const ComObjPtr mEventSource; /** General extension callback for guest control. */ - HGCMSVCEXTHANDLE mhExtCtrl; + HGCMSVCEXTHANDLE mhExtCtrl; #endif #ifdef VBOX_WITH_DRAG_AND_DROP diff --git a/src/VBox/Main/include/GuestProcessImpl.h b/src/VBox/Main/include/GuestProcessImpl.h index 8b83eb2e..95564b4d 100644 --- a/src/VBox/Main/include/GuestProcessImpl.h +++ b/src/VBox/Main/include/GuestProcessImpl.h @@ -1,11 +1,11 @@ /* $Id: GuestProcessImpl.h $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest process handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,10 +26,11 @@ class Console; class GuestSession; /** - * TODO + * Class for handling a guest process. */ class ATL_NO_VTABLE GuestProcess : public VirtualBoxBase, + public GuestObject, VBOX_SCRIPTABLE_IMPL(IGuestProcess) { public: @@ -54,6 +55,7 @@ public: * @{ */ STDMETHOD(COMGETTER(Arguments))(ComSafeArrayOut(BSTR, aArguments)); STDMETHOD(COMGETTER(Environment))(ComSafeArrayOut(BSTR, aEnvironment)); + STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); STDMETHOD(COMGETTER(ExecutablePath))(BSTR *aExecutablePath); STDMETHOD(COMGETTER(ExitCode))(LONG *aExitCode); STDMETHOD(COMGETTER(Name))(BSTR *aName); @@ -71,82 +73,73 @@ public: public: /** @name Public internal methods. * @{ */ - int callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData); - inline bool callbackExists(uint32_t uContextID); + int callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); inline int checkPID(uint32_t uPID); static Utf8Str guestErrorToString(int guestRc); - bool isReady(void); - ULONG getProcessID(void) { return mData.mProcessID; } - int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); + int onRemove(void); + int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc); static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); - int startProcess(int *pGuestRc); + int startProcess(uint32_t uTimeoutMS, int *pGuestRc); int startProcessAsync(void); - int terminateProcess(void); + int terminateProcess(uint32_t uTimeoutMS, int *pGuestRc); + static ProcessWaitResult_T waitFlagsToResultEx(uint32_t fWaitFlags, ProcessStatus_T oldStatus, ProcessStatus_T newStatus, uint32_t uProcFlags, uint32_t uProtocol); + ProcessWaitResult_T waitFlagsToResult(uint32_t fWaitFlags); int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc); + int waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed); + int waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead); + int waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc); + static bool waitResultImpliesEx(ProcessWaitResult_T waitResult, ProcessStatus_T procStatus, uint32_t uProcFlags, uint32_t uProtocol); int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc); /** @} */ protected: /** @name Protected internal methods. * @{ */ - inline int callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID); - inline int callbackRemove(uint32_t uContextID); inline bool isAlive(void); - int onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData); - int onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData); - int onProcessNotifyIO(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData); - int onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData); - int onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData); + inline bool hasEnded(void); + int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars); - int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); int setProcessStatus(ProcessStatus_T procStatus, int procRc); - int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS); static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser); /** @} */ private: + /** + * This can safely be used without holding any locks. + * An AutoCaller suffices to prevent it being destroy while in use and + * internally there is a lock providing the necessary serialization. + */ + const ComObjPtr mEventSource; + struct Data { - /** Pointer to parent session. Per definition - * this objects *always* lives shorter than the - * parent. */ - GuestSession *mParent; - /** Pointer to the console object. Needed - * for HGCM (VMMDev) communication. */ - Console *mConsole; - /** All related callbacks to this process. */ - GuestCtrlCallbacks mCallbacks; - /** The process start information. */ + /** The process startup information. */ GuestProcessStartupInfo mProcess; /** Exit code if process has been terminated. */ LONG mExitCode; /** PID reported from the guest. */ ULONG mPID; - /** Internal, host-side process ID. */ - ULONG mProcessID; /** The current process status. */ ProcessStatus_T mStatus; - int mRC; - /** The next upcoming context ID. */ - ULONG mNextContextID; - /** The mutex for protecting the waiter(s). */ - RTSEMMUTEX mWaitMutex; - /** How many waiters? At the moment there can only - * be one. */ - uint32_t mWaitCount; - /** The actual process event for doing the waits. - * At the moment we only support one wait a time. */ - GuestProcessWaitEvent *mWaitEvent; + /** The last returned process status + * returned from the guest side. */ + int mLastError; } mData; }; /** * Guest process tool flags. */ -/** No flags specified. */ +/** No flags specified; wait until process terminates. + * The maximum waiting time is set in the process' startup + * info. */ #define GUESTPROCESSTOOL_FLAG_NONE 0 -/** Run until next stream block from stdout has been +/** Wait until next stream block from stdout has been * read in completely, then return. */ #define GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK RT_BIT(0) @@ -178,13 +171,18 @@ public: bool IsRunning(void); + static int Run(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, int *pGuestRc); + + static int RunEx(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, GuestCtrlStreamObjects *pStrmOutObjects, + uint32_t cStrmOutObjects, int *pGuestRc); + int TerminatedOk(LONG *pExitCode); - void Terminate(void); + int Terminate(uint32_t uTimeoutMS, int *pGuestRc); protected: - GuestSession *pSession; + ComObjPtr pSession; ComObjPtr pProcess; GuestProcessStartupInfo mStartupInfo; GuestProcessStream mStdOut; diff --git a/src/VBox/Main/include/GuestSessionImpl.h b/src/VBox/Main/include/GuestSessionImpl.h index fc2bc307..263ed6d7 100644 --- a/src/VBox/Main/include/GuestSessionImpl.h +++ b/src/VBox/Main/include/GuestSessionImpl.h @@ -1,11 +1,11 @@ /* $Id: GuestSessionImpl.h $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest session handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,6 +20,7 @@ #define ____H_GUESTSESSIONIMPL #include "VirtualBoxBase.h" +#include "EventImpl.h" #include "GuestCtrlImplPrivate.h" #include "GuestProcessImpl.h" @@ -65,6 +66,33 @@ protected: ComObjPtr mProgress; }; +/** + * Task for opening a guest session. + */ +class SessionTaskOpen : public GuestSessionTask +{ +public: + + SessionTaskOpen(GuestSession *pSession, + uint32_t uFlags, + uint32_t uTimeoutMS); + + virtual ~SessionTaskOpen(void); + +public: + + int Run(int *pGuestRc); + int RunAsync(const Utf8Str &strDesc, ComObjPtr &pProgress); + static int taskThread(RTTHREAD Thread, void *pvUser); + +protected: + + /** Session creation flags. */ + uint32_t mFlags; + /** Session creation timeout (in ms). */ + uint32_t mTimeoutMS; +}; + /** * Task for copying files from host to the guest. */ @@ -130,7 +158,8 @@ class SessionTaskUpdateAdditions : public GuestSessionTask public: SessionTaskUpdateAdditions(GuestSession *pSession, - const Utf8Str &strSource, uint32_t uFlags); + const Utf8Str &strSource, const ProcessArguments &aArguments, + uint32_t uFlags); virtual ~SessionTaskUpdateAdditions(void); @@ -191,6 +220,8 @@ protected: GuestProcessStartupInfo mProcInfo; }; + int addProcessArguments(ProcessArguments &aArgumentsDest, + const ProcessArguments &aArgumentsSource); int copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize); @@ -201,6 +232,8 @@ protected: /** The (optionally) specified Guest Additions .ISO on the host * which will be used for the updating process. */ Utf8Str mSource; + /** (Optional) installer command line arguments. */ + ProcessArguments mArguments; /** Update flags. */ uint32_t mFlags; }; @@ -210,6 +243,7 @@ protected: */ class ATL_NO_VTABLE GuestSession : public VirtualBoxBase, + public GuestBase, VBOX_SCRIPTABLE_IMPL(IGuestSession) { public: @@ -223,7 +257,7 @@ public: END_COM_MAP() DECLARE_EMPTY_CTOR_DTOR(GuestSession) - int init(Guest *aGuest, ULONG aSessionID, Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName); + int init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo, const GuestCredentials &guestCreds); void uninit(void); HRESULT FinalConstruct(void); void FinalRelease(void); @@ -235,13 +269,16 @@ public: STDMETHOD(COMGETTER(Domain))(BSTR *aDomain); STDMETHOD(COMGETTER(Name))(BSTR *aName); STDMETHOD(COMGETTER(Id))(ULONG *aId); + STDMETHOD(COMGETTER(Status))(GuestSessionStatus_T *aStatus); STDMETHOD(COMGETTER(Timeout))(ULONG *aTimeout); STDMETHOD(COMSETTER(Timeout))(ULONG aTimeout); + STDMETHOD(COMGETTER(ProtocolVersion))(ULONG *aVersion); STDMETHOD(COMGETTER(Environment))(ComSafeArrayOut(BSTR, aEnvironment)); STDMETHOD(COMSETTER(Environment))(ComSafeArrayIn(IN_BSTR, aEnvironment)); STDMETHOD(COMGETTER(Processes))(ComSafeArrayOut(IGuestProcess *, aProcesses)); STDMETHOD(COMGETTER(Directories))(ComSafeArrayOut(IGuestDirectory *, aDirectories)); STDMETHOD(COMGETTER(Files))(ComSafeArrayOut(IGuestFile *, aFiles)); + STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); /** @} */ /** @name IGuestSession methods. @@ -265,7 +302,8 @@ public: STDMETHOD(FileCreateTemp)(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile); STDMETHOD(FileExists)(IN_BSTR aPath, BOOL *aExists); STDMETHOD(FileRemove)(IN_BSTR aPath); - STDMETHOD(FileOpen)(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile); + STDMETHOD(FileOpen)(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, IGuestFile **aFile); + STDMETHOD(FileOpenEx)(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, IN_BSTR aSharingMode, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile); STDMETHOD(FileQueryInfo)(IN_BSTR aPath, IGuestFsObjInfo **aInfo); STDMETHOD(FileQuerySize)(IN_BSTR aPath, LONG64 *aSize); STDMETHOD(FileRename)(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags)); @@ -282,12 +320,16 @@ public: STDMETHOD(SymlinkRead)(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget); STDMETHOD(SymlinkRemoveDirectory)(IN_BSTR aPath); STDMETHOD(SymlinkRemoveFile)(IN_BSTR aFile); + STDMETHOD(WaitFor)(ULONG aWaitFlags, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason); + STDMETHOD(WaitForArray)(ComSafeArrayIn(GuestSessionWaitForFlag_T, aFlags), ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason); /** @} */ private: - typedef std::vector > SessionDirectories; - typedef std::vector > SessionFiles; + /** Map of guest directories. The key specifies the internal directory ID. */ + typedef std::map > SessionDirectories; + /** Map of guest files. The key specifies the internal file ID. */ + typedef std::map > SessionFiles; /** Map of guest processes. The key specifies the internal process number. * To retrieve the process' guest PID use the Id() method of the IProcess interface. */ typedef std::map > SessionProcesses; @@ -295,66 +337,100 @@ private: public: /** @name Public internal methods. * @{ */ + int closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc); + inline bool directoryExists(uint32_t uDirID, ComObjPtr *pDir); int directoryRemoveFromList(GuestDirectory *pDirectory); + int directoryRemoveInternal(const Utf8Str &strPath, uint32_t uFlags, int *pGuestRc); int directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc); - int objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, bool fDirectory, const Utf8Str &strName, int *pGuestRc); - int directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags, ComObjPtr &pDirectory); + int objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, bool fDirectory, Utf8Str &strName, int *pGuestRc); + int directoryOpenInternal(const GuestDirectoryOpenInfo &openInfo, ComObjPtr &pDirectory, int *pGuestRc); int directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); - int dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData); + int dispatchToDirectory(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int dispatchToObject(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + int dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb); + inline bool fileExists(uint32_t uFileID, ComObjPtr *pFile); int fileRemoveFromList(GuestFile *pFile); int fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc); - int fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, - uint32_t uCreationMode, int64_t iOffset, ComObjPtr &pFile, int *pGuestRc); + int fileOpenInternal(const GuestFileOpenInfo &openInfo, ComObjPtr &pFile, int *pGuestRc); int fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); int fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc); int fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); const GuestCredentials &getCredentials(void); const GuestEnvironment &getEnvironment(void); + EventSource *getEventSource(void) { return mEventSource; } Utf8Str getName(void); - ULONG getId(void) { return mData.mId; } - Guest *getParent(void) { return mData.mParent; } + ULONG getId(void) { return mData.mSession.mID; } + static Utf8Str guestErrorToString(int guestRc); + HRESULT isReadyExternal(void); + int onRemove(void); + int onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); + int startSessionInternal(int *pGuestRc); + int startSessionAsync(void); + static DECLCALLBACK(int) + startSessionThread(RTTHREAD Thread, void *pvUser); + Guest *getParent(void) { return mParent; } uint32_t getProtocolVersion(void) { return mData.mProtocolVersion; } + int pathRenameInternal(const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags, int *pGuestRc); int processRemoveFromList(GuestProcess *pProcess); int processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr &pProgress); inline bool processExists(uint32_t uProcessID, ComObjPtr *pProcess); inline int processGetByPID(ULONG uPID, ComObjPtr *pProcess); + int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); + static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); + int setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc); + int signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */); int startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr &pProgress); int queryInfo(void); + int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc); + int waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc); /** @} */ private: + /** Pointer to the parent (Guest). */ + Guest *mParent; + /** + * The session's event source. This source is used for + * serving the internal listener as well as all other + * external listeners that may register to it. + * + * Note: This can safely be used without holding any locks. + * An AutoCaller suffices to prevent it being destroy while in use and + * internally there is a lock providing the necessary serialization. + */ + const ComObjPtr mEventSource; + struct Data { - /** Guest control protocol version to be used. - * Guest Additions < VBox 4.2 have version 1, - * any newer version will have version 2. */ - uint32_t mProtocolVersion; - /** Flag indicating if this is an internal session - * or not. Internal session are not accessible by clients. */ - bool fInternal; - /** Pointer to the parent (Guest). */ - Guest *mParent; /** The session credentials. */ - GuestCredentials mCredentials; - /** The (optional) session name. */ - Utf8Str mName; - /** The session ID. */ - ULONG mId; - /** The session timeout. Default is 30s. */ - ULONG mTimeout; + GuestCredentials mCredentials; + /** The session's startup info. */ + GuestSessionStartupInfo mSession; + /** The session's current status. */ + GuestSessionStatus_T mStatus; /** The session's environment block. Can be * overwritten/extended by ProcessCreate(Ex). */ - GuestEnvironment mEnvironment; + GuestEnvironment mEnvironment; /** Directory objects bound to this session. */ - SessionDirectories mDirectories; + SessionDirectories mDirectories; /** File objects bound to this session. */ - SessionFiles mFiles; + SessionFiles mFiles; /** Process objects bound to this session. */ - SessionProcesses mProcesses; + SessionProcesses mProcesses; + /** Guest control protocol version to be used. + * Guest Additions < VBox 4.3 have version 1, + * any newer version will have version 2. */ + uint32_t mProtocolVersion; + /** Session timeout (in ms). */ + uint32_t mTimeout; /** Total number of session objects (processes, * files, ...). */ - uint32_t mNumObjects; + uint32_t mNumObjects; + /** The last returned session status + * returned from the guest side. */ + int mRC; } mData; }; diff --git a/src/VBox/Main/include/HGCM.h b/src/VBox/Main/include/HGCM.h index f96d8432..acf1528b 100644 --- a/src/VBox/Main/include/HGCM.h +++ b/src/VBox/Main/include/HGCM.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/HGCMObjects.h b/src/VBox/Main/include/HGCMObjects.h index f7f51884..27c9c967 100644 --- a/src/VBox/Main/include/HGCMObjects.h +++ b/src/VBox/Main/include/HGCMObjects.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/HGCMThread.h b/src/VBox/Main/include/HGCMThread.h index fb01cebc..ab0abcc7 100644 --- a/src/VBox/Main/include/HGCMThread.h +++ b/src/VBox/Main/include/HGCMThread.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/HostHardwareLinux.h b/src/VBox/Main/include/HostHardwareLinux.h index 6469ced1..b30da8a2 100644 --- a/src/VBox/Main/include/HostHardwareLinux.h +++ b/src/VBox/Main/include/HostHardwareLinux.h @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/HostImpl.h b/src/VBox/Main/include/HostImpl.h index 56decbfc..a8f34e01 100644 --- a/src/VBox/Main/include/HostImpl.h +++ b/src/VBox/Main/include/HostImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -61,9 +61,13 @@ public: STDMETHOD(COMGETTER(USBDevices))(ComSafeArrayOut(IHostUSBDevice *, aUSBDevices)); STDMETHOD(COMGETTER(USBDeviceFilters))(ComSafeArrayOut(IHostUSBDeviceFilter *, aUSBDeviceFilters)); STDMETHOD(COMGETTER(NetworkInterfaces))(ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces)); + STDMETHOD(COMGETTER(NameServers))(ComSafeArrayOut(BSTR, aNameServers)); + STDMETHOD(COMGETTER(DomainName))(BSTR *aDomainName); + STDMETHOD(COMGETTER(SearchStrings))(ComSafeArrayOut(BSTR, aSearchStrings)); STDMETHOD(COMGETTER(ProcessorCount))(ULONG *count); STDMETHOD(COMGETTER(ProcessorOnlineCount))(ULONG *count); STDMETHOD(COMGETTER(ProcessorCoreCount))(ULONG *count); + STDMETHOD(COMGETTER(ProcessorOnlineCoreCount))(ULONG *count); STDMETHOD(GetProcessorSpeed)(ULONG cpuId, ULONG *speed); STDMETHOD(GetProcessorDescription)(ULONG cpuId, BSTR *description); STDMETHOD(GetProcessorFeature)(ProcessorFeature_T feature, BOOL *supported); @@ -74,6 +78,7 @@ public: STDMETHOD(COMGETTER(OSVersion))(BSTR *version); STDMETHOD(COMGETTER(UTCTime))(LONG64 *aUTCTime); STDMETHOD(COMGETTER(Acceleration3DAvailable))(BOOL *aSupported); + STDMETHOD(COMGETTER(VideoInputDevices))(ComSafeArrayOut(IHostVideoInputDevice*, aVideoInputDevices)); // IHost methods STDMETHOD(CreateHostOnlyNetworkInterface)(IHostNetworkInterface **aHostNetworkInterface, @@ -146,6 +151,12 @@ private: HRESULT updateNetIfList(); +#ifndef RT_OS_WINDOWS + HRESULT parseResolvConf(); +#else + HRESULT fetchNameResolvingInformation(); +#endif + #ifdef VBOX_WITH_RESOURCE_USAGE_API void registerMetrics(PerformanceCollector *aCollector); void registerDiskMetrics(PerformanceCollector *aCollector); diff --git a/src/VBox/Main/include/HostNetworkInterfaceImpl.h b/src/VBox/Main/include/HostNetworkInterfaceImpl.h index 54449c33..4055d1e8 100644 --- a/src/VBox/Main/include/HostNetworkInterfaceImpl.h +++ b/src/VBox/Main/include/HostNetworkInterfaceImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -59,6 +59,7 @@ public: // IHostNetworkInterface properties STDMETHOD(COMGETTER(Name))(BSTR *aInterfaceName); + STDMETHOD(COMGETTER(ShortName))(BSTR *aShortName); STDMETHOD(COMGETTER(Id))(BSTR *aGuid); STDMETHOD(COMGETTER(DHCPEnabled))(BOOL *aDHCPEnabled); STDMETHOD(COMGETTER(IPAddress))(BSTR *aIPAddress); @@ -78,8 +79,10 @@ public: STDMETHOD(DHCPRediscover)(); HRESULT setVirtualBox(VirtualBox *pVBox); +#ifdef VBOX_WITH_RESOURCE_USAGE_API void registerMetrics(PerformanceCollector *aCollector, ComPtr objptr); void unregisterMetrics(PerformanceCollector *aCollector, ComPtr objptr); +#endif private: Bstr composeNetworkName(const Utf8Str szShortName); diff --git a/src/VBox/Main/include/HostPower.h b/src/VBox/Main/include/HostPower.h index 0d7ba548..c7774c33 100644 --- a/src/VBox/Main/include/HostPower.h +++ b/src/VBox/Main/include/HostPower.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -19,7 +19,6 @@ #define ____H_HOSTPOWER #include "VirtualBoxBase.h" -#include "MachineImpl.h" #include @@ -28,27 +27,16 @@ # include #endif /* RT_OS_DARWIN */ -typedef enum -{ - HostPowerEvent_Suspend, - HostPowerEvent_Resume, - HostPowerEvent_BatteryLow -} HostPowerEvent; - class HostPowerService { -public: - - HostPowerService (VirtualBox *aVirtualBox); + public: + HostPowerService(VirtualBox *aVirtualBox); virtual ~HostPowerService(); + void notify(Reason_T aReason); - void notify (HostPowerEvent aEvent); - -protected: - - VirtualBox *mVirtualBox; - - std::vector< ComPtr > mConsoles; + protected: + VirtualBox *mVirtualBox; + std::vector > mSessionControls; }; # ifdef RT_OS_WINDOWS @@ -64,7 +52,7 @@ public: private: - static DECLCALLBACK(int) NotificationThread (RTTHREAD ThreadSelf, void *pInstance); + static DECLCALLBACK(int) NotificationThread(RTTHREAD ThreadSelf, void *pInstance); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); HWND mHwnd; @@ -78,16 +66,16 @@ class HostPowerServiceDarwin : public HostPowerService { public: - HostPowerServiceDarwin (VirtualBox *aVirtualBox); + HostPowerServiceDarwin(VirtualBox *aVirtualBox); virtual ~HostPowerServiceDarwin(); private: - static DECLCALLBACK(int) powerChangeNotificationThread (RTTHREAD ThreadSelf, void *pInstance); - static void powerChangeNotificationHandler (void *pvData, io_service_t service, natural_t messageType, void *pMessageArgument); - static void lowPowerHandler (void *pvData); + static DECLCALLBACK(int) powerChangeNotificationThread(RTTHREAD ThreadSelf, void *pInstance); + static void powerChangeNotificationHandler(void *pvData, io_service_t service, natural_t messageType, void *pMessageArgument); + static void lowPowerHandler(void *pvData); - void checkBatteryCriticalLevel (bool *pfCriticalChanged = NULL); + void checkBatteryCriticalLevel(bool *pfCriticalChanged = NULL); /* Private member vars */ RTTHREAD mThread; /* Our message thread. */ diff --git a/src/VBox/Main/include/HostUSBDeviceImpl.h b/src/VBox/Main/include/HostUSBDeviceImpl.h index e04f1727..57023e1e 100644 --- a/src/VBox/Main/include/HostUSBDeviceImpl.h +++ b/src/VBox/Main/include/HostUSBDeviceImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/HostVideoInputDeviceImpl.h b/src/VBox/Main/include/HostVideoInputDeviceImpl.h new file mode 100644 index 00000000..5e385455 --- /dev/null +++ b/src/VBox/Main/include/HostVideoInputDeviceImpl.h @@ -0,0 +1,71 @@ +/* $Id: HostVideoInputDeviceImpl.h $ */ + +/** @file + * + * A host video capture device description. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef HOSTVIDEOINPUTDEVICE_IMPL_H_ +#define HOSTVIDEOINPUTDEVICE_IMPL_H_ + +#include "HostVideoInputDeviceWrap.h" + +#include + +class HostVideoInputDevice; + +typedef std::list > HostVideoInputDeviceList; + +class ATL_NO_VTABLE HostVideoInputDevice : + public HostVideoInputDeviceWrap +{ +public: + + DECLARE_EMPTY_CTOR_DTOR(HostVideoInputDevice) + + HRESULT FinalConstruct(); + void FinalRelease(); + + /* Public initializer/uninitializer for internal purposes only. */ + HRESULT init(const com::Utf8Str &name, const com::Utf8Str &path, const com::Utf8Str &alias); + void uninit(); + + static HRESULT queryHostDevices(VirtualBox *pVirtualBox, HostVideoInputDeviceList *pList); + +private: + + // wrapped IHostVideoInputDevice properties + virtual HRESULT getName(com::Utf8Str &aName) { aName = m.name; return S_OK; } + virtual HRESULT getPath(com::Utf8Str &aPath) { aPath = m.path; return S_OK; } + virtual HRESULT getAlias(com::Utf8Str &aAlias) { aAlias = m.alias; return S_OK; } + + /* Data. */ + struct Data + { + Data() + { + } + + com::Utf8Str name; + com::Utf8Str path; + com::Utf8Str alias; + }; + + Data m; +}; + +#endif // HOSTVIDEOINPUTDEVICE_IMPL_H_ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/KeyboardImpl.h b/src/VBox/Main/include/KeyboardImpl.h index 4b8446f4..a94e67bf 100644 --- a/src/VBox/Main/include/KeyboardImpl.h +++ b/src/VBox/Main/include/KeyboardImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -85,8 +85,9 @@ public: private: - static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); + static DECLCALLBACK(void) keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds); static DECLCALLBACK(void) keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive); + static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns); diff --git a/src/VBox/Main/include/Logging.h b/src/VBox/Main/include/Logging.h index c6385e22..4de5f576 100644 --- a/src/VBox/Main/include/Logging.h +++ b/src/VBox/Main/include/Logging.h @@ -40,6 +40,9 @@ #else # define LOG_GROUP LOG_GROUP_MAIN #endif +#ifndef VBOXSVC_LOG_DEFAULT +# define VBOXSVC_LOG_DEFAULT "all" +#endif #include diff --git a/src/VBox/Main/include/MachineDebuggerImpl.h b/src/VBox/Main/include/MachineDebuggerImpl.h index d92cbe28..ab5a6b65 100644 --- a/src/VBox/Main/include/MachineDebuggerImpl.h +++ b/src/VBox/Main/include/MachineDebuggerImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,6 +22,7 @@ #include "VirtualBoxBase.h" #include +#include class Console; @@ -57,6 +58,8 @@ public: STDMETHOD(COMSETTER(RecompileUser))(BOOL a_fEnable); STDMETHOD(COMGETTER(RecompileSupervisor))(BOOL *a_pfEnabled); STDMETHOD(COMSETTER(RecompileSupervisor))(BOOL a_fEnable); + STDMETHOD(COMGETTER(ExecuteAllInIEM))(BOOL *a_pfEnabled); + STDMETHOD(COMSETTER(ExecuteAllInIEM))(BOOL a_fEnable); STDMETHOD(COMGETTER(PATMEnabled))(BOOL *a_pfEnabled); STDMETHOD(COMSETTER(PATMEnabled))(BOOL a_fEnable); STDMETHOD(COMGETTER(CSAMEnabled))(BOOL *a_pfEnabled); @@ -72,6 +75,7 @@ public: STDMETHOD(COMGETTER(HWVirtExEnabled))(BOOL *a_pfEnabled); STDMETHOD(COMGETTER(HWVirtExNestedPagingEnabled))(BOOL *a_pfEnabled); STDMETHOD(COMGETTER(HWVirtExVPIDEnabled))(BOOL *a_pfEnabled); + STDMETHOD(COMGETTER(HWVirtExUXEnabled))(BOOL *a_pfEnabled); STDMETHOD(COMGETTER(PAEEnabled))(BOOL *a_pfEnabled); STDMETHOD(COMGETTER(OSName))(BSTR *a_pbstrName); STDMETHOD(COMGETTER(OSVersion))(BSTR *a_pbstrVersion); @@ -108,6 +112,8 @@ public: private: // private methods bool queueSettings() const; + HRESULT getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced); + HRESULT setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce); /** RTLogGetFlags, RTLogGetGroupSettings and RTLogGetDestinations function. */ typedef DECLCALLBACK(int) FNLOGGETSTR(PRTLOGGER, char *, size_t); @@ -119,6 +125,7 @@ private: /** @name Flags whether settings have been queued because they could not be sent * to the VM (not up yet, etc.) * @{ */ + uint8_t maiQueuedEmExecPolicyParams[EMEXECPOLICY_END]; int mSingleStepQueued; int mRecompileUserQueued; int mRecompileSupervisorQueued; diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h index 888861a4..0ad42659 100644 --- a/src/VBox/Main/include/MachineImpl.h +++ b/src/VBox/Main/include/MachineImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,6 +31,7 @@ #include "ParallelPortImpl.h" #include "BIOSSettingsImpl.h" #include "StorageControllerImpl.h" // required for MachineImpl.h to compile on Windows +#include "USBControllerImpl.h" // required for MachineImpl.h to compile on Windows #include "BandwidthControlImpl.h" #include "BandwidthGroupImpl.h" #include "VBox/settings.h" @@ -64,6 +65,7 @@ class Mouse; class Display; class MachineDebugger; class USBController; +class USBDeviceFilters; class Snapshot; class SharedFolder; class HostUSBDevice; @@ -222,6 +224,8 @@ public: struct UserData { settings::MachineUserData s; + typedef std::vector IconBlob; + IconBlob mIcon; }; /** @@ -238,8 +242,6 @@ public: * Data structure to hold information about a guest property. */ struct GuestProperty { - /** Property name */ - Utf8Str strName; /** Property value */ Utf8Str strValue; /** Property timestamp */ @@ -251,67 +253,75 @@ public: HWData(); ~HWData(); - Bstr mHWVersion; - Guid mHardwareUUID; /**< If Null, use mData.mUuid. */ - ULONG mMemorySize; - ULONG mMemoryBalloonSize; - BOOL mPageFusionEnabled; - ULONG mVRAMSize; - ULONG mVideoCaptureWidth; - ULONG mVideoCaptureHeight; - Bstr mVideoCaptureFile; - BOOL mVideoCaptureEnabled; - ULONG mMonitorCount; - BOOL mHWVirtExEnabled; - BOOL mHWVirtExExclusive; - BOOL mHWVirtExNestedPagingEnabled; - BOOL mHWVirtExLargePagesEnabled; - BOOL mHWVirtExVPIDEnabled; - BOOL mHWVirtExForceEnabled; - BOOL mAccelerate2DVideoEnabled; - BOOL mPAEEnabled; - BOOL mSyntheticCpu; - ULONG mCPUCount; - BOOL mCPUHotPlugEnabled; - ULONG mCpuExecutionCap; - BOOL mAccelerate3DEnabled; - BOOL mHPETEnabled; - - BOOL mCPUAttached[SchemaDefs::MaxCPUCount]; - - settings::CpuIdLeaf mCpuIdStdLeafs[11]; - settings::CpuIdLeaf mCpuIdExtLeafs[11]; - - DeviceType_T mBootOrder[SchemaDefs::MaxBootPosition]; + Bstr mHWVersion; + Guid mHardwareUUID; /**< If Null, use mData.mUuid. */ + ULONG mMemorySize; + ULONG mMemoryBalloonSize; + BOOL mPageFusionEnabled; + GraphicsControllerType_T mGraphicsControllerType; + ULONG mVRAMSize; + ULONG mVideoCaptureWidth; + ULONG mVideoCaptureHeight; + ULONG mVideoCaptureRate; + ULONG mVideoCaptureFPS; + Utf8Str mVideoCaptureFile; + BOOL mVideoCaptureEnabled; + BOOL maVideoCaptureScreens[SchemaDefs::MaxGuestMonitors]; + ULONG mMonitorCount; + BOOL mHWVirtExEnabled; + BOOL mHWVirtExNestedPagingEnabled; + BOOL mHWVirtExLargePagesEnabled; + BOOL mHWVirtExVPIDEnabled; + BOOL mHWVirtExUXEnabled; + BOOL mHWVirtExForceEnabled; + BOOL mAccelerate2DVideoEnabled; + BOOL mPAEEnabled; + settings::Hardware::LongModeType mLongMode; + BOOL mSyntheticCpu; + BOOL mTripleFaultReset; + ULONG mCPUCount; + BOOL mCPUHotPlugEnabled; + ULONG mCpuExecutionCap; + BOOL mAccelerate3DEnabled; + BOOL mHPETEnabled; + + BOOL mCPUAttached[SchemaDefs::MaxCPUCount]; + + settings::CpuIdLeaf mCpuIdStdLeafs[11]; + settings::CpuIdLeaf mCpuIdExtLeafs[11]; + + DeviceType_T mBootOrder[SchemaDefs::MaxBootPosition]; typedef std::list > SharedFolderList; - SharedFolderList mSharedFolders; + SharedFolderList mSharedFolders; - ClipboardMode_T mClipboardMode; - DragAndDropMode_T mDragAndDropMode; + ClipboardMode_T mClipboardMode; + DragAndDropMode_T mDragAndDropMode; - typedef std::list GuestPropertyList; - GuestPropertyList mGuestProperties; - Utf8Str mGuestPropertyNotificationPatterns; + typedef std::map GuestPropertyMap; + GuestPropertyMap mGuestProperties; + Utf8Str mGuestPropertyNotificationPatterns; - FirmwareType_T mFirmwareType; - KeyboardHIDType_T mKeyboardHIDType; - PointingHIDType_T mPointingHIDType; - ChipsetType_T mChipsetType; - BOOL mEmulatedUSBCardReaderEnabled; + FirmwareType_T mFirmwareType; + KeyboardHIDType_T mKeyboardHIDType; + PointingHIDType_T mPointingHIDType; + ChipsetType_T mChipsetType; + BOOL mEmulatedUSBCardReaderEnabled; - BOOL mIOCacheEnabled; - ULONG mIOCacheSize; + BOOL mIOCacheEnabled; + ULONG mIOCacheSize; typedef std::list > PCIDeviceAssignmentList; PCIDeviceAssignmentList mPCIDeviceAssignments; - settings::Debugging mDebugging; - settings::Autostart mAutostart; + settings::Debugging mDebugging; + settings::Autostart mAutostart; + + Utf8Str mDefaultFrontend; }; /** - * Hard disk and other media data. + * Hard disk and other media data. * * The usage policy is the same as for HWData, but a separate structure * is necessary because hard disk data requires different procedures when @@ -406,39 +416,46 @@ public: STDMETHOD(COMSETTER(CPUHotPlugEnabled))(BOOL enabled); STDMETHOD(COMGETTER(CPUExecutionCap))(ULONG *aExecutionCap); STDMETHOD(COMSETTER(CPUExecutionCap))(ULONG aExecutionCap); - STDMETHOD(COMGETTER(EmulatedUSBCardReaderEnabled))(BOOL *enabled); - STDMETHOD(COMSETTER(EmulatedUSBCardReaderEnabled))(BOOL enabled); - STDMETHOD(COMGETTER(EmulatedUSBWebcameraEnabled))(BOOL *enabled); - STDMETHOD(COMSETTER(EmulatedUSBWebcameraEnabled))(BOOL enabled); + STDMETHOD(COMGETTER(EmulatedUSBCardReaderEnabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(EmulatedUSBCardReaderEnabled))(BOOL aEnabled); STDMETHOD(COMGETTER(HPETEnabled))(BOOL *enabled); STDMETHOD(COMSETTER(HPETEnabled))(BOOL enabled); STDMETHOD(COMGETTER(MemoryBalloonSize))(ULONG *memoryBalloonSize); STDMETHOD(COMSETTER(MemoryBalloonSize))(ULONG memoryBalloonSize); STDMETHOD(COMGETTER(PageFusionEnabled))(BOOL *enabled); STDMETHOD(COMSETTER(PageFusionEnabled))(BOOL enabled); + STDMETHOD(COMGETTER(GraphicsControllerType))(GraphicsControllerType_T *aGraphicsController); + STDMETHOD(COMSETTER(GraphicsControllerType))(GraphicsControllerType_T aGraphicsController); STDMETHOD(COMGETTER(VRAMSize))(ULONG *memorySize); STDMETHOD(COMSETTER(VRAMSize))(ULONG memorySize); + STDMETHOD(COMGETTER(Accelerate3DEnabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(Accelerate3DEnabled))(BOOL aEnabled); + STDMETHOD(COMGETTER(Accelerate2DVideoEnabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(Accelerate2DVideoEnabled))(BOOL aEnabled); + STDMETHOD(COMGETTER(MonitorCount))(ULONG *monitorCount); + STDMETHOD(COMSETTER(MonitorCount))(ULONG monitorCount); STDMETHOD(COMGETTER(VideoCaptureEnabled))(BOOL *u8VideoRecEnabled); STDMETHOD(COMSETTER(VideoCaptureEnabled))(BOOL u8VideoRecEnabled); + STDMETHOD(COMGETTER(VideoCaptureScreens))(ComSafeArrayOut(BOOL, aScreens)); + STDMETHOD(COMSETTER(VideoCaptureScreens))(ComSafeArrayIn(BOOL, aScreens)); STDMETHOD(COMGETTER(VideoCaptureFile))(BSTR * ppChVideoRecFilename); STDMETHOD(COMSETTER(VideoCaptureFile))(IN_BSTR pChVideoRecFilename); - STDMETHOD(COMGETTER(VideoCaptureWidth))(ULONG *u32VideoRecHorzRes); - STDMETHOD(COMSETTER(VideoCaptureWidth))(ULONG u32VideoRecHorzRes); - STDMETHOD(COMGETTER(VideoCaptureHeight))(ULONG *u32VideoRecVertRes); - STDMETHOD(COMSETTER(VideoCaptureHeight))(ULONG u32VideoRecVertRes); - STDMETHOD(COMGETTER(MonitorCount))(ULONG *monitorCount); - STDMETHOD(COMSETTER(MonitorCount))(ULONG monitorCount); - STDMETHOD(COMGETTER(Accelerate3DEnabled))(BOOL *enabled); - STDMETHOD(COMSETTER(Accelerate3DEnabled))(BOOL enabled); - STDMETHOD(COMGETTER(Accelerate2DVideoEnabled))(BOOL *enabled); - STDMETHOD(COMSETTER(Accelerate2DVideoEnabled))(BOOL enabled); + STDMETHOD(COMGETTER(VideoCaptureWidth))(ULONG *aHorzRes); + STDMETHOD(COMSETTER(VideoCaptureWidth))(ULONG aorzRes); + STDMETHOD(COMGETTER(VideoCaptureHeight))(ULONG *aVertRes); + STDMETHOD(COMSETTER(VideoCaptureHeight))(ULONG aVertRes); + STDMETHOD(COMGETTER(VideoCaptureRate))(ULONG *aRate); + STDMETHOD(COMSETTER(VideoCaptureRate))(ULONG aRate); + STDMETHOD(COMGETTER(VideoCaptureFPS))(ULONG *aFPS); + STDMETHOD(COMSETTER(VideoCaptureFPS))(ULONG aFPS); STDMETHOD(COMGETTER(BIOSSettings))(IBIOSSettings **biosSettings); STDMETHOD(COMGETTER(SnapshotFolder))(BSTR *aSavedStateFolder); STDMETHOD(COMSETTER(SnapshotFolder))(IN_BSTR aSavedStateFolder); STDMETHOD(COMGETTER(MediumAttachments))(ComSafeArrayOut(IMediumAttachment *, aAttachments)); STDMETHOD(COMGETTER(VRDEServer))(IVRDEServer **vrdeServer); STDMETHOD(COMGETTER(AudioAdapter))(IAudioAdapter **audioAdapter); - STDMETHOD(COMGETTER(USBController))(IUSBController * *aUSBController); + STDMETHOD(COMGETTER(USBControllers))(ComSafeArrayOut(IUSBController *, aUSBControllers)); + STDMETHOD(COMGETTER(USBDeviceFilters))(IUSBDeviceFilters * *aUSBDeviceFilters); STDMETHOD(COMGETTER(SettingsFilePath))(BSTR *aFilePath); STDMETHOD(COMGETTER(SettingsModified))(BOOL *aModified); STDMETHOD(COMGETTER(SessionState))(SessionState_T *aSessionState); @@ -505,6 +522,11 @@ public: STDMETHOD(COMSETTER(AutostartDelay))(ULONG uDelay); STDMETHOD(COMGETTER(AutostopType))(AutostopType_T *penmAutostopType); STDMETHOD(COMSETTER(AutostopType))(AutostopType_T enmAutostopType); + STDMETHOD(COMGETTER(DefaultFrontend))(BSTR *aDefaultFrontend); + STDMETHOD(COMSETTER(DefaultFrontend))(IN_BSTR aDefaultFrontend); + STDMETHOD(COMGETTER(Icon))(ComSafeArrayOut(BYTE, aIcon)); + STDMETHOD(COMSETTER(Icon))(ComSafeArrayIn(BYTE, aIcon)); + STDMETHOD(COMGETTER(USBProxyAvailable))(BOOL *aAvailable); // IMachine methods STDMETHOD(LockMachine)(ISession *aSession, LockType_T lockType); @@ -521,6 +543,7 @@ public: STDMETHOD(TemporaryEjectDevice)(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice, BOOL aTempEject); STDMETHOD(NonRotationalDevice)(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice, BOOL aNonRotational); STDMETHOD(SetAutoDiscardForDevice)(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice, BOOL aDiscard); + STDMETHOD(SetHotPluggableForDevice)(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice, BOOL aHotPluggable); STDMETHOD(SetNoBandwidthGroupForDevice)(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice); STDMETHOD(SetBandwidthGroupForDevice)(IN_BSTR aControllerName, LONG aControllerPort, @@ -545,11 +568,12 @@ public: STDMETHOD(RemoveAllCPUIDLeaves)(); STDMETHOD(GetHWVirtExProperty)(HWVirtExPropertyType_T property, BOOL *aVal); STDMETHOD(SetHWVirtExProperty)(HWVirtExPropertyType_T property, BOOL aVal); + STDMETHOD(SetSettingsFilePath)(IN_BSTR aFilePath, IProgress **aProgress); STDMETHOD(SaveSettings)(); STDMETHOD(DiscardSettings)(); STDMETHOD(Unregister)(CleanupMode_T cleanupMode, ComSafeArrayOut(IMedium*, aMedia)); - STDMETHOD(Delete)(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress); - STDMETHOD(Export)(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription); + STDMETHOD(DeleteConfig)(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress); + STDMETHOD(ExportTo)(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription); STDMETHOD(FindSnapshot)(IN_BSTR aNameOrId, ISnapshot **aSnapshot); STDMETHOD(CreateSharedFolder)(IN_BSTR aName, IN_BSTR aHostPath, BOOL aWritable, BOOL aAutoMount); STDMETHOD(RemoveSharedFolder)(IN_BSTR aName); @@ -569,6 +593,10 @@ public: STDMETHOD(GetStorageControllerByName(IN_BSTR aName, IStorageController **storageController)); STDMETHOD(GetStorageControllerByInstance(ULONG aInstance, IStorageController **storageController)); STDMETHOD(SetStorageControllerBootable)(IN_BSTR aName, BOOL fBootable); + STDMETHOD(AddUSBController)(IN_BSTR aName, USBControllerType_T aConnectionType, IUSBController **controller); + STDMETHOD(RemoveUSBController(IN_BSTR aName)); + STDMETHOD(GetUSBControllerByName(IN_BSTR aName, IUSBController **usbController)); + STDMETHOD(GetUSBControllerCountByType(USBControllerType_T aType, ULONG *aControllers)); STDMETHOD(QuerySavedGuestScreenInfo)(ULONG uScreenId, ULONG *puOriginX, ULONG *puOriginY, ULONG *puWidth, ULONG *puHeight, BOOL *pfEnabled); STDMETHOD(QuerySavedThumbnailSize)(ULONG aScreenId, ULONG *aSize, ULONG *aWidth, ULONG *aHeight); STDMETHOD(ReadSavedThumbnailToArray)(ULONG aScreenId, BOOL aBGR, ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData)); @@ -718,7 +746,8 @@ public: virtual HRESULT onClipboardModeChange(ClipboardMode_T /* aClipboardMode */) { return S_OK; } virtual HRESULT onDragAndDropModeChange(DragAndDropMode_T /* aDragAndDropMode */) { return S_OK; } virtual HRESULT onBandwidthGroupChange(IBandwidthGroup * /* aBandwidthGroup */) { return S_OK; } - virtual HRESULT onStorageDeviceChange(IMediumAttachment * /* mediumAttachment */, BOOL /* remove */) { return S_OK; } + virtual HRESULT onStorageDeviceChange(IMediumAttachment * /* mediumAttachment */, BOOL /* remove */, BOOL /* silent */) { return S_OK; } + virtual HRESULT onVideoCaptureChange() { return S_OK; } HRESULT saveRegistryEntry(settings::MachineRegistryEntry &data); @@ -730,6 +759,10 @@ public: void composeSavedStateFilename(Utf8Str &strStateFilePath); + void getDefaultVideoCaptureFile(Utf8Str &strFile); + + bool isUSBControllerPresent(); + HRESULT launchVMProcess(IInternalSessionControl *aControl, const Utf8Str &strType, const Utf8Str &strEnvironment, @@ -748,33 +781,6 @@ public: return rc; } -#if defined(RT_OS_WINDOWS) - - bool isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl = NULL, - HANDLE *aIPCSem = NULL, bool aAllowClosing = false); - bool isSessionSpawning(RTPROCESS *aPID = NULL); - - bool isSessionOpenOrClosing(ComObjPtr &aMachine, - ComPtr *aControl = NULL, - HANDLE *aIPCSem = NULL) - { return isSessionOpen(aMachine, aControl, aIPCSem, true /* aAllowClosing */); } - -#elif defined(RT_OS_OS2) - - bool isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl = NULL, - HMTX *aIPCSem = NULL, bool aAllowClosing = false); - - bool isSessionSpawning(RTPROCESS *aPID = NULL); - - bool isSessionOpenOrClosing(ComObjPtr &aMachine, - ComPtr *aControl = NULL, - HMTX *aIPCSem = NULL) - { return isSessionOpen(aMachine, aControl, aIPCSem, true /* aAllowClosing */); } - -#else - bool isSessionOpen(ComObjPtr &aMachine, ComPtr *aControl = NULL, bool aAllowClosing = false); @@ -784,8 +790,6 @@ public: ComPtr *aControl = NULL) { return isSessionOpen(aMachine, aControl, true /* aAllowClosing */); } -#endif - bool checkForSpawnFailure(); HRESULT prepareRegister(); @@ -814,6 +818,8 @@ public: protected: + class ClientToken; + HRESULT checkStateDependency(StateDependency aDepType); Machine *getMachine(); @@ -858,6 +864,12 @@ protected: HRESULT getMediumAttachmentsOfController(CBSTR aName, MediaData::AttachmentList &aAttachments); + HRESULT getUSBControllerByName(const Utf8Str &aName, + ComObjPtr &aUSBController, + bool aSetError = false); + + ULONG getUSBControllerCountByType(USBControllerType_T enmType); + enum { /* flags for #saveSettings() */ @@ -887,7 +899,7 @@ protected: HRESULT createImplicitDiffs(IProgress *aProgress, ULONG aWeight, bool aOnline); - HRESULT deleteImplicitDiffs(); + HRESULT deleteImplicitDiffs(bool aOnline); MediumAttachment* findAttachment(const MediaData::AttachmentList &ll, IN_BSTR aControllerName, @@ -921,6 +933,8 @@ protected: static DECLCALLBACK(int) deleteThread(RTTHREAD Thread, void *pvUser); HRESULT deleteTaskWorker(DeleteTask &task); + Utf8Str getExtraData(const Utf8Str &strKey); + #ifdef VBOX_WITH_GUEST_PROPS HRESULT getGuestPropertyFromService(IN_BSTR aName, BSTR *aValue, LONG64 *aTimestamp, BSTR *aFlags) const; @@ -943,6 +957,7 @@ protected: #endif /* VBOX_WITH_GUEST_PROPS */ #ifdef VBOX_WITH_RESOURCE_USAGE_API + void getDiskList(MediaList &list); void registerMetrics(PerformanceCollector *aCollector, Machine *aMachine, RTPROCESS pid); pm::CollectorGuest *mCollectorGuest; @@ -962,18 +977,22 @@ protected: // the following fields need special backup/rollback/commit handling, // so they cannot be a part of HWData - const ComObjPtr mVRDEServer; - const ComObjPtr mSerialPorts[SchemaDefs::SerialPortCount]; - const ComObjPtr mParallelPorts[SchemaDefs::ParallelPortCount]; - const ComObjPtr mAudioAdapter; - const ComObjPtr mUSBController; - const ComObjPtr mBIOSSettings; + const ComObjPtr mVRDEServer; + const ComObjPtr mSerialPorts[SchemaDefs::SerialPortCount]; + const ComObjPtr mParallelPorts[SchemaDefs::ParallelPortCount]; + const ComObjPtr mAudioAdapter; + const ComObjPtr mUSBDeviceFilters; + const ComObjPtr mBIOSSettings; + const ComObjPtr mBandwidthControl; + typedef std::vector > NetworkAdapterVector; - NetworkAdapterVector mNetworkAdapters; - const ComObjPtr mBandwidthControl; + NetworkAdapterVector mNetworkAdapters; typedef std::list > StorageControllerList; - Backupable mStorageControllers; + Backupable mStorageControllers; + + typedef std::list > USBControllerList; + Backupable mUSBControllers; uint64_t uRegistryNeedsSaving; @@ -1017,9 +1036,16 @@ public: HRESULT FinalConstruct(); void FinalRelease(); + struct Uninit + { + enum Reason { Unexpected, Abnormal, Normal }; + }; + // public initializer/uninitializer for internal purposes only HRESULT init(Machine *aMachine); void uninit() { uninit(Uninit::Unexpected); } + void uninit(Uninit::Reason aReason); + // util::Lockable interface RWLockHandle *lockHandle() const; @@ -1027,7 +1053,6 @@ public: // IInternalMachineControl methods STDMETHOD(SetRemoveSavedStateFile)(BOOL aRemove); STDMETHOD(UpdateState)(MachineState_T machineState); - STDMETHOD(GetIPCId)(BSTR *id); STDMETHOD(BeginPowerUp)(IProgress *aProgress); STDMETHOD(EndPowerUp)(LONG iResult); STDMETHOD(BeginPoweringDown)(IProgress **aProgress); @@ -1051,11 +1076,7 @@ public: STDMETHOD(DeleteSnapshot)(IConsole *aInitiator, IN_BSTR aStartId, IN_BSTR aEndID, BOOL fDeleteAllChildren, MachineState_T *aMachineState, IProgress **aProgress); - STDMETHOD(FinishOnlineMergeMedium)(IMediumAttachment *aMediumAttachment, - IMedium *aSource, IMedium *aTarget, - BOOL fMergeForward, - IMedium *pParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent)); + STDMETHOD(FinishOnlineMergeMedium)(); STDMETHOD(RestoreSnapshot)(IConsole *aInitiator, ISnapshot *aSnapshot, MachineState_T *aMachineState, @@ -1064,17 +1085,18 @@ public: ComSafeArrayOut(LONG64, aTimestamps), ComSafeArrayOut(BSTR, aFlags)); STDMETHOD(PushGuestProperty)(IN_BSTR aName, IN_BSTR aValue, LONG64 aTimestamp, IN_BSTR aFlags); - STDMETHOD(LockMedia)() { return lockMedia(); } - STDMETHOD(UnlockMedia)() { unlockMedia(); return S_OK; } + STDMETHOD(LockMedia)(); + STDMETHOD(UnlockMedia)(); STDMETHOD(EjectMedium)(IMediumAttachment *aAttachment, IMediumAttachment **aNewAttachment); - STDMETHOD(ReportGuestStatistics)(ULONG aValidStats, ULONG aCpuUser, - ULONG aCpuKernel, ULONG aCpuIdle, - ULONG aMemTotal, ULONG aMemFree, - ULONG aMemBalloon, ULONG aMemShared, - ULONG aMemCache, ULONG aPageTotal, - ULONG aAllocVMM, ULONG aFreeVMM, - ULONG aBalloonedVMM, ULONG aSharedVMM); + STDMETHOD(ReportVmStatistics)(ULONG aValidStats, ULONG aCpuUser, + ULONG aCpuKernel, ULONG aCpuIdle, + ULONG aMemTotal, ULONG aMemFree, + ULONG aMemBalloon, ULONG aMemShared, + ULONG aMemCache, ULONG aPageTotal, + ULONG aAllocVMM, ULONG aFreeVMM, + ULONG aBalloonedVMM, ULONG aSharedVMM, + ULONG aVmNetRx, ULONG aVmNetTx); // public methods only for internal purposes @@ -1083,8 +1105,17 @@ public: return true; } +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER bool checkForDeath(); + void getTokenId(Utf8Str &strTokenId); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + IToken *getToken(); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + // getClientToken must be only used by callers who can guarantee that + // the object cannot be deleted in the mean time, i.e. have a caller/lock. + ClientToken *getClientToken(); + HRESULT onNetworkAdapterChange(INetworkAdapter *networkAdapter, BOOL changeAdapter); HRESULT onNATRedirectRuleChange(ULONG ulSlot, BOOL aNatRuleRemove, IN_BSTR aRuleName, NATProtocol_T aProto, IN_BSTR aHostIp, LONG aHostPort, IN_BSTR aGuestIp, LONG aGuestPort); @@ -1093,8 +1124,8 @@ public: HRESULT onSerialPortChange(ISerialPort *serialPort); HRESULT onParallelPortChange(IParallelPort *parallelPort); HRESULT onCPUChange(ULONG aCPU, BOOL aRemove); - HRESULT onCPUExecutionCapChange(ULONG aCpuExecutionCap); HRESULT onVRDEServerChange(BOOL aRestart); + HRESULT onVideoCaptureChange(); HRESULT onUSBControllerChange(); HRESULT onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError, @@ -1105,16 +1136,20 @@ public: HRESULT onClipboardModeChange(ClipboardMode_T aClipboardMode); HRESULT onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode); HRESULT onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup); - HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove); + HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent); + HRESULT onCPUExecutionCapChange(ULONG aCpuExecutionCap); bool hasMatchingUSBFilter(const ComObjPtr &aDevice, ULONG *aMaskedIfs); + HRESULT lockMedia(); + void unlockMedia(); + private: struct ConsoleTaskData { ConsoleTaskData() - : mLastState(MachineState_Null) + : mLastState(MachineState_Null), mDeleteSnapshotInfo(NULL) { } MachineState_T mLastState; @@ -1123,15 +1158,13 @@ private: // used when taking snapshot ComObjPtr mSnapshot; + // used when deleting online snapshot + void *mDeleteSnapshotInfo; + // used when saving state (either as part of a snapshot or separate) Utf8Str strStateFilePath; }; - struct Uninit - { - enum Reason { Unexpected, Abnormal, Normal }; - }; - struct SnapshotTask; struct DeleteSnapshotTask; struct RestoreSnapshotTask; @@ -1139,8 +1172,6 @@ private: friend struct DeleteSnapshotTask; friend struct RestoreSnapshotTask; - void uninit(Uninit::Reason aReason); - HRESULT endSavingState(HRESULT aRC, const Utf8Str &aErrMsg); void releaseSavedStateFile(const Utf8Str &strSavedStateFile, Snapshot *pSnapshotToIgnore); @@ -1156,14 +1187,16 @@ private: ComObjPtr &aTarget, bool &fMergeForward, ComObjPtr &pParentForTarget, - MediaList &aChildrenToReparent, + MediumLockList * &aChildrenToReparent, bool &fNeedOnlineMerge, - MediumLockList * &aMediumLockList); + MediumLockList * &aMediumLockList, + ComPtr &aHDLockToken); void cancelDeleteSnapshotMedium(const ComObjPtr &aHD, const ComObjPtr &aSource, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, bool fNeedsOnlineMerge, MediumLockList *aMediumLockList, + const ComPtr &aHDLockToken, const Guid &aMediumId, const Guid &aSnapshotId); HRESULT onlineMergeMedium(const ComObjPtr &aMediumAttachment, @@ -1171,14 +1204,11 @@ private: const ComObjPtr &aTarget, bool fMergeForward, const ComObjPtr &pParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList, ComObjPtr &aProgress, bool *pfNeedsMachineSaveSettings); - HRESULT lockMedia(); - void unlockMedia(); - HRESULT setMachineState(MachineState_T aMachineState); HRESULT updateMachineStateOnClient(); @@ -1186,27 +1216,10 @@ private: ConsoleTaskData mConsoleTaskData; - /** interprocess semaphore handle for this machine */ -#if defined(RT_OS_WINDOWS) - HANDLE mIPCSem; - Bstr mIPCSemName; - friend bool Machine::isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl, - HANDLE *aIPCSem, bool aAllowClosing); -#elif defined(RT_OS_OS2) - HMTX mIPCSem; - Bstr mIPCSemName; - friend bool Machine::isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl, - HMTX *aIPCSem, bool aAllowClosing); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - int mIPCSem; -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN - Bstr mIPCKey; -# endif /*VBOX_WITH_NEW_SYS_V_KEYGEN */ -#else -# error "Port me!" -#endif + /** client token for this machine */ + ClientToken *mClientToken; + + int miNATNetworksStarted; static DECLCALLBACK(int) taskHandler(RTTHREAD thread, void *pvUser); }; diff --git a/src/VBox/Main/include/Matching.h b/src/VBox/Main/include/Matching.h index 0f5bbc4f..2f01f692 100644 --- a/src/VBox/Main/include/Matching.h +++ b/src/VBox/Main/include/Matching.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/MediumAttachmentImpl.h b/src/VBox/Main/include/MediumAttachmentImpl.h index 819317f0..1f3f3d3b 100644 --- a/src/VBox/Main/include/MediumAttachmentImpl.h +++ b/src/VBox/Main/include/MediumAttachmentImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -51,6 +51,7 @@ public: bool fTempEject, bool fNonRotational, bool fDiscard, + bool fHotPluggable, const Utf8Str &strBandwidthGroup); HRESULT initCopy(Machine *aParent, MediumAttachment *aThat); void uninit(); @@ -70,6 +71,7 @@ public: STDMETHOD(COMGETTER(NonRotational))(BOOL *aNonRotational); STDMETHOD(COMGETTER(Discard))(BOOL *aDiscard); STDMETHOD(COMGETTER(BandwidthGroup))(IBandwidthGroup **aBwGroup); + STDMETHOD(COMGETTER(HotPluggable))(BOOL *aHotPluggable); // public internal methods void rollback(); @@ -90,6 +92,7 @@ public: bool getNonRotational() const; bool getDiscard() const; const Utf8Str& getBandwidthGroup() const; + bool getHotPluggable() const; bool matches(CBSTR aControllerName, LONG aPort, LONG aDevice); @@ -116,6 +119,9 @@ public: void updateParentMachine(Machine * const pMachine); + /** Must be called from under this object's write lock. */ + void updateHotPluggable(bool aHotPluggable); + /** Get a unique and somewhat descriptive name for logging. */ const char* getLogName(void) const { return mLogName.c_str(); } diff --git a/src/VBox/Main/include/MediumFormatImpl.h b/src/VBox/Main/include/MediumFormatImpl.h index feac8a71..2acdc6e8 100644 --- a/src/VBox/Main/include/MediumFormatImpl.h +++ b/src/VBox/Main/include/MediumFormatImpl.h @@ -2,11 +2,11 @@ /** @file * - * VirtualBox COM class implementation + * MediumFormat COM class implementation */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -17,14 +17,11 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -#ifndef ____H_MEDIUMFORMAT -#define ____H_MEDIUMFORMAT +#ifndef MEDIUMFORMAT_IMPL_H_ +#define MEDIUMFORMAT_IMPL_H_ -#include "VirtualBoxBase.h" +#include "MediumFormatWrap.h" -#include - -#include struct VDBACKENDINFO; @@ -38,8 +35,7 @@ struct VDBACKENDINFO; * wait! */ class ATL_NO_VTABLE MediumFormat : - public VirtualBoxBase, - VBOX_SCRIPTABLE_IMPL(IMediumFormat) + public MediumFormatWrap { public: @@ -52,31 +48,8 @@ public: Utf8Str strDefaultValue; }; - typedef std::list StrList; - typedef std::list DeviceTypeList; - typedef std::list PropertyList; - - struct Data - { - Data() : capabilities((MediumFormatCapabilities_T)0) {} - - const Utf8Str strId; - const Utf8Str strName; - const StrList llFileExtensions; - const DeviceTypeList llDeviceTypes; - const MediumFormatCapabilities_T capabilities; - const PropertyList llProperties; - }; - - VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(MediumFormat, IMediumFormat) - - DECLARE_NOT_AGGREGATABLE(MediumFormat) - - DECLARE_PROTECT_FINAL_CONSTRUCT() - - BEGIN_COM_MAP(MediumFormat) - VBOX_DEFAULT_INTERFACE_ENTRIES(IMediumFormat) - END_COM_MAP() + typedef std::vector PropertyArray; + typedef std::vector StrArray; DECLARE_EMPTY_CTOR_DTOR(MediumFormat) @@ -87,39 +60,53 @@ public: HRESULT init(const VDBACKENDINFO *aVDInfo); void uninit(); - // IMediumFormat properties - STDMETHOD(COMGETTER(Id))(BSTR *aId); - STDMETHOD(COMGETTER(Name))(BSTR *aName); - STDMETHOD(COMGETTER(Capabilities))(ULONG *aCaps); - - // IMediumFormat methods - STDMETHOD(DescribeFileExtensions)(ComSafeArrayOut(BSTR, aFileExtensions), - ComSafeArrayOut(DeviceType_T, aDeviceTypes)); - STDMETHOD(DescribeProperties)(ComSafeArrayOut(BSTR, aNames), - ComSafeArrayOut(BSTR, aDescriptions), - ComSafeArrayOut(DataType_T, aTypes), - ComSafeArrayOut(ULONG, aFlags), - ComSafeArrayOut(BSTR, aDefaults)); - - // public methods only for internal purposes - // public methods for internal purposes only // (ensure there is a caller and a read lock before calling them!) /** Const, no need to lock */ - const Utf8Str& getId() const { return m.strId; } + const Utf8Str &i_getId() const { return m.strId; } /** Const, no need to lock */ - const StrList& getFileExtensions() const { return m.llFileExtensions; } + const StrArray &i_getFileExtensions() const { return m.maFileExtensions; } /** Const, no need to lock */ - MediumFormatCapabilities_T getCapabilities() const { return m.capabilities; } + MediumFormatCapabilities_T i_getCapabilities() const { return m.capabilities; } /** Const, no need to lock */ - const PropertyList& getProperties() const { return m.llProperties; } + const PropertyArray &i_getProperties() const { return m.maProperties; } private: + // wrapped IMediumFormat properties + HRESULT getId(com::Utf8Str &aId); + HRESULT getName(com::Utf8Str &aName); + HRESULT getCapabilities(std::vector &aCapabilities); + + // wrapped IMediumFormat methods + HRESULT describeFileExtensions(std::vector &aExtensions, + std::vector &aTypes); + HRESULT describeProperties(std::vector &aNames, + std::vector &aDescriptions, + std::vector &aTypes, + std::vector &aFlags, + std::vector &aDefaults); + + // types + typedef std::vector DeviceTypeArray; + + // data + struct Data + { + Data() : capabilities((MediumFormatCapabilities_T)0) {} + + const Utf8Str strId; + const Utf8Str strName; + const StrArray maFileExtensions; + const DeviceTypeArray maDeviceTypes; + const MediumFormatCapabilities_T capabilities; + const PropertyArray maProperties; + }; + Data m; }; -#endif // ____H_MEDIUMFORMAT +#endif // MEDIUMFORMAT_IMPL_H_ /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/MediumImpl.h b/src/VBox/Main/include/MediumImpl.h index 33bff7b6..4f64d414 100644 --- a/src/VBox/Main/include/MediumImpl.h +++ b/src/VBox/Main/include/MediumImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2012 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -103,9 +103,8 @@ public: STDMETHOD(COMGETTER(Description))(BSTR *aDescription); STDMETHOD(COMSETTER(Description))(IN_BSTR aDescription); STDMETHOD(COMGETTER(State))(MediumState_T *aState); - STDMETHOD(COMGETTER(Variant))(ULONG *aVariant); + STDMETHOD(COMGETTER(Variant))(ComSafeArrayOut(MediumVariant_T, aVariant)); STDMETHOD(COMGETTER(Location))(BSTR *aLocation); - STDMETHOD(COMSETTER(Location))(IN_BSTR aLocation); STDMETHOD(COMGETTER(Name))(BSTR *aName); STDMETHOD(COMGETTER(DeviceType))(DeviceType_T *aDeviceType); STDMETHOD(COMGETTER(HostDrive))(BOOL *aHostDrive); @@ -131,10 +130,8 @@ public: STDMETHOD(RefreshState)(MediumState_T *aState); STDMETHOD(GetSnapshotIds)(IN_BSTR aMachineId, ComSafeArrayOut(BSTR, aSnapshotIds)); - STDMETHOD(LockRead)(MediumState_T *aState); - STDMETHOD(UnlockRead)(MediumState_T *aState); - STDMETHOD(LockWrite)(MediumState_T *aState); - STDMETHOD(UnlockWrite)(MediumState_T *aState); + STDMETHOD(LockRead)(IToken **aToken); + STDMETHOD(LockWrite)(IToken **aToken); STDMETHOD(Close)(); STDMETHOD(GetProperty)(IN_BSTR aName, BSTR *aValue); STDMETHOD(SetProperty)(IN_BSTR aName, IN_BSTR aValue); @@ -144,17 +141,18 @@ public: STDMETHOD(SetProperties)(ComSafeArrayIn(IN_BSTR, aNames), ComSafeArrayIn(IN_BSTR, aValues)); STDMETHOD(CreateBaseStorage)(LONG64 aLogicalSize, - ULONG aVariant, + ComSafeArrayIn(MediumVariant_T, aVariant), IProgress **aProgress); STDMETHOD(DeleteStorage)(IProgress **aProgress); STDMETHOD(CreateDiffStorage)(IMedium *aTarget, - ULONG aVariant, + ComSafeArrayIn(MediumVariant_T, aVariant), IProgress **aProgress); STDMETHOD(MergeTo)(IMedium *aTarget, IProgress **aProgress); - STDMETHOD(CloneTo)(IMedium *aTarget, ULONG aVariant, + STDMETHOD(CloneTo)(IMedium *aTarget, ComSafeArrayIn(MediumVariant_T, aVariant), IMedium *aParent, IProgress **aProgress); - STDMETHOD(CloneToBase)(IMedium *aTarget, ULONG aVariant, + STDMETHOD(CloneToBase)(IMedium *aTarget, ComSafeArrayIn(MediumVariant_T, aVariant), IProgress **aProgress); + STDMETHOD(SetLocation)(IN_BSTR aLocation, IProgress **aProgress); STDMETHOD(Compact)(IProgress **aProgress); STDMETHOD(Resize)(LONG64 aLogicalSize, IProgress **aProgress); STDMETHOD(Reset)(IProgress **aProgress); @@ -225,31 +223,36 @@ public: Utf8Str getPreferredDiffFormat(); HRESULT close(AutoCaller &autoCaller); + HRESULT unlockRead(MediumState_T *aState); + HRESULT unlockWrite(MediumState_T *aState); HRESULT deleteStorage(ComObjPtr *aProgress, bool aWait); HRESULT markForDeletion(); HRESULT unmarkForDeletion(); HRESULT markLockedForDeletion(); HRESULT unmarkLockedForDeletion(); + HRESULT queryPreferredMergeDirection(const ComObjPtr &pOther, + bool &fMergeForward); + HRESULT prepareMergeTo(const ComObjPtr &pTarget, const Guid *aMachineId, const Guid *aSnapshotId, bool fLockMedia, bool &fMergeForward, ComObjPtr &pParentForTarget, - MediaList &aChildrenToReparent, + MediumLockList * &aChildrenToReparent, MediumLockList * &aMediumLockList); HRESULT mergeTo(const ComObjPtr &pTarget, bool fMergeForward, const ComObjPtr &pParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList, ComObjPtr *aProgress, bool aWait); - void cancelMergeTo(const MediaList &aChildrenToReparent, + void cancelMergeTo(MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList); - HRESULT fixParentUuidOfChildren(const MediaList &childrenToReparent); + HRESULT fixParentUuidOfChildren(MediumLockList *pChildrenToReparent); HRESULT exportFile(const char *aFilename, const ComObjPtr &aFormat, diff --git a/src/VBox/Main/include/MediumLock.h b/src/VBox/Main/include/MediumLock.h index eaa12f8b..a65ebd03 100644 --- a/src/VBox/Main/include/MediumLock.h +++ b/src/VBox/Main/include/MediumLock.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -88,12 +88,19 @@ public: */ bool GetLockRequest() const; + /** + * Check if this medium object has been locked by this MediumLock. + */ + bool IsLocked() const; + /** * Acquire a medium lock. * * @return COM status code + * @param aIgnoreLockedMedia If set ignore all media which is already + * locked in an incompatible way. */ - HRESULT Lock(); + HRESULT Lock(bool aIgnoreLockedMedia = false); /** * Release a medium lock. @@ -104,6 +111,7 @@ public: private: ComObjPtr mMedium; + ComPtr mToken; AutoCaller mMediumCaller; bool mLockWrite; bool mIsLocked; @@ -207,8 +215,14 @@ public: * Acquire all medium locks "atomically", i.e. all or nothing. * * @return COM status code + * @param aSkipOverLockedMedia If set ignore all media which is already + * locked for reading or writing. For callers + * which need to know which medium objects + * have been locked by this lock list you + * can iterate over the list and check the + * MediumLock state. */ - HRESULT Lock(); + HRESULT Lock(bool aSkipOverLockedMedia = false); /** * Release all medium locks. diff --git a/src/VBox/Main/include/MouseImpl.h b/src/VBox/Main/include/MouseImpl.h index 4bbb6a18..404c7594 100644 --- a/src/VBox/Main/include/MouseImpl.h +++ b/src/VBox/Main/include/MouseImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,9 +21,7 @@ #include "VirtualBoxBase.h" #include "ConsoleEvents.h" #include "ConsoleImpl.h" -#ifndef VBOXBFE_WITHOUT_COM #include "EventImpl.h" -#endif #include /** Maximum number of devices supported */ @@ -33,9 +31,7 @@ typedef struct DRVMAINMOUSE DRVMAINMOUSE, *PDRVMAINMOUSE; class ATL_NO_VTABLE Mouse : public VirtualBoxBase -#ifndef VBOXBFE_WITHOUT_COM , VBOX_SCRIPTABLE_IMPL(IMouse) -#endif { public: @@ -55,12 +51,13 @@ public: void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init(Console *parent); + HRESULT init(ConsoleMouseInterface *parent); void uninit(); // IMouse properties STDMETHOD(COMGETTER(AbsoluteSupported)) (BOOL *absoluteSupported); STDMETHOD(COMGETTER(RelativeSupported)) (BOOL *relativeSupported); + STDMETHOD(COMGETTER(MultiTouchSupported)) (BOOL *multiTouchSupported); STDMETHOD(COMGETTER(NeedsHostCursor)) (BOOL *needsHostCursor); // IMouse methods @@ -68,13 +65,13 @@ public: LONG buttonState); STDMETHOD(PutMouseEventAbsolute)(LONG x, LONG y, LONG dz, LONG dw, LONG buttonState); -#ifndef VBOXBFE_WITHOUT_COM + STDMETHOD(PutEventMultiTouch)(LONG aCount, ComSafeArrayIn(LONG64, aContacts), ULONG aScanTime); + STDMETHOD(PutEventMultiTouchString)(LONG aCount, IN_BSTR aContacts, ULONG aScanTime); STDMETHOD(COMGETTER(EventSource)) (IEventSource ** aEventSource); -#endif static const PDMDRVREG DrvReg; - Console *getParent() const + ConsoleMouseInterface *getParent() const { return mParent; } @@ -89,68 +86,53 @@ public: private: static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); - static DECLCALLBACK(void) mouseReportModes (PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs); + static DECLCALLBACK(void) mouseReportModes (PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs, bool fMT); static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns); HRESULT updateVMMDevMouseCaps(uint32_t fCapsAdded, uint32_t fCapsRemoved); HRESULT reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz, int32_t dw, uint32_t fButtons); - HRESULT reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs, - int32_t dz, int32_t dw, uint32_t fButtons); - HRESULT reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs); - HRESULT reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs, - int32_t dz, int32_t dw, uint32_t fButtons, - bool fUsesVMMDevEvent); - HRESULT convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY, + HRESULT reportAbsEventToMouseDev(int32_t x, int32_t y, int32_t dz, + int32_t dw, uint32_t fButtons); + HRESULT reportMTEventToMouseDev(int32_t x, int32_t z, uint32_t cContact, + uint32_t fContact); + HRESULT reportMultiTouchEventToDevice(uint8_t cContacts, const uint64_t *pau64Contacts, uint32_t u32ScanTime); + HRESULT reportAbsEventToVMMDev(int32_t x, int32_t y); + HRESULT reportAbsEvent(int32_t x, int32_t y, int32_t dz, int32_t dw, + uint32_t fButtons, bool fUsesVMMDevEvent); + HRESULT convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj, bool *pfValid); + HRESULT putEventMultiTouch(LONG aCount, LONG64 *paContacts, ULONG aScanTime); - void getDeviceCaps(bool *pfAbs, bool *pfRel); + void getDeviceCaps(bool *pfAbs, bool *pfRel, bool *fMT); void sendMouseCapsNotifications(void); bool guestNeedsHostCursor(void); bool vmmdevCanAbs(void); bool deviceCanAbs(void); bool supportsAbs(void); bool supportsRel(void); + bool supportsMT(void); -#ifdef VBOXBFE_WITHOUT_COM - Console *mParent; -#else - Console * const mParent; -#endif + ConsoleMouseInterface * const mParent; /** Pointer to the associated mouse driver. */ struct DRVMAINMOUSE *mpDrv[MOUSE_MAX_DEVICES]; uint32_t mfVMMDevGuestCaps; /** We cache this to avoid access races */ - int32_t mcLastAbsX; - int32_t mcLastAbsY; + int32_t mcLastX; + int32_t mcLastY; uint32_t mfLastButtons; -#ifndef VBOXBFE_WITHOUT_COM const ComObjPtr mEventSource; VBoxEventDesc mMouseEvent; - void fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LONG Buttons); -#else - void fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LONG Buttons) - {} -#endif -}; - -#ifdef VBOXBFE_WITHOUT_COM -/** @todo make this a member of Console */ -extern Mouse *gMouse; + void fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, + LONG fButtons); -/** @todo can we get these from the API somehow? */ -enum -{ - MouseButtonState_LeftButton = 1, - MouseButtonState_RightButton = 2, - MouseButtonState_MiddleButton = 4, - MouseButtonState_XButton1 = 8, - MouseButtonState_XButton2 = 16 + void fireMultiTouchEvent(uint8_t cContacts, + const LONG64 *paContacts, + uint32_t u32ScanTime); }; -#endif #endif // !____H_MOUSEIMPL /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/NATNetworkImpl.h b/src/VBox/Main/include/NATNetworkImpl.h new file mode 100644 index 00000000..1ce0769c --- /dev/null +++ b/src/VBox/Main/include/NATNetworkImpl.h @@ -0,0 +1,147 @@ +/* $Id: NATNetworkImpl.h $ */ +/** @file + * INATNetwork implementation header, lives in VBoxSVC. + */ + +/* + * Copyright (C) 2006-2011 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_H_NATNETWORKIMPL +#define ____H_H_NATNETWORKIMPL + +#include "VirtualBoxBase.h" + +#ifdef VBOX_WITH_HOSTNETIF_API +struct NETIFINFO; +#endif + +namespace settings +{ + struct NATNetwork; + struct NATRule; +} + +#ifdef RT_OS_WINDOWS +# define NATSR_EXECUTABLE_NAME "VBoxNetNAT.exe" +#else +# define NATSR_EXECUTABLE_NAME "VBoxNetNAT" +#endif + +enum ADDRESSLOOKUPTYPE +{ + ADDR_GATEWAY, + ADDR_DHCP, + ADDR_DHCPLOWERIP, + ADDR_ANY +}; + +class NATNetworkServiceRunner: public NetworkServiceRunner +{ +public: + NATNetworkServiceRunner(): NetworkServiceRunner(NATSR_EXECUTABLE_NAME){} + ~NATNetworkServiceRunner(){} +}; + +class ATL_NO_VTABLE NATNetwork : + public VirtualBoxBase, + VBOX_SCRIPTABLE_IMPL(INATNetwork) +{ +public: + + VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(NATNetwork, INATNetwork) + + DECLARE_NOT_AGGREGATABLE (NATNetwork) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP (NATNetwork) + VBOX_DEFAULT_INTERFACE_ENTRIES(INATNetwork) + END_COM_MAP() + + DECLARE_EMPTY_CTOR_DTOR (NATNetwork) + + HRESULT FinalConstruct(); + void FinalRelease(); + + HRESULT init(VirtualBox *aVirtualBox, + IN_BSTR aName); + + + HRESULT init(VirtualBox *aVirtualBox, + const settings::NATNetwork &data); + HRESULT saveSettings(settings::NATNetwork &data); + void uninit(); + // INATNetwork::EventSource + STDMETHOD(COMGETTER(EventSource))(IEventSource **IEventSource); + // INATNetwork properties + STDMETHOD(COMGETTER(Enabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(Enabled))(BOOL aEnabled); + + STDMETHOD(COMGETTER(NetworkName))(BSTR *aName); + STDMETHOD(COMSETTER(NetworkName))(IN_BSTR aName); + + STDMETHOD(COMGETTER(Gateway))(BSTR *aIPGateway); + + STDMETHOD(COMGETTER(Network))(BSTR *aIPNetwork); + STDMETHOD(COMSETTER(Network))(IN_BSTR aIPNetwork); + + STDMETHOD(COMGETTER(IPv6Enabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(IPv6Enabled))(BOOL aEnabled); + + STDMETHOD(COMGETTER(IPv6Prefix))(BSTR *aName); + STDMETHOD(COMSETTER(IPv6Prefix))(IN_BSTR aName); + + STDMETHOD(COMGETTER(AdvertiseDefaultIPv6RouteEnabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(AdvertiseDefaultIPv6RouteEnabled))(BOOL aEnabled); + + STDMETHOD(COMGETTER(NeedDhcpServer))(BOOL *aEnabled); + STDMETHOD(COMSETTER(NeedDhcpServer))(BOOL aEnabled); + + STDMETHOD(COMGETTER(LocalMappings))(ComSafeArrayOut(BSTR, aLocalMappings)); + STDMETHOD(AddLocalMapping)(IN_BSTR aHostId, LONG aOffset); + + STDMETHOD(COMGETTER(LoopbackIp6))(LONG *aLoopbackIp6); + STDMETHOD(COMSETTER(LoopbackIp6))(LONG aLoopbackIp6); + + STDMETHOD(COMGETTER(PortForwardRules4))(ComSafeArrayOut(BSTR, aPortForwardRules4)); + STDMETHOD(COMGETTER(PortForwardRules6))(ComSafeArrayOut(BSTR, aPortForwardRules6)); + + STDMETHOD(AddPortForwardRule)(BOOL aIsIpv6, + IN_BSTR aPortForwardRuleName, + NATProtocol_T aProto, + IN_BSTR aHostIp, + USHORT aHostPort, + IN_BSTR aGuestIp, + USHORT aGuestPort); + STDMETHOD(RemovePortForwardRule)(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName); + + STDMETHOD(Start)(IN_BSTR aTrunkType); + STDMETHOD(Stop)(); + +private: + int recalculateIpv4AddressAssignments(); + int findFirstAvailableOffset(ADDRESSLOOKUPTYPE, uint32_t *); + + typedef std::map NATRuleMap; + typedef NATRuleMap::const_iterator constNATRuleMapIterator; + + void GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules); + /** weak VirtualBox parent */ + VirtualBox * const mVirtualBox; + + const Bstr mName; + struct Data; + struct Data *m; + +}; + +#endif // !____H_H_NATNETWORKIMPL diff --git a/src/VBox/Main/include/NATNetworkServiceRunner.h b/src/VBox/Main/include/NATNetworkServiceRunner.h new file mode 100644 index 00000000..0c39bb0d --- /dev/null +++ b/src/VBox/Main/include/NATNetworkServiceRunner.h @@ -0,0 +1,70 @@ +/* $Id: NATNetworkServiceRunner.h $ */ +/** @file + * VirtualBox Main - interface for VBox NAT Network service + */ + +/* + * Copyright (C) 2009-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#include +#include +#include +#include +#include + +typedef enum +{ + NATSCCFG_NAME = 1, + NATSCCFG_TRUNKTYPE, + NATSCCFG_MACADDRESS, + NATSCCFG_IPADDRESS, + NATSCCFG_NETMASK, + NATSCCFG_PORTFORWARD4, + NATSCCFG_PORTFORWARD6, + NATSCCFG_NOTOPT_MAXVAL +}NATSCCFG; + +#define TRUNKTYPE_WHATEVER "whatever" +#define TRUNKTYPE_SRVNAT "srvnat" + +class NATNetworkServiceRunner +{ +public: + NATNetworkServiceRunner(); + ~NATNetworkServiceRunner() { stop(); /* don't leave abandoned networks */} + + int setOption(NATSCCFG opt, const char *val, bool enabled) + { + if (opt == 0 || opt >= NATSCCFG_NOTOPT_MAXVAL) + return VERR_INVALID_PARAMETER; + if (isRunning()) + return VERR_INVALID_STATE; + + mOptions[opt] = val; + mOptionEnabled[opt] = enabled; + return VINF_SUCCESS; + } + + int setOption(NATSCCFG opt, const com::Utf8Str &val, bool enabled) + { + return setOption(opt, val.c_str(), enabled); + } + + int start(); + int stop(); + bool isRunning(); + + void detachFromServer(); +private: + com::Utf8Str mOptions[NATSCCFG_NOTOPT_MAXVAL]; + bool mOptionEnabled[NATSCCFG_NOTOPT_MAXVAL]; + RTPROCESS mProcess; +}; diff --git a/src/VBox/Main/include/NetworkAdapterImpl.h b/src/VBox/Main/include/NetworkAdapterImpl.h index 32601549..a99a9573 100644 --- a/src/VBox/Main/include/NetworkAdapterImpl.h +++ b/src/VBox/Main/include/NetworkAdapterImpl.h @@ -154,6 +154,8 @@ private: void generateMACAddress(); HRESULT updateMacAddress(Utf8Str aMacAddress); void updateBandwidthGroup(BandwidthGroup *aBwGroup); + HRESULT checkAndSwitchFromNatNetworking(IN_BSTR aNatNetworkName); + HRESULT switchToNatNetworking(IN_BSTR aNatNetworkName); Machine * const mParent; const ComObjPtr mPeer; diff --git a/src/VBox/Main/include/NetworkServiceRunner.h b/src/VBox/Main/include/NetworkServiceRunner.h new file mode 100644 index 00000000..f0ec275d --- /dev/null +++ b/src/VBox/Main/include/NetworkServiceRunner.h @@ -0,0 +1,57 @@ +/* $Id: NetworkServiceRunner.h $ */ +/** @file + * VirtualBox Main - interface for VBox DHCP server. + */ + +/* + * Copyright (C) 2009-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include +#include +#include + +#include + +#define TRUNKTYPE_WHATEVER "whatever" +#define TRUNKTYPE_NETFLT "netflt" +#define TRUNKTYPE_NETADP "netadp" +#define TRUNKTYPE_SRVNAT "srvnat" + +class NetworkServiceRunner +{ +public: + NetworkServiceRunner(const char *aProcName); + virtual ~NetworkServiceRunner(); + + int setOption(const std::string& key, const std::string& val); + + int start(); + int stop(); + bool isRunning(); + + void detachFromServer(); + + static const std::string kNsrKeyName; + static const std::string kNsrKeyNetwork; + static const std::string kNsrKeyTrunkType; + static const std::string kNsrTrunkName; + static const std::string kNsrMacAddress; + static const std::string kNsrIpAddress; + static const std::string kNsrIpNetmask; + static const std::string kNsrKeyNeedMain; + +private: + struct Data; + Data *m; +}; diff --git a/src/VBox/Main/include/Nvram.h b/src/VBox/Main/include/Nvram.h index 4f95e71d..0a444b7b 100644 --- a/src/VBox/Main/include/Nvram.h +++ b/src/VBox/Main/include/Nvram.h @@ -30,16 +30,21 @@ class Nvram public: Nvram(Console *console); virtual ~Nvram(); - static const PDMDRVREG DrvReg; + Console *getParent(void) { return mParent; } - struct NVRAM *mpDrv; + + static const PDMDRVREG DrvReg; private: static DECLCALLBACK(void *) drvNvram_QueryInterface(PPDMIBASE pInterface, const char *pszIID); static DECLCALLBACK(int) drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); static DECLCALLBACK(void) drvNvram_Destruct(PPDMDRVINS pDrvIns); + /** Pointer to the parent object. */ Console * const mParent; + /** Pointer to the driver instance data. + * Can be NULL during init and termination. */ + struct NVRAM *mpDrv; }; #endif /* !____H_NVRAM */ diff --git a/src/VBox/Main/include/PCIDeviceAttachmentImpl.h b/src/VBox/Main/include/PCIDeviceAttachmentImpl.h index e162be1f..8120be5d 100644 --- a/src/VBox/Main/include/PCIDeviceAttachmentImpl.h +++ b/src/VBox/Main/include/PCIDeviceAttachmentImpl.h @@ -23,68 +23,6 @@ #include "VirtualBoxBase.h" #include -class ATL_NO_VTABLE PCIAddress : - public VirtualBoxBase, - VBOX_SCRIPTABLE_IMPL(IPCIAddress) -{ -public: - VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(PCIAddress, IPCIAddress) - - DECLARE_NOT_AGGREGATABLE(PCIAddress) - - DECLARE_PROTECT_FINAL_CONSTRUCT() - - BEGIN_COM_MAP(PCIAddress) - VBOX_DEFAULT_INTERFACE_ENTRIES(IPCIAddress) - END_COM_MAP() - - PCIAddress() { } - ~PCIAddress() { } - - // public initializer/uninitializer for internal purposes only - HRESULT init(LONG aAddess); - void uninit(); - - HRESULT FinalConstruct(); - void FinalRelease(); - - // IPCIAddress properties - STDMETHOD(COMGETTER(Bus))(SHORT *aBus) - { - *aBus = mBus; - return S_OK; - } - STDMETHOD(COMSETTER(Bus))(SHORT aBus) - { - mBus = aBus; - return S_OK; - } - STDMETHOD(COMGETTER(Device))(SHORT *aDevice) - { - *aDevice = mDevice; - return S_OK; - } - STDMETHOD(COMSETTER(Device))(SHORT aDevice) - { - mDevice = aDevice; - return S_OK; - } - - STDMETHOD(COMGETTER(DevFunction))(SHORT *aDevFunction) - { - *aDevFunction = mFn; - return S_OK; - } - STDMETHOD(COMSETTER(DevFunction))(SHORT aDevFunction) - { - mFn = aDevFunction; - return S_OK; - } - -private: - SHORT mBus, mDevice, mFn; -}; - class ATL_NO_VTABLE PCIDeviceAttachment : public VirtualBoxBase, VBOX_SCRIPTABLE_IMPL(IPCIDeviceAttachment) diff --git a/src/VBox/Main/include/Performance.h b/src/VBox/Main/include/Performance.h index d3905237..c1e8ed25 100644 --- a/src/VBox/Main/include/Performance.h +++ b/src/VBox/Main/include/Performance.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,6 +32,8 @@ #include #include +#include "MediumImpl.h" + /* Forward decl. */ class Machine; @@ -153,33 +155,39 @@ namespace pm */ typedef enum { - GUESTSTATMASK_NONE = 0x00000000, - GUESTSTATMASK_CPUUSER = 0x00000001, - GUESTSTATMASK_CPUKERNEL = 0x00000002, - GUESTSTATMASK_CPUIDLE = 0x00000004, - GUESTSTATMASK_MEMTOTAL = 0x00000008, - GUESTSTATMASK_MEMFREE = 0x00000010, - GUESTSTATMASK_MEMBALLOON = 0x00000020, - GUESTSTATMASK_MEMSHARED = 0x00000040, - GUESTSTATMASK_MEMCACHE = 0x00000080, - GUESTSTATMASK_PAGETOTAL = 0x00000100, - GUESTSTATMASK_ALLOCVMM = 0x00000200, - GUESTSTATMASK_FREEVMM = 0x00000400, - GUESTSTATMASK_BALOONVMM = 0x00000800, - GUESTSTATMASK_SHAREDVMM = 0x00001000 - } GUESTSTATMASK; - - const ULONG GUESTSTATS_CPULOAD = - GUESTSTATMASK_CPUUSER|GUESTSTATMASK_CPUKERNEL|GUESTSTATMASK_CPUIDLE; - const ULONG GUESTSTATS_RAMUSAGE = - GUESTSTATMASK_MEMTOTAL|GUESTSTATMASK_MEMFREE|GUESTSTATMASK_MEMBALLOON| - GUESTSTATMASK_MEMSHARED|GUESTSTATMASK_MEMCACHE| - GUESTSTATMASK_PAGETOTAL; - const ULONG GUESTSTATS_VMMRAM = - GUESTSTATMASK_ALLOCVMM|GUESTSTATMASK_FREEVMM| - GUESTSTATMASK_BALOONVMM|GUESTSTATMASK_SHAREDVMM; - const ULONG GUESTSTATS_ALL = GUESTSTATS_CPULOAD|GUESTSTATS_RAMUSAGE|GUESTSTATS_VMMRAM; - + VMSTATMASK_NONE = 0x00000000, + VMSTATMASK_GUEST_CPUUSER = 0x00000001, + VMSTATMASK_GUEST_CPUKERNEL = 0x00000002, + VMSTATMASK_GUEST_CPUIDLE = 0x00000004, + VMSTATMASK_GUEST_MEMTOTAL = 0x00000008, + VMSTATMASK_GUEST_MEMFREE = 0x00000010, + VMSTATMASK_GUEST_MEMBALLOON = 0x00000020, + VMSTATMASK_GUEST_MEMSHARED = 0x00000040, + VMSTATMASK_GUEST_MEMCACHE = 0x00000080, + VMSTATMASK_GUEST_PAGETOTAL = 0x00000100, + VMSTATMASK_VMM_ALLOC = 0x00010000, + VMSTATMASK_VMM_FREE = 0x00020000, + VMSTATMASK_VMM_BALOON = 0x00040000, + VMSTATMASK_VMM_SHARED = 0x00080000, + VMSTATMASK_NET_RX = 0x01000000, + VMSTATMASK_NET_TX = 0x02000000 + } VMSTATMASK; + + const ULONG VMSTATS_GUEST_CPULOAD = + VMSTATMASK_GUEST_CPUUSER | VMSTATMASK_GUEST_CPUKERNEL | + VMSTATMASK_GUEST_CPUIDLE; + const ULONG VMSTATS_GUEST_RAMUSAGE = + VMSTATMASK_GUEST_MEMTOTAL | VMSTATMASK_GUEST_MEMFREE | + VMSTATMASK_GUEST_MEMBALLOON | VMSTATMASK_GUEST_MEMSHARED | + VMSTATMASK_GUEST_MEMCACHE | VMSTATMASK_GUEST_PAGETOTAL; + const ULONG VMSTATS_VMM_RAM = + VMSTATMASK_VMM_ALLOC | VMSTATMASK_VMM_FREE| + VMSTATMASK_VMM_BALOON | VMSTATMASK_VMM_SHARED; + const ULONG VMSTATS_NET_RATE = + VMSTATMASK_NET_RX | VMSTATMASK_NET_TX; + const ULONG VMSTATS_ALL = + VMSTATS_GUEST_CPULOAD | VMSTATS_GUEST_RAMUSAGE | + VMSTATS_VMM_RAM | VMSTATS_NET_RATE; class CollectorGuest; class CollectorGuestRequest @@ -190,7 +198,7 @@ namespace pm virtual ~CollectorGuestRequest() {}; void setGuest(CollectorGuest *aGuest) { mCGuest = aGuest; }; CollectorGuest *getGuest() { return mCGuest; }; - virtual int execute() = 0; + virtual HRESULT execute() = 0; virtual void debugPrint(void *aObject, const char *aFunction, const char *aText) = 0; protected: @@ -203,7 +211,7 @@ namespace pm public: CGRQEnable(ULONG aMask) : mMask(aMask) {}; - int execute(); + HRESULT execute(); void debugPrint(void *aObject, const char *aFunction, const char *aText); private: @@ -215,7 +223,7 @@ namespace pm public: CGRQDisable(ULONG aMask) : mMask(aMask) {}; - int execute(); + HRESULT execute(); void debugPrint(void *aObject, const char *aFunction, const char *aText); private: @@ -226,7 +234,7 @@ namespace pm { public: CGRQAbort() {}; - int execute(); + HRESULT execute(); void debugPrint(void *aObject, const char *aFunction, const char *aText); }; @@ -265,12 +273,13 @@ namespace pm ULONG aMemBalloon, ULONG aMemShared, ULONG aMemCache, ULONG aPageTotal, ULONG aAllocVMM, ULONG aFreeVMM, - ULONG aBalloonedVMM, ULONG aSharedVMM); + ULONG aBalloonedVMM, ULONG aSharedVMM, + ULONG aVmNetRx, ULONG aVmNetTx); int enable(ULONG mask); int disable(ULONG mask); int enqueueRequest(CollectorGuestRequest *aRequest); - int enableInternal(ULONG mask); + HRESULT enableInternal(ULONG mask); int disableInternal(ULONG mask); const com::Utf8Str& getVMName() const { return mMachineName; }; @@ -289,6 +298,8 @@ namespace pm ULONG getFreeVMM() { return mFreeVMM; }; ULONG getBalloonedVMM() { return mBalloonedVMM; }; ULONG getSharedVMM() { return mSharedVMM; }; + ULONG getVmNetRx() { return mVmNetRx; }; + ULONG getVmNetTx() { return mVmNetTx; }; private: int enableVMMStats(bool mCollectVMMStats); @@ -316,6 +327,8 @@ namespace pm ULONG mFreeVMM; ULONG mBalloonedVMM; ULONG mSharedVMM; + ULONG mVmNetRx; + ULONG mVmNetTx; }; typedef std::list CollectorGuestList; @@ -343,6 +356,8 @@ namespace pm }; /* Collector Hardware Abstraction Layer *********************************/ + typedef std::list DiskList; + class CollectorHAL { public: @@ -357,6 +372,8 @@ namespace pm virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available); /** Returns file system counters in megabytes. */ virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available); + /** Returns disk size in bytes. */ + virtual int getHostDiskSize(const char *name, uint64_t *size); /** Returns CPU usage in 1/1000th per cent by a particular process. */ virtual int getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel); /** Returns the amount of memory used by a process in kilobytes. */ @@ -370,13 +387,13 @@ namespace pm virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms); /** Returns process' CPU usage counter in platform-specific units. */ virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); + + /** Returns the lists of disks (aggregate and physical) used by the specified file system. */ + virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad); }; extern CollectorHAL *createHAL(); - typedef std::list DiskList; - extern int getDiskListByFs(const char *name, DiskList& list); - /* Base Metrics *********************************************************/ class BaseMetric { @@ -455,6 +472,7 @@ namespace pm HostCpuLoadRaw(CollectorHAL *hal, ComPtr object, SubMetric *user, SubMetric *kernel, SubMetric *idle) : HostCpuLoad(hal, object, user, kernel, idle), mUserPrev(0), mKernelPrev(0), mIdlePrev(0) {}; + void init(ULONG period, ULONG length); void preCollect(CollectorHints& hints, uint64_t iTick); void collect(); private: @@ -501,6 +519,27 @@ namespace pm SubMetric *mAvailable; }; + class HostNetworkSpeed : public BaseMetric + { + public: + HostNetworkSpeed(CollectorHAL *hal, ComPtr object, com::Utf8Str name, com::Utf8Str shortname, com::Utf8Str /* ifname */, uint32_t speed, SubMetric *linkspeed) + : BaseMetric(hal, name, object), mShortName(shortname), mSpeed(speed), mLinkSpeed(linkspeed) {}; + ~HostNetworkSpeed() { delete mLinkSpeed; }; + + void init(ULONG period, ULONG length); + + void preCollect(CollectorHints& /* hints */, uint64_t /* iTick */) {}; + void collect() { if (mSpeed) mLinkSpeed->put(mSpeed); }; + const char *getUnit() { return "mbit/s"; }; + ULONG getMinValue() { return 0; }; + ULONG getMaxValue() { return INT32_MAX; }; + ULONG getScale() { return 1; } + private: + com::Utf8Str mShortName; + uint32_t mSpeed; + SubMetric *mLinkSpeed; + }; + class HostNetworkLoadRaw : public BaseMetric { public: @@ -549,6 +588,25 @@ namespace pm SubMetric *mAvailable; }; + class HostDiskUsage : public BaseMetric + { + public: + HostDiskUsage(CollectorHAL *hal, ComPtr object, com::Utf8Str name, com::Utf8Str diskname, SubMetric *total) + : BaseMetric(hal, name, object), mDiskName(diskname), mTotal(total) {}; + ~HostDiskUsage() { delete mTotal; }; + + void init(ULONG period, ULONG length); + void preCollect(CollectorHints& hints, uint64_t iTick); + void collect(); + const char *getUnit() { return "mB"; }; + ULONG getMinValue() { return 0; }; + ULONG getMaxValue() { return INT32_MAX; }; + ULONG getScale() { return 1; } + private: + com::Utf8Str mDiskName; + SubMetric *mTotal; + }; + class HostDiskLoadRaw : public BaseMetric { public: @@ -660,6 +718,52 @@ namespace pm #ifndef VBOX_COLLECTOR_TEST_CASE + typedef std::list > MediaList; + class MachineDiskUsage : public BaseMetric + { + public: + MachineDiskUsage(CollectorHAL *hal, ComPtr object, MediaList &disks, SubMetric *used) + : BaseMetric(hal, "Disk/Usage", object), mDisks(disks), mUsed(used) {}; + ~MachineDiskUsage() { delete mUsed; }; + + void init(ULONG period, ULONG length); + void preCollect(CollectorHints& hints, uint64_t iTick); + void collect(); + const char *getUnit() { return "mB"; }; + ULONG getMinValue() { return 0; }; + ULONG getMaxValue() { return INT32_MAX; }; + ULONG getScale() { return 1; } + private: + MediaList mDisks; + SubMetric *mUsed; + }; + + /* + * Although MachineNetRate is measured for VM, not for the guest, it is + * derived from BaseGuestMetric since it uses the same mechanism for + * data collection -- values get pushed by Guest class along with other + * guest statistics. + */ + class MachineNetRate : public BaseGuestMetric + { + public: + MachineNetRate(CollectorGuest *cguest, ComPtr object, SubMetric *rx, SubMetric *tx) + : BaseGuestMetric(cguest, "Net/Rate", object), mRx(rx), mTx(tx) {}; + ~MachineNetRate() { delete mRx; delete mTx; }; + + void init(ULONG period, ULONG length); + void preCollect(CollectorHints& hints, uint64_t iTick); + void collect(); + int enable(); + int disable(); + const char *getUnit() { return "B/s"; }; + ULONG getMinValue() { return 0; }; + ULONG getMaxValue() { return INT32_MAX; }; + ULONG getScale() { return 1; } + private: + SubMetric *mRx, *mTx; + }; + class GuestCpuLoad : public BaseGuestMetric { public: diff --git a/src/VBox/Main/include/PerformanceImpl.h b/src/VBox/Main/include/PerformanceImpl.h index 26e83b4d..4ffbe77a 100644 --- a/src/VBox/Main/include/PerformanceImpl.h +++ b/src/VBox/Main/include/PerformanceImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/ProgressCombinedImpl.h b/src/VBox/Main/include/ProgressCombinedImpl.h deleted file mode 100644 index c6454d6e..00000000 --- a/src/VBox/Main/include/ProgressCombinedImpl.h +++ /dev/null @@ -1,192 +0,0 @@ -/* $Id: ProgressCombinedImpl.h $ */ -/** @file - * - * VirtualBox COM class implementation - */ - -/* - * Copyright (C) 2006-2010 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -#ifndef ____H_PROGRESSCOMBINEDIMPL -#define ____H_PROGRESSCOMBINEDIMPL - -#include "ProgressImpl.h" -#include "AutoCaller.h" - -#include - -/** - * The CombinedProgress class allows to combine several progress objects to a - * single progress component. This single progress component will treat all - * operations of individual progress objects as a single sequence of operations - * that follow each other in the same order as progress objects are passed to - * the #init() method. - * - * @note CombinedProgress is legacy code and deprecated. It does not support - * weighted operations, all suboperations are assumed to take the same - * amount of time. For new code, please use IProgress directly which - * has supported multiple weighted suboperations since VirtualBox 3.0. - * - * Individual progress objects are sequentially combined so that this progress - * object: - * - * - is cancelable only if all progresses are cancelable. - * - is canceled once a progress that follows next to successfully completed - * ones reports it was canceled. - * - is completed successfully only after all progresses are completed - * successfully. - * - is completed unsuccessfully once a progress that follows next to - * successfully completed ones reports it was completed unsuccessfully; - * the result code and error info of the unsuccessful progress - * will be reported as the result code and error info of this progress. - * - returns N as the operation number, where N equals to the number of - * operations in all successfully completed progresses starting from the - * first one plus the operation number of the next (not yet complete) - * progress; the operation description of the latter one is reported as - * the operation description of this progress object. - * - returns P as the percent value, where P equals to the sum of percents - * of all successfully completed progresses starting from the - * first one plus the percent value of the next (not yet complete) - * progress, normalized to 100%. - * - * @note It's the responsibility of the combined progress object creator to - * complete individual progresses in the right order: if, let's say, the - * last progress is completed before all previous ones, - * #WaitForCompletion(-1) will most likely give 100% CPU load because it - * will be in a loop calling a method that returns immediately. - */ -class ATL_NO_VTABLE CombinedProgress : - public Progress -{ - -public: - VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(CombinedProgress, IProgress) - - DECLARE_NOT_AGGREGATABLE(CombinedProgress) - - DECLARE_PROTECT_FINAL_CONSTRUCT() - - BEGIN_COM_MAP (CombinedProgress) - VBOX_DEFAULT_INTERFACE_ENTRIES (IProgress) - END_COM_MAP() - - HRESULT FinalConstruct(); - void FinalRelease(); - - // public initializer/uninitializer for internal purposes only - - HRESULT init ( -#if !defined (VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - IProgress *aProgress1, IProgress *aProgress2, - OUT_GUID aId = NULL); - - /** - * Initializes the combined progress object given the first and the last - * normal progress object from the list. - * - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). - * @param aFirstProgress Iterator of the first normal progress object. - * @param aSecondProgress Iterator of the last normal progress object. - * @param aId See ProgressBase::init(). - */ - template - HRESULT init ( -#if !defined (VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - InputIterator aFirstProgress, InputIterator aLastProgress, - OUT_GUID aId = NULL) - { - /* Enclose the state transition NotReady->InInit->Ready */ - AutoInitSpan autoInitSpan (this); - AssertReturn (autoInitSpan.isOk(), E_FAIL); - - mProgresses = ProgressVector (aFirstProgress, aLastProgress); - - HRESULT rc = protectedInit (autoInitSpan, -#if !defined (VBOX_COM_INPROC) - aParent, -#endif - aInitiator, aDescription, aId); - - /* Confirm a successful initialization when it's the case */ - if (SUCCEEDED(rc)) - autoInitSpan.setSucceeded(); - - return rc; - } - -protected: - - HRESULT protectedInit (AutoInitSpan &aAutoInitSpan, -#if !defined (VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, OUT_GUID aId); - -public: - - void uninit(); - - // IProgress properties - STDMETHOD(COMGETTER(Percent)) (ULONG *aPercent); - STDMETHOD(COMGETTER(Completed)) (BOOL *aCompleted); - STDMETHOD(COMGETTER(Canceled)) (BOOL *aCanceled); - STDMETHOD(COMGETTER(ResultCode)) (LONG *aResultCode); - STDMETHOD(COMGETTER(ErrorInfo)) (IVirtualBoxErrorInfo **aErrorInfo); - STDMETHOD(COMGETTER(Operation)) (ULONG *aCount); - STDMETHOD(COMGETTER(OperationDescription)) (BSTR *aOperationDescription); - STDMETHOD(COMGETTER(OperationPercent)) (ULONG *aOperationPercent); - STDMETHOD(COMSETTER(Timeout)) (ULONG aTimeout); - STDMETHOD(COMGETTER(Timeout)) (ULONG *aTimeout); - - // IProgress methods - STDMETHOD(WaitForCompletion) (LONG aTimeout); - STDMETHOD(WaitForOperationCompletion) (ULONG aOperation, LONG aTimeout); - STDMETHOD(Cancel)(); - - STDMETHOD(SetCurrentOperationProgress)(ULONG aPercent) - { - NOREF(aPercent); - return E_NOTIMPL; - } - - STDMETHOD(SetNextOperation)(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight) - { - NOREF(bstrNextOperationDescription); NOREF(ulNextOperationsWeight); - return E_NOTIMPL; - } - - // public methods only for internal purposes - -private: - - HRESULT checkProgress(); - - typedef std::vector > ProgressVector; - ProgressVector mProgresses; - - size_t mProgress; - ULONG mCompletedOperations; -}; - -#endif /* ____H_PROGRESSCOMBINEDIMPL */ - diff --git a/src/VBox/Main/include/ProgressImpl.h b/src/VBox/Main/include/ProgressImpl.h index a04d4b06..6b012742 100644 --- a/src/VBox/Main/include/ProgressImpl.h +++ b/src/VBox/Main/include/ProgressImpl.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,68 +26,17 @@ //////////////////////////////////////////////////////////////////////////////// /** - * Base component class for progress objects. + * Class for progress objects. */ -class ATL_NO_VTABLE ProgressBase : +class ATL_NO_VTABLE Progress : public VirtualBoxBase, VBOX_SCRIPTABLE_IMPL(IProgress) { protected: -// VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ProgressBase, IProgress) -// cannot be added here or Windows will not buuld; as a result, ProgressBase cannot be -// instantiated, but we're not doing that anyway (but only its children) - - DECLARE_EMPTY_CTOR_DTOR (ProgressBase) - - HRESULT FinalConstruct(); - - // protected initializer/uninitializer for internal purposes only - HRESULT protectedInit(AutoInitSpan &aAutoInitSpan, -#if !defined (VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, OUT_GUID aId = NULL); - HRESULT protectedInit(AutoInitSpan &aAutoInitSpan); - void protectedUninit(AutoUninitSpan &aAutoUninitSpan); - -public: - - // IProgress properties - STDMETHOD(COMGETTER(Id)) (BSTR *aId); - STDMETHOD(COMGETTER(Description)) (BSTR *aDescription); - STDMETHOD(COMGETTER(Initiator)) (IUnknown **aInitiator); + DECLARE_EMPTY_CTOR_DTOR (Progress) - // IProgress properties - STDMETHOD(COMGETTER(Cancelable)) (BOOL *aCancelable); - STDMETHOD(COMGETTER(Percent)) (ULONG *aPercent); - STDMETHOD(COMGETTER(TimeRemaining)) (LONG *aTimeRemaining); - STDMETHOD(COMGETTER(Completed)) (BOOL *aCompleted); - STDMETHOD(COMGETTER(Canceled)) (BOOL *aCanceled); - STDMETHOD(COMGETTER(ResultCode)) (LONG *aResultCode); - STDMETHOD(COMGETTER(ErrorInfo)) (IVirtualBoxErrorInfo **aErrorInfo); - STDMETHOD(COMGETTER(OperationCount)) (ULONG *aOperationCount); - STDMETHOD(COMGETTER(Operation)) (ULONG *aOperation); - STDMETHOD(COMGETTER(OperationDescription)) (BSTR *aOperationDescription); - STDMETHOD(COMGETTER(OperationPercent)) (ULONG *aOperationPercent); - STDMETHOD(COMGETTER(OperationWeight)) (ULONG *aOperationWeight); - STDMETHOD(COMSETTER(Timeout)) (ULONG aTimeout); - STDMETHOD(COMGETTER(Timeout)) (ULONG *aTimeout); - - // public methods only for internal purposes - - bool setCancelCallback(void (*pfnCallback)(void *), void *pvUser); - - - // unsafe inline public methods for internal purposes only (ensure there is - // a caller and a read lock before calling them!) - - BOOL getCompleted() const { return mCompleted; } - HRESULT getResultCode() const { return mResultCode; } - double calcTotalPercent(); -protected: void checkForAutomaticTimeout(void); #if !defined (VBOX_COM_INPROC) @@ -123,16 +72,6 @@ protected: ULONG m_ulCurrentOperationWeight; // weight of current operation, given to setNextOperation() ULONG m_ulOperationPercent; // percentage of current operation, set with setCurrentOperationProgress() ULONG m_cMsTimeout; /**< Automatic timeout value. 0 means none. */ -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Normal progress object. - */ -class ATL_NO_VTABLE Progress : - public ProgressBase -{ public: VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(Progress, IProgress) @@ -236,7 +175,17 @@ public: ULONG aOperationCount, CBSTR aOperationDescription); +// initializer/uninitializer for internal purposes only + HRESULT init(AutoInitSpan &aAutoInitSpan, +#if !defined (VBOX_COM_INPROC) + VirtualBox *aParent, +#endif + IUnknown *aInitiator, + CBSTR aDescription, OUT_GUID aId = NULL); + HRESULT init(AutoInitSpan &aAutoInitSpan); + void init(AutoUninitSpan &aAutoUninitSpan); void uninit(); + void uninit(AutoUninitSpan &aAutoUninitSpan); // IProgress methods STDMETHOD(WaitForCompletion)(LONG aTimeout); @@ -264,6 +213,38 @@ public: va_list va); bool notifyPointOfNoReturn(void); + // IProgress properties + STDMETHOD(COMGETTER(Id)) (BSTR *aId); + STDMETHOD(COMGETTER(Description)) (BSTR *aDescription); + STDMETHOD(COMGETTER(Initiator)) (IUnknown **aInitiator); + + // IProgress properties + STDMETHOD(COMGETTER(Cancelable)) (BOOL *aCancelable); + STDMETHOD(COMGETTER(Percent)) (ULONG *aPercent); + STDMETHOD(COMGETTER(TimeRemaining)) (LONG *aTimeRemaining); + STDMETHOD(COMGETTER(Completed)) (BOOL *aCompleted); + STDMETHOD(COMGETTER(Canceled)) (BOOL *aCanceled); + STDMETHOD(COMGETTER(ResultCode)) (LONG *aResultCode); + STDMETHOD(COMGETTER(ErrorInfo)) (IVirtualBoxErrorInfo **aErrorInfo); + STDMETHOD(COMGETTER(OperationCount)) (ULONG *aOperationCount); + STDMETHOD(COMGETTER(Operation)) (ULONG *aOperation); + STDMETHOD(COMGETTER(OperationDescription)) (BSTR *aOperationDescription); + STDMETHOD(COMGETTER(OperationPercent)) (ULONG *aOperationPercent); + STDMETHOD(COMGETTER(OperationWeight)) (ULONG *aOperationWeight); + STDMETHOD(COMSETTER(Timeout)) (ULONG aTimeout); + STDMETHOD(COMGETTER(Timeout)) (ULONG *aTimeout); + + // public methods only for internal purposes + + bool setCancelCallback(void (*pfnCallback)(void *), void *pvUser); + + + // unsafe inline public methods for internal purposes only (ensure there is + // a caller and a read lock before calling them!) + BOOL getCompleted() const { return mCompleted; } + HRESULT getResultCode() const { return mResultCode; } + double calcTotalPercent(); + private: RTSEMEVENTMULTI mCompletedSem; diff --git a/src/VBox/Main/include/ProgressProxyImpl.h b/src/VBox/Main/include/ProgressProxyImpl.h index 87ebd708..66f2b31c 100644 --- a/src/VBox/Main/include/ProgressProxyImpl.h +++ b/src/VBox/Main/include/ProgressProxyImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/RemoteUSBBackend.h b/src/VBox/Main/include/RemoteUSBBackend.h index dd6685c9..baf47a48 100644 --- a/src/VBox/Main/include/RemoteUSBBackend.h +++ b/src/VBox/Main/include/RemoteUSBBackend.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/RemoteUSBDeviceImpl.h b/src/VBox/Main/include/RemoteUSBDeviceImpl.h index 2285ee93..e92552e6 100644 --- a/src/VBox/Main/include/RemoteUSBDeviceImpl.h +++ b/src/VBox/Main/include/RemoteUSBDeviceImpl.h @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/SessionImpl.h b/src/VBox/Main/include/SessionImpl.h index dd93411a..f6a3db13 100644 --- a/src/VBox/Main/include/SessionImpl.h +++ b/src/VBox/Main/include/SessionImpl.h @@ -1,10 +1,9 @@ /** @file - * * VBox Client Session COM Class definition */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -25,14 +24,6 @@ # include "win/resource.h" #endif -/** @def VBOX_WITH_SYS_V_IPC_SESSION_WATCHER - * Use SYS V IPC for watching a session. - * This is defined in the Makefile since it's also used by MachineImpl.h/cpp. - */ -#ifdef DOXYGEN_RUNNING -# define VBOX_WITH_SYS_V_IPC_SESSION_WATCHER -#endif - #ifdef RT_OS_WINDOWS [threading(free)] #endif @@ -80,7 +71,11 @@ public: // IInternalSessionControl methods STDMETHOD(GetPID)(ULONG *aPid); STDMETHOD(GetRemoteConsole)(IConsole **aConsole); - STDMETHOD(AssignMachine)(IMachine *aMachine, LockType_T aLockType); +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + STDMETHOD(AssignMachine)(IMachine *aMachine, LockType_T aLockType, IN_BSTR aTokenId); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + STDMETHOD(AssignMachine)(IMachine *aMachine, LockType_T aLockType, IToken *aToken); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ STDMETHOD(AssignRemoteMachine)(IMachine *aMachine, IConsole *aConsole); STDMETHOD(UpdateMachineState)(MachineState_T aMachineState); STDMETHOD(Uninitialize)(); @@ -92,6 +87,7 @@ public: STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove); STDMETHOD(OnCPUExecutionCapChange)(ULONG aExecutionCap); STDMETHOD(OnVRDEServerChange)(BOOL aRestart); + STDMETHOD(OnVideoCaptureChange)(); STDMETHOD(OnUSBControllerChange)(); STDMETHOD(OnSharedFolderChange)(BOOL aGlobal); STDMETHOD(OnClipboardModeChange)(ClipboardMode_T aClipboardMode); @@ -100,7 +96,7 @@ public: STDMETHOD(OnUSBDeviceDetach)(IN_BSTR aId, IVirtualBoxErrorInfo *aError); STDMETHOD(OnShowWindow)(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId); STDMETHOD(OnBandwidthGroupChange)(IBandwidthGroup *aBandwidthGroup); - STDMETHOD(OnStorageDeviceChange)(IMediumAttachment *aMediumAttachment, BOOL aRemove); + STDMETHOD(OnStorageDeviceChange)(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent); STDMETHOD(AccessGuestProperty)(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags, BOOL aIsSetter, BSTR *aRetValue, LONG64 *aRetTimestamp, BSTR *aRetFlags); STDMETHOD(EnumerateGuestProperties)(IN_BSTR aPatterns, @@ -110,43 +106,34 @@ public: ComSafeArrayOut(BSTR, aFlags)); STDMETHOD(OnlineMergeMedium)(IMediumAttachment *aMediumAttachment, ULONG aSourceIdx, ULONG aTargetIdx, - IMedium *aSource, IMedium *aTarget, - BOOL aMergeForward, IMedium *aParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent), IProgress *aProgress); STDMETHOD(EnableVMMStatistics)(BOOL aEnable); + STDMETHOD(PauseWithReason)(Reason_T aReason); + STDMETHOD(ResumeWithReason)(Reason_T aReason); + STDMETHOD(SaveStateWithReason)(Reason_T aReason, IProgress **aProgress); private: HRESULT unlockMachine(bool aFinalRelease, bool aFromServer); - HRESULT grabIPCSemaphore(); - void releaseIPCSemaphore(); SessionState_T mState; SessionType_T mType; ComPtr mControl; +#ifndef VBOX_COM_INPROC_API_CLIENT ComObjPtr mConsole; +#endif ComPtr mRemoteMachine; ComPtr mRemoteConsole; ComPtr mVirtualBox; - /* interprocess semaphore handle (id) for the opened machine */ -#if defined(RT_OS_WINDOWS) - HANDLE mIPCSem; - HANDLE mIPCThreadSem; -#elif defined(RT_OS_OS2) - RTTHREAD mIPCThread; - RTSEMEVENT mIPCThreadSem; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - int mIPCSem; -#else -# error "Port me!" -#endif + class ClientTokenHolder; + + ClientTokenHolder *mClientTokenHolder; }; -#endif // ____H_SESSIONIMPL +#endif // !____H_SESSIONIMPL /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/SharedFolderImpl.h b/src/VBox/Main/include/SharedFolderImpl.h index a4ee94ac..d14a7b58 100644 --- a/src/VBox/Main/include/SharedFolderImpl.h +++ b/src/VBox/Main/include/SharedFolderImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -99,9 +99,12 @@ private: VirtualBoxBase * const mParent; /* weak parents (only one of them is not null) */ +#if !defined(VBOX_COM_INPROC) Machine * const mMachine; - Console * const mConsole; VirtualBox * const mVirtualBox; +#else + Console * const mConsole; +#endif struct Data; // opaque data struct, defined in SharedFolderImpl.cpp Data *m; diff --git a/src/VBox/Main/include/SnapshotImpl.h b/src/VBox/Main/include/SnapshotImpl.h index 1e94e5ea..e86bbbcd 100644 --- a/src/VBox/Main/include/SnapshotImpl.h +++ b/src/VBox/Main/include/SnapshotImpl.h @@ -100,6 +100,8 @@ public: const Utf8Str& getStateFilePath() const; + uint32_t getDepth(); + ULONG getChildrenCount(); ULONG getAllChildrenCount(); ULONG getAllChildrenCountImpl(); diff --git a/src/VBox/Main/include/StorageControllerImpl.h b/src/VBox/Main/include/StorageControllerImpl.h index 98e8d473..1292804a 100644 --- a/src/VBox/Main/include/StorageControllerImpl.h +++ b/src/VBox/Main/include/StorageControllerImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/SystemPropertiesImpl.h b/src/VBox/Main/include/SystemPropertiesImpl.h index e910b982..3f77949a 100644 --- a/src/VBox/Main/include/SystemPropertiesImpl.h +++ b/src/VBox/Main/include/SystemPropertiesImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -69,6 +69,10 @@ public: STDMETHOD(COMGETTER(SerialPortCount))(ULONG *count); STDMETHOD(COMGETTER(ParallelPortCount))(ULONG *count); STDMETHOD(COMGETTER(MaxBootPosition))(ULONG *aMaxBootPosition); + STDMETHOD(COMGETTER(ExclusiveHwVirt))(BOOL *aExclusiveHwVirt); + STDMETHOD(COMSETTER(ExclusiveHwVirt))(BOOL aExclusiveHwVirt); + STDMETHOD(COMGETTER(LoggingLevel))(BSTR *aLoggingLevel); + STDMETHOD(COMSETTER(LoggingLevel))(IN_BSTR aLoggingLevel); STDMETHOD(COMGETTER(DefaultMachineFolder))(BSTR *aDefaultMachineFolder); STDMETHOD(COMSETTER(DefaultMachineFolder))(IN_BSTR aDefaultMachineFolder); STDMETHOD(COMGETTER(MediumFormats))(ComSafeArrayOut(IMediumFormat *, aMediumFormats)); @@ -95,6 +99,8 @@ public: STDMETHOD(COMSETTER(AutostartDatabasePath))(IN_BSTR aAutostartDbPath); STDMETHOD(COMGETTER(DefaultAdditionsISO))(BSTR *aDefaultAdditionsISO); STDMETHOD(COMSETTER(DefaultAdditionsISO))(IN_BSTR aDefaultAdditionsISO); + STDMETHOD(COMGETTER(DefaultFrontend))(BSTR *aDefaultFrontend); + STDMETHOD(COMSETTER(DefaultFrontend))(IN_BSTR aDefaultFrontend); STDMETHOD(GetMaxNetworkAdapters)(ChipsetType_T aChipset, ULONG *aMaxInstances); STDMETHOD(GetMaxNetworkAdaptersOfType)(ChipsetType_T aChipset, NetworkAttachmentType_T aType, ULONG *aMaxInstances); @@ -104,6 +110,7 @@ public: STDMETHOD(GetMaxInstancesOfStorageBus)(ChipsetType_T aChipset, StorageBus_T aBus, ULONG *aMaxInstances); STDMETHOD(GetDeviceTypesForStorageBus)(StorageBus_T aBus, ComSafeArrayOut(DeviceType_T, aDeviceTypes)); STDMETHOD(GetDefaultIoCacheSettingForStorageController)(StorageControllerType_T aControllerType, BOOL *aEnabled); + STDMETHOD(GetMaxInstancesOfUSBControllerType)(ChipsetType_T aChipset, USBControllerType_T aType, ULONG *aMaxInstances); // public methods only for internal purposes @@ -122,6 +129,7 @@ private: HRESULT getUserHomeDirectory(Utf8Str &strPath); HRESULT setDefaultMachineFolder(const Utf8Str &aPath); + HRESULT setLoggingLevel(const Utf8Str &aLoggingLevel); HRESULT setDefaultHardDiskFormat(const Utf8Str &aFormat); HRESULT setVRDEAuthLibrary(const Utf8Str &aPath); @@ -129,6 +137,7 @@ private: HRESULT setDefaultVRDEExtPack(const Utf8Str &aPath); HRESULT setAutostartDatabasePath(const Utf8Str &aPath); HRESULT setDefaultAdditionsISO(const Utf8Str &aPath); + HRESULT setDefaultFrontend(const Utf8Str &aPath); VirtualBox * const mParent; diff --git a/src/VBox/Main/include/TokenImpl.h b/src/VBox/Main/include/TokenImpl.h new file mode 100644 index 00000000..1bb49639 --- /dev/null +++ b/src/VBox/Main/include/TokenImpl.h @@ -0,0 +1,107 @@ +/* $Id: TokenImpl.h $ */ + +/** @file + * + * Token COM class implementations: MachineToken and MediumLockToken + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef TOKEN_IMPL_H_ +#define TOKEN_IMPL_H_ + +#include "TokenWrap.h" +#include "MachineImpl.h" + + +/** + * The MachineToken class automates cleanup of a SessionMachine object. + */ +class ATL_NO_VTABLE MachineToken : + public TokenWrap +{ +public: + + DECLARE_EMPTY_CTOR_DTOR(MachineToken) + + HRESULT FinalConstruct(); + void FinalRelease(); + + // public initializer/uninitializer for internal purposes only + HRESULT init(const ComObjPtr &pSessionMachine); + void uninit(bool fAbandon); + +private: + + // wrapped IToken methods + HRESULT abandon(AutoCaller &aAutoCaller); + HRESULT dummy(); + + // data + struct Data + { + Data() + { + } + + ComObjPtr pSessionMachine; + }; + + Data m; +}; + + +class Medium; + +/** + * The MediumLockToken class automates cleanup of a Medium lock. + */ +class ATL_NO_VTABLE MediumLockToken : + public TokenWrap +{ +public: + + DECLARE_EMPTY_CTOR_DTOR(MediumLockToken) + + HRESULT FinalConstruct(); + void FinalRelease(); + + // public initializer/uninitializer for internal purposes only + HRESULT init(const ComObjPtr &pMedium, bool fWrite); + void uninit(); + +private: + + // wrapped IToken methods + HRESULT abandon(AutoCaller &aAutoCaller); + HRESULT dummy(); + + // data + struct Data + { + Data() : + fWrite(false) + { + } + + ComObjPtr pMedium; + bool fWrite; + }; + + Data m; +}; + + +#endif // TOKEN_IMPL_H_ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/USBControllerImpl.h b/src/VBox/Main/include/USBControllerImpl.h index 63ba58f2..814f4b53 100644 --- a/src/VBox/Main/include/USBControllerImpl.h +++ b/src/VBox/Main/include/USBControllerImpl.h @@ -51,47 +51,27 @@ public: void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init(Machine *aParent); - HRESULT init(Machine *aParent, USBController *aThat); + HRESULT init(Machine *aParent, const Utf8Str &aName, USBControllerType_T enmType); + HRESULT init(Machine *aParent, USBController *aThat, bool fReshare = false); HRESULT initCopy(Machine *aParent, USBController *aThat); void uninit(); // IUSBController properties - STDMETHOD(COMGETTER(Enabled))(BOOL *aEnabled); - STDMETHOD(COMSETTER(Enabled))(BOOL aEnabled); - STDMETHOD(COMGETTER(EnabledEHCI))(BOOL *aEnabled); - STDMETHOD(COMSETTER(EnabledEHCI))(BOOL aEnabled); - STDMETHOD(COMGETTER(ProxyAvailable))(BOOL *aEnabled); + STDMETHOD(COMGETTER(Name))(BSTR *aName); + STDMETHOD(COMGETTER(Type))(USBControllerType_T *enmType); STDMETHOD(COMGETTER(USBStandard))(USHORT *aUSBStandard); - STDMETHOD(COMGETTER(DeviceFilters))(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters)); - - // IUSBController methods - STDMETHOD(CreateDeviceFilter)(IN_BSTR aName, IUSBDeviceFilter **aFilter); - STDMETHOD(InsertDeviceFilter)(ULONG aPosition, IUSBDeviceFilter *aFilter); - STDMETHOD(RemoveDeviceFilter)(ULONG aPosition, IUSBDeviceFilter **aFilter); // public methods only for internal purposes - HRESULT loadSettings(const settings::USBController &data); - HRESULT saveSettings(settings::USBController &data); - void rollback(); void commit(); void copyFrom(USBController *aThat); + void unshare(); -#ifdef VBOX_WITH_USB - HRESULT onDeviceFilterChange(USBDeviceFilter *aFilter, - BOOL aActiveChanged = FALSE); - - bool hasMatchingFilter(const ComObjPtr &aDevice, ULONG *aMaskedIfs); - bool hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs); - - HRESULT notifyProxy(bool aInsertFilters); -#endif /* VBOX_WITH_USB */ + const Utf8Str &getName() const; + USBControllerType_T getControllerType() const; - // public methods for internal purposes only - // (ensure there is a caller and a read lock before calling them!) - Machine* getMachine(); + ComObjPtr getPeer(); private: diff --git a/src/VBox/Main/include/USBDeviceFilterImpl.h b/src/VBox/Main/include/USBDeviceFilterImpl.h index 562d7693..aaa8ced7 100644 --- a/src/VBox/Main/include/USBDeviceFilterImpl.h +++ b/src/VBox/Main/include/USBDeviceFilterImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,7 +23,7 @@ #include "Matching.h" #include -class USBController; +class USBDeviceFilters; class Host; namespace settings { @@ -82,12 +82,12 @@ public: void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init(USBController *aParent, + HRESULT init(USBDeviceFilters *aParent, const settings::USBDeviceFilter &data); - HRESULT init(USBController *aParent, IN_BSTR aName); - HRESULT init(USBController *aParent, USBDeviceFilter *aThat, + HRESULT init(USBDeviceFilters *aParent, IN_BSTR aName); + HRESULT init(USBDeviceFilters *aParent, USBDeviceFilter *aThat, bool aReshare = false); - HRESULT initCopy(USBController *aParent, USBDeviceFilter *aThat); + HRESULT initCopy(USBDeviceFilters *aParent, USBDeviceFilter *aThat); void uninit(); // IUSBDeviceFilter properties @@ -142,8 +142,8 @@ private: HRESULT usbFilterFieldSetter(USBFILTERIDX aIdx, IN_BSTR aStr); HRESULT usbFilterFieldSetter(USBFILTERIDX aIdx, const Utf8Str &strNew); - USBController * const mParent; - USBDeviceFilter * const mPeer; + USBDeviceFilters * const mParent; + USBDeviceFilter * const mPeer; Backupable mData; @@ -153,7 +153,7 @@ private: (not touched by the class itself except that in init()/uninit()) */ bool mInList; - friend class USBController; + friend class USBDeviceFilters; }; // HostUSBDeviceFilter diff --git a/src/VBox/Main/include/USBDeviceFiltersImpl.h b/src/VBox/Main/include/USBDeviceFiltersImpl.h new file mode 100644 index 00000000..190430f5 --- /dev/null +++ b/src/VBox/Main/include/USBDeviceFiltersImpl.h @@ -0,0 +1,99 @@ +/* $Id: USBDeviceFiltersImpl.h $ */ + +/** @file + * + * VBox USBDeviceFilters COM Class declaration. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_USBDEVICEFILTERSIMPL +#define ____H_USBDEVICEFILTERSIMPL + +#include "VirtualBoxBase.h" + +class HostUSBDevice; +class USBDeviceFilter; + +namespace settings +{ + struct USB; +} + +class ATL_NO_VTABLE USBDeviceFilters : + public VirtualBoxBase, + VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilters) +{ +public: + VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(USBDeviceFilters, IUSBDeviceFilters) + + DECLARE_NOT_AGGREGATABLE(USBDeviceFilters) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(USBDeviceFilters) + VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilters) + END_COM_MAP() + + DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilters) + + HRESULT FinalConstruct(); + void FinalRelease(); + + // public initializer/uninitializer for internal purposes only + HRESULT init(Machine *aParent); + HRESULT init(Machine *aParent, USBDeviceFilters *aThat); + HRESULT initCopy(Machine *aParent, USBDeviceFilters *aThat); + void uninit(); + + // IUSBDeviceFilters attributes + STDMETHOD(COMGETTER(DeviceFilters))(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters)); + + // IUSBDeviceFilters methods + STDMETHOD(CreateDeviceFilter)(IN_BSTR aName, IUSBDeviceFilter **aFilter); + STDMETHOD(InsertDeviceFilter)(ULONG aPosition, IUSBDeviceFilter *aFilter); + STDMETHOD(RemoveDeviceFilter)(ULONG aPosition, IUSBDeviceFilter **aFilter); + + // public methods only for internal purposes + + HRESULT loadSettings(const settings::USB &data); + HRESULT saveSettings(settings::USB &data); + + void rollback(); + void commit(); + void copyFrom(USBDeviceFilters *aThat); + +#ifdef VBOX_WITH_USB + HRESULT onDeviceFilterChange(USBDeviceFilter *aFilter, + BOOL aActiveChanged = FALSE); + + bool hasMatchingFilter(const ComObjPtr &aDevice, ULONG *aMaskedIfs); + bool hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs); + + HRESULT notifyProxy(bool aInsertFilters); +#endif /* VBOX_WITH_USB */ + + // public methods for internal purposes only + // (ensure there is a caller and a read lock before calling them!) + Machine* getMachine(); + +private: + + void printList(); + + struct Data; + Data *m; +}; + +#endif //!____H_USBDEVICEFILTERSIMPL +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/USBDeviceImpl.h b/src/VBox/Main/include/USBDeviceImpl.h index 162fb6e8..2ea81ef6 100644 --- a/src/VBox/Main/include/USBDeviceImpl.h +++ b/src/VBox/Main/include/USBDeviceImpl.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/USBGetDevices.h b/src/VBox/Main/include/USBGetDevices.h index fd0b29ff..2b0e35f6 100644 --- a/src/VBox/Main/include/USBGetDevices.h +++ b/src/VBox/Main/include/USBGetDevices.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/UsbWebcamInterface.h b/src/VBox/Main/include/UsbWebcamInterface.h new file mode 100644 index 00000000..2604c731 --- /dev/null +++ b/src/VBox/Main/include/UsbWebcamInterface.h @@ -0,0 +1,66 @@ +/* $Id: UsbWebcamInterface.h $ */ +/** @file + * VirtualBox PDM Driver for Emulated USB Webcam + */ + +/* + * Copyright (C) 2011-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_USBWEBCAMINTERFACE +#define ____H_USBWEBCAMINTERFACE + +#include +#define VRDE_VIDEOIN_WITH_VRDEINTERFACE /* Get the VRDE interface definitions. */ +#include + +class ConsoleVRDPServer; +typedef struct EMWEBCAMDRV EMWEBCAMDRV; +typedef struct EMWEBCAMREMOTE EMWEBCAMREMOTE; + +class EmWebcam +{ + public: + EmWebcam(ConsoleVRDPServer *pServer); + virtual ~EmWebcam(); + + static const PDMDRVREG DrvReg; + + void EmWebcamConstruct(EMWEBCAMDRV *pDrv); + void EmWebcamDestruct(EMWEBCAMDRV *pDrv); + + /* Callbacks. */ + void EmWebcamCbNotify(uint32_t u32Id, const void *pvData, uint32_t cbData); + void EmWebcamCbDeviceDesc(int rcRequest, void *pDeviceCtx, void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, uint32_t cbDeviceDesc); + void EmWebcamCbControl(int rcRequest, void *pDeviceCtx, void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl); + void EmWebcamCbFrame(int rcRequest, void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, uint32_t cbFrame); + + /* Methods for the PDM driver. */ + int SendControl(EMWEBCAMDRV *pDrv, void *pvUser, uint64_t u64DeviceId, + const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl); + + private: + static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); + static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); + static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns); + + ConsoleVRDPServer * const mParent; + + EMWEBCAMDRV *mpDrv; + EMWEBCAMREMOTE *mpRemote; + uint64_t volatile mu64DeviceIdSrc; +}; + +#endif /* !____H_USBWEBCAMINTERFACE */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/VFSExplorerImpl.h b/src/VBox/Main/include/VFSExplorerImpl.h index 95871432..e87e1d96 100644 --- a/src/VBox/Main/include/VFSExplorerImpl.h +++ b/src/VBox/Main/include/VFSExplorerImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -55,7 +55,7 @@ class ATL_NO_VTABLE VFSExplorer : STDMETHOD(Cd)(IN_BSTR aDir, IProgress **aProgress); STDMETHOD(CdUp)(IProgress **aProgress); - STDMETHOD(EntryList)(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(ULONG, aSizes), ComSafeArrayOut(ULONG, aModes)); + STDMETHOD(EntryList)(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(LONG64, aSizes), ComSafeArrayOut(ULONG, aModes)); STDMETHOD(Exists)(ComSafeArrayIn(IN_BSTR, aNames), ComSafeArrayOut(BSTR, aExists)); diff --git a/src/VBox/Main/include/VMMDev.h b/src/VBox/Main/include/VMMDev.h index 3258bdfe..3fe366ad 100644 --- a/src/VBox/Main/include/VMMDev.h +++ b/src/VBox/Main/include/VMMDev.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,7 +23,13 @@ class Console; -class VMMDev +class VMMDevMouseInterface +{ +public: + virtual PPDMIVMMDEVPORT getVMMDevPort() = 0; +}; + +class VMMDev : public VMMDevMouseInterface { public: VMMDev(Console *console); @@ -48,6 +54,7 @@ public: PPDMIVMMDEVPORT getVMMDevPort(); +#ifdef VBOX_WITH_HGCM int hgcmLoadService (const char *pszServiceLibrary, const char *pszServiceName); int hgcmHostCall (const char *pszServiceName, uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms); #ifdef VBOX_WITH_CRHGSMI @@ -58,6 +65,7 @@ public: void hgcmShutdown (void); bool hgcmIsActive (void) { return ASMAtomicReadBool(&m_fHGCMActive); } +#endif /* VBOX_WITH_HGCM */ private: static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID); diff --git a/src/VBox/Main/include/VRDEServerImpl.h b/src/VBox/Main/include/VRDEServerImpl.h index 84ceaa52..dbef40e2 100644 --- a/src/VBox/Main/include/VRDEServerImpl.h +++ b/src/VBox/Main/include/VRDEServerImpl.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -53,7 +53,7 @@ public: VBOX_DEFAULT_INTERFACE_ENTRIES(IVRDEServer) END_COM_MAP() - DECLARE_EMPTY_CTOR_DTOR (VRDEServer) + DECLARE_EMPTY_CTOR_DTOR(VRDEServer) HRESULT FinalConstruct(); void FinalRelease(); @@ -61,29 +61,29 @@ public: // public initializer/uninitializer for internal purposes only HRESULT init(Machine *aParent); HRESULT init(Machine *aParent, VRDEServer *aThat); - HRESULT initCopy (Machine *aParent, VRDEServer *aThat); + HRESULT initCopy(Machine *aParent, VRDEServer *aThat); void uninit(); // IVRDEServer properties - STDMETHOD(COMGETTER(Enabled)) (BOOL *aEnabled); - STDMETHOD(COMSETTER(Enabled)) (BOOL aEnable); - STDMETHOD(COMGETTER(AuthType)) (AuthType_T *aType); - STDMETHOD(COMSETTER(AuthType)) (AuthType_T aType); - STDMETHOD(COMGETTER(AuthTimeout)) (ULONG *aTimeout); - STDMETHOD(COMSETTER(AuthTimeout)) (ULONG aTimeout); - STDMETHOD(COMGETTER(AllowMultiConnection)) (BOOL *aAllowMultiConnection); - STDMETHOD(COMSETTER(AllowMultiConnection)) (BOOL aAllowMultiConnection); - STDMETHOD(COMGETTER(ReuseSingleConnection)) (BOOL *aReuseSingleConnection); - STDMETHOD(COMSETTER(ReuseSingleConnection)) (BOOL aReuseSingleConnection); + STDMETHOD(COMGETTER(Enabled))(BOOL *aEnabled); + STDMETHOD(COMSETTER(Enabled))(BOOL aEnable); + STDMETHOD(COMGETTER(AuthType))(AuthType_T *aType); + STDMETHOD(COMSETTER(AuthType))(AuthType_T aType); + STDMETHOD(COMGETTER(AuthTimeout))(ULONG *aTimeout); + STDMETHOD(COMSETTER(AuthTimeout))(ULONG aTimeout); + STDMETHOD(COMGETTER(AllowMultiConnection))(BOOL *aAllowMultiConnection); + STDMETHOD(COMSETTER(AllowMultiConnection))(BOOL aAllowMultiConnection); + STDMETHOD(COMGETTER(ReuseSingleConnection))(BOOL *aReuseSingleConnection); + STDMETHOD(COMSETTER(ReuseSingleConnection))(BOOL aReuseSingleConnection); STDMETHOD(COMGETTER(VRDEExtPack))(BSTR *aExtPack); STDMETHOD(COMSETTER(VRDEExtPack))(IN_BSTR aExtPack); - STDMETHOD(COMGETTER(AuthLibrary)) (BSTR *aValue); - STDMETHOD(COMSETTER(AuthLibrary)) (IN_BSTR aValue); - STDMETHOD(COMGETTER(VRDEProperties)) (ComSafeArrayOut (BSTR, aProperties)); + STDMETHOD(COMGETTER(AuthLibrary))(BSTR *aValue); + STDMETHOD(COMSETTER(AuthLibrary))(IN_BSTR aValue); + STDMETHOD(COMGETTER(VRDEProperties))(ComSafeArrayOut(BSTR, aProperties)); // IVRDEServer methods - STDMETHOD(SetVRDEProperty) (IN_BSTR aKey, IN_BSTR aValue); - STDMETHOD(GetVRDEProperty) (IN_BSTR aKey, BSTR *aValue); + STDMETHOD(SetVRDEProperty)(IN_BSTR aKey, IN_BSTR aValue); + STDMETHOD(GetVRDEProperty)(IN_BSTR aKey, BSTR *aValue); // public methods only for internal purposes @@ -92,7 +92,7 @@ public: void rollback(); void commit(); - void copyFrom (VRDEServer *aThat); + void copyFrom(VRDEServer *aThat); private: diff --git a/src/VBox/Main/include/VirtualBoxBase.h b/src/VBox/Main/include/VirtualBoxBase.h index bde071c0..6e7ea715 100644 --- a/src/VBox/Main/include/VirtualBoxBase.h +++ b/src/VBox/Main/include/VirtualBoxBase.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -211,6 +211,25 @@ public: } while (0) #endif +/** + * Special version of the AssertMsgFailed macro to be used within VirtualBoxBase + * subclasses. + * + * See ComAssert for more info. + * + * @param a printf argument list (in parenthesis). + */ +#if defined(DEBUG) +#define ComAssertMsgFailed(a) AssertMsgFailed(a) +#else +#define ComAssertMsgFailed(a) \ + do { \ + setError(E_FAIL, \ + "Assertion failed: at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .c_str()); \ + } while (0) +#endif + /** * Special version of the AssertRC macro to be used within VirtualBoxBase * subclasses. @@ -270,9 +289,32 @@ public: /** Special version of ComAssertComRC that returns rc if rc does not succeed */ #define ComAssertComRCRetRC(rc) \ do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0) -/** Special version of ComAssert that returns ret */ -#define ComAssertFailedRet(ret) \ +/** Special version of ComAssertFailed that returns ret */ +#define ComAssertFailedRet(ret) \ do { ComAssertFailed(); return (ret); } while (0) +/** Special version of ComAssertMsgFailed that returns ret */ +#define ComAssertMsgFailedRet(msg, ret) \ + do { ComAssertMsgFailed(msg); return (ret); } while (0) + + +/** Special version of ComAssert that returns void if expr fails */ +#define ComAssertRetVoid(expr) \ + do { ComAssert(expr); if (!(expr)) return; } while (0) +/** Special version of ComAssertMsg that returns void if expr fails */ +#define ComAssertMsgRetVoid(expr, a) \ + do { ComAssertMsg(expr, a); if (!(expr)) return; } while (0) +/** Special version of ComAssertRC that returns void if vrc does not succeed */ +#define ComAssertRCRetVoid(vrc) \ + do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return; } while (0) +/** Special version of ComAssertComRC that returns void if rc does not succeed */ +#define ComAssertComRCRetVoid(rc) \ + do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return; } while (0) +/** Special version of ComAssertFailed that returns void */ +#define ComAssertFailedRetVoid() \ + do { ComAssertFailed(); return; } while (0) +/** Special version of ComAssertMsgFailed that returns void */ +#define ComAssertMsgFailedRetVoid(msg) \ + do { ComAssertMsgFailed(msg); return; } while (0) /** Special version of ComAssert that evaluates eval and breaks if expr fails */ @@ -383,7 +425,7 @@ public: do { \ Guid tmpGuid(a_Arg); \ (a_GuidVar) = tmpGuid; \ - if (RT_UNLIKELY((a_GuidVar).isEmpty())) \ + if (RT_UNLIKELY((a_GuidVar).isValid() == false)) \ return setError(E_INVALIDARG, \ tr("GUID argument %s is not valid (\"%ls\")"), #a_Arg, Bstr(a_Arg).raw()); \ } while (0) diff --git a/src/VBox/Main/include/VirtualBoxClientImpl.h b/src/VBox/Main/include/VirtualBoxClientImpl.h index 8a4d973d..db17640a 100644 --- a/src/VBox/Main/include/VirtualBoxClientImpl.h +++ b/src/VBox/Main/include/VirtualBoxClientImpl.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -59,6 +59,7 @@ public: STDMETHOD(COMGETTER(VirtualBox))(IVirtualBox **aVirtualBox); STDMETHOD(COMGETTER(Session))(ISession **aSession); STDMETHOD(COMGETTER(EventSource))(IEventSource **aEventSource); + STDMETHOD(CheckMachineError)(IMachine *aMachine); private: /** Instance counter for simulating something similar to a singleton. diff --git a/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h b/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h index bb47dc54..8f02cf9d 100644 --- a/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h +++ b/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -83,7 +83,8 @@ public: #endif VirtualBoxErrorInfo() - : m_resultCode(S_OK) + : m_resultCode(S_OK), + m_resultDetail(0) {} // public initializer/uninitializer for internal purposes only @@ -93,11 +94,19 @@ public: const Utf8Str &strText, IVirtualBoxErrorInfo *aNext = NULL); + HRESULT initEx(HRESULT aResultCode, + LONG aResultDetail, + const GUID &aIID, + const char *pcszComponent, + const Utf8Str &strText, + IVirtualBoxErrorInfo *aNext = NULL); + HRESULT init(const com::ErrorInfo &ei, IVirtualBoxErrorInfo *aNext = NULL); // IVirtualBoxErrorInfo properties STDMETHOD(COMGETTER(ResultCode))(LONG *aResultCode); + STDMETHOD(COMGETTER(ResultDetail))(LONG *aResultDetail); STDMETHOD(COMGETTER(InterfaceID))(BSTR *aIID); STDMETHOD(COMGETTER(Component))(BSTR *aComponent); STDMETHOD(COMGETTER(Text))(BSTR *aText); @@ -113,6 +122,7 @@ private: void * /* c */) { return rc; } HRESULT m_resultCode; + LONG m_resultDetail; Utf8Str m_strText; Guid m_IID; Utf8Str m_strComponent; diff --git a/src/VBox/Main/include/VirtualBoxImpl.h b/src/VBox/Main/include/VirtualBoxImpl.h index 3bf748a9..0ba8a3f1 100644 --- a/src/VBox/Main/include/VirtualBoxImpl.h +++ b/src/VBox/Main/include/VirtualBoxImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -19,6 +19,7 @@ #define ____H_VIRTUALBOXIMPL #include "VirtualBoxBase.h" +#include "objectslist.h" #ifdef RT_OS_WINDOWS # include "win/resource.h" @@ -32,17 +33,17 @@ namespace com class SessionMachine; class GuestOSType; -class SharedFolder; class Progress; class Host; class SystemProperties; class DHCPServer; class PerformanceCollector; -class VirtualBoxCallbackRegistration; /* see VirtualBoxImpl.cpp */ #ifdef VBOX_WITH_EXTPACK class ExtPackManager; #endif class AutostartDb; +class NATNetwork; + typedef std::list > SessionMachinesList; @@ -50,8 +51,6 @@ typedef std::list > SessionMachinesList; class SVCHlpClient; #endif -struct VMClientWatcherData; - namespace settings { class MainConfigFile; @@ -68,6 +67,7 @@ class ATL_NO_VTABLE VirtualBox : public: typedef std::list > InternalControlList; + typedef ObjectsList MachinesOList; class CallbackEvent; friend class CallbackEvent; @@ -120,6 +120,7 @@ public: STDMETHOD(COMGETTER(SharedFolders))(ComSafeArrayOut(ISharedFolder *, aSharedFolders)); STDMETHOD(COMGETTER(PerformanceCollector))(IPerformanceCollector **aPerformanceCollector); STDMETHOD(COMGETTER(DHCPServers))(ComSafeArrayOut(IDHCPServer *, aDHCPServers)); + STDMETHOD(COMGETTER(NATNetworks))(ComSafeArrayOut(INATNetwork *, aNATNetworks)); STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); STDMETHOD(COMGETTER(ExtensionPackManager))(IExtPackManager **aExtPackManager); STDMETHOD(COMGETTER(InternalNetworks))(ComSafeArrayOut(BSTR, aInternalNetworks)); @@ -160,6 +161,11 @@ public: STDMETHOD(CreateDHCPServer)(IN_BSTR aName, IDHCPServer ** aServer); STDMETHOD(FindDHCPServerByNetworkName)(IN_BSTR aName, IDHCPServer ** aServer); STDMETHOD(RemoveDHCPServer)(IDHCPServer * aServer); + + STDMETHOD(CreateNATNetwork)(IN_BSTR aName, INATNetwork ** aNATNetworks); + STDMETHOD(FindNATNetworkByName)(IN_BSTR aName, INATNetwork ** aNATNetworks); + STDMETHOD(RemoveNATNetwork)(INATNetwork * aNATNetwork); + STDMETHOD(CheckFirmwarePresent)(FirmwareType_T aFirmwareType, IN_BSTR aVersion, BSTR * aUrl, BSTR * aFile, BOOL * aResult); @@ -207,15 +213,28 @@ public: void onSnapshotChange(const Guid &aMachineId, const Guid &aSnapshotId); void onGuestPropertyChange(const Guid &aMachineId, IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags); - void onMachineUninit(Machine *aMachine); void onNatRedirectChange(const Guid &aMachineId, ULONG ulSlot, bool fRemove, IN_BSTR aName, NATProtocol_T aProto, IN_BSTR aHostIp, uint16_t aHostPort, IN_BSTR aGuestIp, uint16_t aGuestPort); + void onNATNetworkChange(IN_BSTR aNetworkName); + void onNATNetworkStartStop(IN_BSTR aNetworkName, BOOL aStart); + void onNATNetworkSetting(IN_BSTR aNetworkName, BOOL aEnabled, IN_BSTR aNetwork, + IN_BSTR aGateway, BOOL aAdvertiseDefaultIpv6RouteEnabled, + BOOL fNeedDhcpServer); + void onNATNetworkPortForward(IN_BSTR aNetworkName, BOOL create, BOOL fIpv6, + IN_BSTR aRuleName, NATProtocol_T proto, + IN_BSTR aHostIp, LONG aHostPort, + IN_BSTR aGuestIp, LONG aGuestPort); + void onHostNameResolutionConfigurationChange(); + + int natNetworkRefInc(IN_BSTR aNetworkName); + int natNetworkRefDec(IN_BSTR aNetworkName); ComObjPtr getUnknownOSType(); void getOpenedMachines(SessionMachinesList &aMachines, InternalControlList *aControls = NULL); + MachinesOList &getMachinesList(); HRESULT findMachine(const Guid &aId, bool fPermitInaccessible, @@ -295,13 +314,17 @@ public: AutostartDb* getAutostartDb() const; + RWLockHandle& getMachinesListLockHandle(); RWLockHandle& getMediaTreeLockHandle(); int encryptSetting(const Utf8Str &aPlaintext, Utf8Str *aCiphertext); int decryptSetting(Utf8Str *aPlaintext, const Utf8Str &aCiphertext); void storeSettingsKey(const Utf8Str &aKey); + bool isMediaUuidInUse(const Guid &aId, DeviceType_T deviceType); + private: + class ClientWatcher; static HRESULT setErrorStatic(HRESULT aResultCode, const Utf8Str &aText) @@ -309,17 +332,20 @@ private: return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true); } - HRESULT checkMediaForConflicts(const Guid &aId, - const Utf8Str &aLocation, - Utf8Str &aConflictType, - ComObjPtr *pDupMedium); - HRESULT registerMachine(Machine *aMachine); HRESULT registerDHCPServer(DHCPServer *aDHCPServer, bool aSaveRegistry = true); HRESULT unregisterDHCPServer(DHCPServer *aDHCPServer, bool aSaveRegistry = true); + HRESULT registerNATNetwork(NATNetwork *aNATNetwork, + bool aSaveRegistry = true); + HRESULT unregisterNATNetwork(NATNetwork *aNATNetwork, + bool aSaveRegistry = true); + HRESULT checkMediaForConflicts(const Guid &aId, + const Utf8Str &aLocation, + Utf8Str &aConflictType, + ComObjPtr *pDupMedium); int decryptSettings(); int decryptMediumSettings(Medium *pMedium); @@ -337,8 +363,9 @@ private: static ULONG sRevision; static Bstr sPackageType; static Bstr sAPIVersion; + static std::map sNatNetworkNameToRefCount; + static RWLockHandle* spMtxNatNetworkNameToRefCountLock; - static DECLCALLBACK(int) ClientWatcher(RTTHREAD thread, void *pvUser); static DECLCALLBACK(int) AsyncEventHandler(RTTHREAD thread, void *pvUser); #ifdef RT_OS_WINDOWS diff --git a/src/VBox/Main/include/Wrapper.h b/src/VBox/Main/include/Wrapper.h new file mode 100644 index 00000000..2381ea2b --- /dev/null +++ b/src/VBox/Main/include/Wrapper.h @@ -0,0 +1,491 @@ +/* $Id: Wrapper.h $ */ +/** @file + * VirtualBox COM: API wrapper helpers + */ + +/* + * Copyright (C) 2012-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_WRAPPER +#define ____H_WRAPPER + +#include +#include +#include + +#include "AutoCaller.h" + + +/** + * Checks that the given pointer to an output argument is valid and throws + * E_POINTER + extended error info otherwise. + * @param arg Pointer argument. + */ +#define CheckComArgOutPointerValidThrow(arg) \ + do { \ + if (RT_UNLIKELY(!VALID_PTR(arg))) \ + throw setError(E_POINTER, \ + tr("Output argument %s points to invalid memory location (%p)"), \ + #arg, (void *)(arg)); \ + } while (0) + + +class BSTROutConverter +{ +public: + BSTROutConverter() : mDst(NULL) + { + } + + BSTROutConverter(BSTR *aDst) : mDst(aDst) + { + } + + ~BSTROutConverter() + { + if (mDst) + Bstr(mStr).detachTo(mDst); + } + + com::Utf8Str &str() + { + return mStr; + } + +private: + com::Utf8Str mStr; + BSTR *mDst; +}; + +class BSTRInConverter +{ +public: + BSTRInConverter() : mSrc() + { + } + + BSTRInConverter(CBSTR aSrc) : mSrc(aSrc) + { + } + + ~BSTRInConverter() + { + } + + const com::Utf8Str &str() + { + return mSrc; + } + +private: + const com::Utf8Str mSrc; +}; + +class ArrayBSTROutConverter +{ +public: + ArrayBSTROutConverter() : +#ifdef VBOX_WITH_XPCOM + mDstSize(NULL), + mDst(NULL) +#else // !VBOX_WITH_XPCOM + mDst(NULL) +#endif // !VBOX_WITH_XPCOM + { + } + + ArrayBSTROutConverter(ComSafeArrayOut(BSTR, aDst)) : +#ifdef VBOX_WITH_XPCOM + mDstSize(aDstSize), + mDst(aDst) +#else // !VBOX_WITH_XPCOM + mDst(aDst) +#endif // !VBOX_WITH_XPCOM + { + } + + ~ArrayBSTROutConverter() + { + if (mDst) + { + com::SafeArray outArray(mArray.size()); + for (size_t i = 0; i < mArray.size(); i++) + Bstr(mArray[i]).detachTo(&outArray[i]); + outArray.detachTo(ComSafeArrayOutArg(mDst)); + } + } + + std::vector &array() + { + return mArray; + } + +private: + std::vector mArray; +#ifdef VBOX_WITH_XPCOM + PRUint32 *mDstSize; + BSTR **mDst; +#else // !VBOX_WITH_XPCOM + SAFEARRAY **mDst; +#endif // !VBOX_WITH_XPCOM +}; + +class ArrayBSTRInConverter +{ +public: + ArrayBSTRInConverter() + { + } + + ArrayBSTRInConverter(ComSafeArrayIn(IN_BSTR, aSrc)) + { + if (!ComSafeArrayInIsNull(aSrc)) + { + com::SafeArray inArray(ComSafeArrayInArg(aSrc)); + mArray.resize(inArray.size()); + for (size_t i = 0; i < inArray.size(); i++) + mArray[i] = inArray[i]; + } + } + + ~ArrayBSTRInConverter() + { + } + + const std::vector &array() + { + return mArray; + } + +private: + std::vector mArray; +}; + +class UuidOutConverter +{ +public: + UuidOutConverter() : mDst(NULL) + { + } + + UuidOutConverter(BSTR *aDst) : mDst(aDst) + { + } + + ~UuidOutConverter() + { + if (mDst) + mUuid.toUtf16().detachTo(mDst); + } + + com::Guid &uuid() + { + return mUuid; + } + +private: + com::Guid mUuid; + BSTR *mDst; +}; + +class UuidInConverter +{ +public: + UuidInConverter() : mSrc() + { + } + + UuidInConverter(CBSTR aSrc) : mSrc(aSrc) + { + } + + ~UuidInConverter() + { + } + + const com::Guid &uuid() + { + return mSrc; + } + +private: + const com::Guid mSrc; +}; + +class ArrayUuidOutConverter +{ +public: + ArrayUuidOutConverter() : +#ifdef VBOX_WITH_XPCOM + mDstSize(NULL), + mDst(NULL) +#else // !VBOX_WITH_XPCOM + mDst(NULL) +#endif // !VBOX_WITH_XPCOM + { + } + + ArrayUuidOutConverter(ComSafeArrayOut(BSTR, aDst)) : +#ifdef VBOX_WITH_XPCOM + mDstSize(aDstSize), + mDst(aDst) +#else // !VBOX_WITH_XPCOM + mDst(aDst) +#endif // !VBOX_WITH_XPCOM + { + } + + ~ArrayUuidOutConverter() + { + if (mDst) + { + com::SafeArray outArray(mArray.size()); + for (size_t i = 0; i < mArray.size(); i++) + mArray[i].toUtf16().detachTo(&outArray[i]); + outArray.detachTo(ComSafeArrayOutArg(mDst)); + } + } + + std::vector &array() + { + return mArray; + } + +private: + std::vector mArray; +#ifdef VBOX_WITH_XPCOM + PRUint32 *mDstSize; + BSTR **mDst; +#else // !VBOX_WITH_XPCOM + SAFEARRAY **mDst; +#endif // !VBOX_WITH_XPCOM +}; + +template +class ComTypeOutConverter +{ +public: + ComTypeOutConverter() : mDst(NULL) + { + } + + ComTypeOutConverter(A **aDst) : mDst(aDst) + { + } + + ~ComTypeOutConverter() + { + if (mDst) + mPtr.queryInterfaceTo(mDst); + } + + ComPtr &ptr() + { + return mPtr; + } + +private: + ComPtr mPtr; + A **mDst; +}; + +template +class ComTypeInConverter +{ +public: + ComTypeInConverter() : mSrc(NULL) + { + } + + ComTypeInConverter(A *aSrc) : mSrc(aSrc) + { + } + + ~ComTypeInConverter() + { + } + + const ComPtr &ptr() + { + return mSrc; + } + +private: + const ComPtr mSrc; +}; + +template +class ArrayComTypeOutConverter +{ +public: + ArrayComTypeOutConverter() : +#ifdef VBOX_WITH_XPCOM + mDstSize(NULL), + mDst(NULL) +#else // !VBOX_WITH_XPCOM + mDst(NULL) +#endif // !VBOX_WITH_XPCOM + { + } + + ArrayComTypeOutConverter(ComSafeArrayOut(A *, aDst)) : +#ifdef VBOX_WITH_XPCOM + mDstSize(aDstSize), + mDst(aDst) +#else // !VBOX_WITH_XPCOM + mDst(aDst) +#endif // !VBOX_WITH_XPCOM + { + } + + ~ArrayComTypeOutConverter() + { + if (mDst) + { + com::SafeIfaceArray outArray(mArray.size()); + for (size_t i = 0; i < mArray.size(); i++) + outArray[i] = mArray[i]; + outArray.detachTo(ComSafeArrayOutArg(mDst)); + } + } + + std::vector > &array() + { + return mArray; + } + +private: + std::vector > mArray; +#ifdef VBOX_WITH_XPCOM + PRUint32 *mDstSize; + A ***mDst; +#else // !VBOX_WITH_XPCOM + SAFEARRAY **mDst; +#endif // !VBOX_WITH_XPCOM +}; + +template +class ArrayComTypeInConverter +{ +public: + ArrayComTypeInConverter() + { + } + + ArrayComTypeInConverter(ComSafeArrayIn(A *, aSrc)) + { + if (!ComSafeArrayInIsNull(aSrc)) + { + com::SafeIfaceArray inArray(ComSafeArrayInArg(aSrc)); + mArray.resize(inArray.size()); + for (size_t i = 0; i < inArray.size(); i++) + mArray[i] = inArray[i]; + } + } + + ~ArrayComTypeInConverter() + { + } + + const std::vector > &array() + { + return mArray; + } + +private: + std::vector > mArray; +}; + +template +class ArrayOutConverter +{ +public: + ArrayOutConverter() : +#ifdef VBOX_WITH_XPCOM + mDstSize(NULL), + mDst(NULL) +#else // !VBOX_WITH_XPCOM + mDst(NULL) +#endif // !VBOX_WITH_XPCOM + { + } + + ArrayOutConverter(ComSafeArrayOut(A, aDst)) : +#ifdef VBOX_WITH_XPCOM + mDstSize(aDstSize), + mDst(aDst) +#else // !VBOX_WITH_XPCOM + mDst(aDst) +#endif // !VBOX_WITH_XPCOM + { + } + + ~ArrayOutConverter() + { + if (mDst) + { + com::SafeArray outArray(mArray.size()); + for (size_t i = 0; i < mArray.size(); i++) + outArray[i] = mArray[i]; + outArray.detachTo(ComSafeArrayOutArg(mDst)); + } + } + + std::vector &array() + { + return mArray; + } + +private: + std::vector mArray; +#ifdef VBOX_WITH_XPCOM + PRUint32 *mDstSize; + A **mDst; +#else // !VBOX_WITH_XPCOM + SAFEARRAY **mDst; +#endif // !VBOX_WITH_XPCOM +}; + +template +class ArrayInConverter +{ +public: + ArrayInConverter() + { + } + + ArrayInConverter(ComSafeArrayIn(A, aSrc)) + { + if (!ComSafeArrayInIsNull(aSrc)) + { + com::SafeArray inArray(ComSafeArrayInArg(aSrc)); + mArray.resize(inArray.size()); + for (size_t i = 0; i < inArray.size(); i++) + mArray[i] = inArray[i]; + } + } + + ~ArrayInConverter() + { + } + + const std::vector &array() + { + return mArray; + } + +private: + std::vector mArray; +}; + +#endif // !____H_WRAPPER +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/netif.h b/src/VBox/Main/include/netif.h index b1ab8901..bd618922 100644 --- a/src/VBox/Main/include/netif.h +++ b/src/VBox/Main/include/netif.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -84,14 +84,16 @@ typedef NETIFINFO const *PCNETIFINFO; #endif int NetIfList(std::list > &list); -int NetIfEnableStaticIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf, ULONG aOldIp, ULONG aNewIp, ULONG aMask); -int NetIfEnableStaticIpConfigV6(VirtualBox *pVbox, HostNetworkInterface * pIf, IN_BSTR aOldIPV6Address, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength); -int NetIfEnableDynamicIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf); -int NetIfCreateHostOnlyNetworkInterface (VirtualBox *pVbox, IHostNetworkInterface **aHostNetworkInterface, IProgress **aProgress, const char *pcszName = NULL); -int NetIfRemoveHostOnlyNetworkInterface (VirtualBox *pVbox, IN_GUID aId, IProgress **aProgress); +int NetIfEnableStaticIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf, ULONG aOldIp, ULONG aNewIp, ULONG aMask); +int NetIfEnableStaticIpConfigV6(VirtualBox *pVBox, HostNetworkInterface * pIf, IN_BSTR aOldIPV6Address, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength); +int NetIfEnableDynamicIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf); +int NetIfCreateHostOnlyNetworkInterface (VirtualBox *pVBox, IHostNetworkInterface **aHostNetworkInterface, IProgress **aProgress, const char *pcszName = NULL); +int NetIfRemoveHostOnlyNetworkInterface (VirtualBox *pVBox, IN_GUID aId, IProgress **aProgress); int NetIfGetConfig(HostNetworkInterface * pIf, NETIFINFO *); int NetIfGetConfigByName(PNETIFINFO pInfo); -int NetIfDhcpRediscover(VirtualBox *pVbox, HostNetworkInterface * pIf); +int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState); +int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits); +int NetIfDhcpRediscover(VirtualBox *pVBox, HostNetworkInterface * pIf); int NetIfAdpCtlOut(const char * pcszName, const char * pcszCmd, char *pszBuffer, size_t cBufSize); DECLINLINE(Bstr) composeIPv6Address(PRTNETADDRIPV6 aAddrPtr) @@ -121,12 +123,12 @@ DECLINLINE(ULONG) composeIPv6PrefixLenghFromAddress(PRTNETADDRIPV6 aAddrPtr) DECLINLINE(int) prefixLength2IPv6Address(ULONG cPrefix, PRTNETADDRIPV6 aAddrPtr) { - if(cPrefix > 128) + if (cPrefix > 128) return VERR_INVALID_PARAMETER; - if(!aAddrPtr) + if (!aAddrPtr) return VERR_INVALID_PARAMETER; - memset(aAddrPtr, 0, sizeof(RTNETADDRIPV6)); + RT_ZERO(*aAddrPtr); ASMBitSetRange(aAddrPtr, 0, cPrefix); @@ -150,7 +152,8 @@ DECLINLINE(Bstr) getDefaultIPv4Address(Bstr bstrIfName) /* Get the index from the name */ Utf8Str strTmp = bstrIfName; const char *pszIfName = strTmp.c_str(); - int iInstance = 0, iPos = strcspn(pszIfName, "0123456789"); + int iInstance = 0; + size_t iPos = strcspn(pszIfName, "0123456789"); if (pszIfName[iPos]) iInstance = RTStrToUInt32(pszIfName + iPos); diff --git a/src/VBox/Main/include/objectslist.h b/src/VBox/Main/include/objectslist.h index a506a161..7b9ca04d 100644 --- a/src/VBox/Main/include/objectslist.h +++ b/src/VBox/Main/include/objectslist.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/ovfreader.h b/src/VBox/Main/include/ovfreader.h index e1e21d5c..80769308 100644 --- a/src/VBox/Main/include/ovfreader.h +++ b/src/VBox/Main/include/ovfreader.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,12 +26,41 @@ namespace ovf { +//////////////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Thrown by OVFReader for any kind of error that is not an XML error but + * still makes the OVF impossible to parse. Based on xml::LogicError so + * that one catch() for all xml::LogicError can handle all possible errors. + */ +class OVFLogicError : public xml::LogicError +{ +public: + OVFLogicError(const char *aFormat, ...); +}; + + //////////////////////////////////////////////////////////////////////////////// // // Enumerations // //////////////////////////////////////////////////////////////////////////////// +/** + * CIM OS values. + * + * The OVF 1.10 spec refers to some CIM_OperatingSystem.mof doc. Could this be it: + * http://cvs.opengroup.org/cgi-bin/cvsweb.cgi/pegasus/Schemas/CIM231/DMTF/System/CIM_OperatingSystem.mof + * + * @todo r=bird: Why are the values are repeating 'CIMOS'. CIMOSType_T is also + * repeating it self, 'Type' and '_T'. Why not call it kCIOMOpSys, + * easier to read as well. + * Then also apply: s/CIMOSType_CIMOS_/kCIMOpSys_/g + */ enum CIMOSType_T { CIMOSType_CIMOS_Unknown = 0, @@ -149,6 +178,62 @@ enum CIMOSType_T // no new types added with CIM 2.26.0 }; +enum OVFVersion_T +{ + OVFVersion_unknown, + OVFVersion_0_9, + OVFVersion_1_0, + OVFVersion_2_0 +}; + +const char* const OVF09_URI_string = "http://www.vmware.com/schema/ovf/1/envelope"; +const char* const OVF10_URI_string = "http://schemas.dmtf.org/ovf/envelope/1"; +const char* const OVF20_URI_string = "http://schemas.dmtf.org/ovf/envelope/2"; + +const char* const DTMF_SPECS_URI = "http://schemas.dmtf.org/wbem/cim-html/2/"; + +//////////////////////////////////////////////////////////////////////////////// +// +// Envelope data +// +//////////////////////////////////////////////////////////////////////////////// +struct EnvelopeData +{ + OVFVersion_T version;//OVF standard version, it is used internally only by VirtualBox + RTCString lang;//language + + OVFVersion_T getOVFVersion() const + { + return version; + } + + + RTCString getStringOVFVersion() const + { + if (version == OVFVersion_0_9) + return "0.9"; + else if (version == OVFVersion_1_0) + return "1.0"; + else if (version == OVFVersion_2_0) + return "2.0"; + else + return ""; + } + + void setOVFVersion(OVFVersion_T v) + { + version = v; + } +}; + + +struct FileReference +{ + RTCString strHref; // value from /References/File/@href (filename) + RTCString strDiskId; // value from /References/File/@id () +}; + +typedef std::map FileReferenceMap; //////////////////////////////////////////////////////////////////////////////// // @@ -167,7 +252,7 @@ struct DiskImage // space, but cannot be larger than iCapacity; -1 if not set) RTCString strFormat; // value from DiskSection/Disk/@format // typically http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized - RTCString uuidVbox; // optional; if the file was exported by VirtualBox >= 3.2, + RTCString uuidVBox; // optional; if the file was exported by VirtualBox >= 3.2, // then this has the UUID with which the disk was registered // fields from /References/File; the spec says the file reference from disk can be empty, @@ -204,8 +289,24 @@ enum ResourceType_T ResourceType_SoundCard = 35 }; -struct VirtualHardwareItem + +enum StorageAccessType_T +{ StorageAccessType_Unknown = 0, + StorageAccessType_Readable = 1, + StorageAccessType_Writeable = 2, + StorageAccessType_ReadWrite = 3 +}; + +enum ComplianceType_T +{ ComplianceType_No = 0, + ComplianceType_Soft = 1, + ComplianceType_Medium = 2, + ComplianceType_Strong = 3 +}; + +class VirtualHardwareItem { +public: RTCString strDescription; RTCString strCaption; RTCString strElementName; @@ -253,7 +354,133 @@ struct VirtualHardwareItem ullWeight(0), ulBusNumber(0), ulLineNumber(0) - {}; + { + itemName = "Item"; + }; + + void fillItem(const xml::ElementNode *item); + + void setDefaultFlag() + { + fDefault = true; + } + + bool isThereDefaultValues() const + { + return fDefault; + } + + void checkConsistencyAndCompliance() RT_THROW(OVFLogicError) + { + _checkConsistencyAndCompliance(); + } + +protected: + virtual void _checkConsistencyAndCompliance() RT_THROW(OVFLogicError); + virtual const RTCString& getItemName() + { + return _getItemName(); + } + +private: + RTCString itemName; + bool fDefault;//true means that some fields were absent in the XML and some default values were assigned to. + + virtual const RTCString& _getItemName() + { + return itemName; + } +}; + +class StorageItem: public VirtualHardwareItem +{ + //see DMTF Schema Documentation http://schemas.dmtf.org/wbem/cim-html/2/ + StorageAccessType_T accessType; + RTCString strHostExtentName; + int16_t hostExtentNameFormat; + int16_t hostExtentNameNamespace; + int64_t hostExtentStartingAddress; + int64_t hostResourceBlockSize; + int64_t limit; + RTCString strOtherHostExtentNameFormat; + RTCString strOtherHostExtentNameNamespace; + int64_t reservation; + int64_t virtualQuantity; + RTCString strVirtualQuantityUnits; + int64_t virtualResourceBlockSize; + +public: + StorageItem(): VirtualHardwareItem(), + accessType(StorageAccessType_Unknown), + hostExtentNameFormat(-1), + hostExtentNameNamespace(-1), + hostExtentStartingAddress(-1), + hostResourceBlockSize(-1), + limit(-1), + reservation(-1), + virtualQuantity(-1), + virtualResourceBlockSize(-1) + { + itemName = "StorageItem"; + }; + + void fillItem(const xml::ElementNode *item); + +protected: + virtual void _checkConsistencyAndCompliance() RT_THROW(OVFLogicError); +private: + RTCString itemName; + + virtual const RTCString& _getItemName() + { + return itemName; + } +}; + + +class EthernetPortItem: public VirtualHardwareItem +{ + //see DMTF Schema Documentation http://schemas.dmtf.org/wbem/cim-html/2/ + uint16_t DefaultPortVID; + uint16_t DefaultPriority; + uint16_t DesiredVLANEndpointMode; + uint32_t GroupID; + uint32_t ManagerID; + RTCString strNetworkPortProfileID; + uint16_t NetworkPortProfileIDType; + RTCString strOtherEndpointMode; + RTCString strOtherNetworkPortProfileIDTypeInfo; + RTCString strPortCorrelationID; + uint16_t PortVID; + bool Promiscuous; + uint64_t ReceiveBandwidthLimit; + uint16_t ReceiveBandwidthReservation; + bool SourceMACFilteringEnabled; + uint32_t VSITypeID; + uint8_t VSITypeIDVersion; + uint16_t AllowedPriorities[256]; + RTCString strAllowedToReceiveMACAddresses; + uint16_t AllowedToReceiveVLANs[256]; + RTCString strAllowedToTransmitMACAddresses; + uint16_t AllowedToTransmitVLANs[256]; + +public: + EthernetPortItem(): VirtualHardwareItem() + { + itemName = "EthernetPortItem"; + }; + + void fillItem(const xml::ElementNode *item); + +protected: + virtual void _checkConsistencyAndCompliance() RT_THROW(OVFLogicError); +private: + RTCString itemName; + + virtual const RTCString& _getItemName() + { + return itemName; + } }; typedef std::map DiskImagesMap; @@ -290,14 +517,15 @@ typedef std::map ControllersMap; struct VirtualDisk { - uint32_t idController; // SCSI (or IDE) controller this disk is connected to; - // this must match HardDiskController.idController and - // points into VirtualSystem.mapControllers - uint32_t ulAddressOnParent; // parsed strAddressOnParent of hardware item; will be 0 or 1 for IDE - // and possibly higher for disks attached to SCSI controllers (untested) - RTCString strDiskId; // if the hard disk has an ovf:/disk/ reference, - // this receives the component; points to one of the - // references in Appliance::Data.mapDisks + uint32_t idController;// SCSI (or IDE) controller this disk is connected to; + // this must match HardDiskController.idController and + // points into VirtualSystem.mapControllers + uint32_t ulAddressOnParent;// parsed strAddressOnParent of hardware item; will be 0 or 1 for IDE + // and possibly higher for disks attached to SCSI controllers (untested) + RTCString strDiskId;// if the hard disk has an ovf:/disk/ reference, + // this receives the component; points to one of the + // references in Appliance::Data.mapDisks + bool fEmpty;//true - empty disk, e.g. the component ... is absent. }; typedef std::map VirtualDisksMap; @@ -326,7 +554,7 @@ struct VirtualSystem CIMOSType_T cimos; RTCString strCimosDesc; // readable description of the cimos type in the case of cimos = 0/1/102 - RTCString strTypeVbox; // optional type from @vbox:ostype attribute (VirtualBox 4.0 or higher) + RTCString strTypeVBox; // optional type from @vbox:ostype attribute (VirtualBox 4.0 or higher) RTCString strVirtualSystemType; // generic hardware description; OVF says this can be something like "vmx-4" or "xen"; // VMware Workstation 6.5 is "vmx-07" @@ -360,8 +588,7 @@ struct VirtualSystem RTCString strProductUrl; // product info if any; receives contents of VirtualSystem/ProductSection/ProductUrl RTCString strVendorUrl; // product info if any; receives contents of VirtualSystem/ProductSection/VendorUrl - const xml::ElementNode // pointer to element under element or NULL if not present - *pelmVboxMachine; + const xml::ElementNode *pelmVBoxMachine; // pointer to element under element or NULL if not present VirtualSystem() : cimos(CIMOSType_CIMOS_Unknown), @@ -370,7 +597,7 @@ struct VirtualSystem fHasFloppyDrive(false), fHasCdromDrive(false), fHasUsbController(false), - pelmVboxMachine(NULL) + pelmVBoxMachine(NULL) { } }; @@ -403,7 +630,6 @@ struct VirtualSystem delete pReader; */ - class OVFReader { public: @@ -411,7 +637,8 @@ public: OVFReader(const RTCString &path); // Data fields - RTCString m_strPath; // file name given to constructor + EnvelopeData m_envelopeData; //data of root element "Envelope" + RTCString m_strPath; // file name given to constructor DiskImagesMap m_mapDisks; // map of DiskImage structs, sorted by DiskImage.strDiskId std::list m_llVirtualSystems; // list of virtual systems, created by and valid after read() @@ -425,24 +652,7 @@ private: void HandleVirtualSystemContent(const xml::ElementNode *pContentElem); }; -//////////////////////////////////////////////////////////////////////////////// -// -// Errors -// -//////////////////////////////////////////////////////////////////////////////// - -/** - * Thrown by OVFReader for any kind of error that is not an XML error but - * still makes the OVF impossible to parse. Based on xml::LogicError so - * that one catch() for all xml::LogicError can handle all possible errors. - */ - -class OVFLogicError : public xml::LogicError -{ -public: - OVFLogicError(const char *aFormat, ...); -}; - } // end namespace ovf -#endif // ____H_OVFREADER +#endif // !____H_OVFREADER + diff --git a/src/VBox/Main/include/vbox-libhal.h b/src/VBox/Main/include/vbox-libhal.h index 5f67a4d2..5697b20f 100644 --- a/src/VBox/Main/include/vbox-libhal.h +++ b/src/VBox/Main/include/vbox-libhal.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/include/win/resource.h b/src/VBox/Main/include/win/resource.h index 173a49b8..160e4734 100644 --- a/src/VBox/Main/include/win/resource.h +++ b/src/VBox/Main/include/win/resource.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/DisplayPNGUtil.cpp b/src/VBox/Main/src-all/DisplayPNGUtil.cpp index 345becfc..6515845b 100644 --- a/src/VBox/Main/src-all/DisplayPNGUtil.cpp +++ b/src/VBox/Main/src-all/DisplayPNGUtil.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/DisplayResampleImage.cpp b/src/VBox/Main/src-all/DisplayResampleImage.cpp index 85c29d65..d46bffae 100644 --- a/src/VBox/Main/src-all/DisplayResampleImage.cpp +++ b/src/VBox/Main/src-all/DisplayResampleImage.cpp @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/DisplayUtils.cpp b/src/VBox/Main/src-all/DisplayUtils.cpp index efc994f3..70e15559 100644 --- a/src/VBox/Main/src-all/DisplayUtils.cpp +++ b/src/VBox/Main/src-all/DisplayUtils.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/EventImpl.cpp b/src/VBox/Main/src-all/EventImpl.cpp index 03eb7e3c..820f84b9 100644 --- a/src/VBox/Main/src-all/EventImpl.cpp +++ b/src/VBox/Main/src-all/EventImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -120,7 +120,7 @@ HRESULT VBoxEvent::init(IEventSource *aSource, VBoxEventType_T aType, BOOL aWait if (RT_FAILURE(vrc)) { - AssertFailed (); + AssertFailed(); return setError(E_FAIL, tr("Internal error (%Rrc)"), vrc); } @@ -155,19 +155,21 @@ STDMETHODIMP VBoxEvent::COMGETTER(Type)(VBoxEventType_T *aType) CheckComArgNotNull(aType); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); - // never changes till event alive, no locking? + // never changes while event alive, no locking *aType = m->mType; return S_OK; } -STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource* *aSource) +STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource **aSource) { CheckComArgOutPointerValid(aSource); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); m->mSource.queryInterfaceTo(aSource); return S_OK; @@ -178,9 +180,10 @@ STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable) CheckComArgNotNull(aWaitable); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); - // never changes till event alive, no locking? + // never changes while event alive, no locking *aWaitable = m->mWaitable; return S_OK; } @@ -189,7 +192,8 @@ STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable) STDMETHODIMP VBoxEvent::SetProcessed() { AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -209,7 +213,8 @@ STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult) CheckComArgNotNull(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -249,8 +254,7 @@ STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult) typedef std::list VetoList; struct VBoxVetoEvent::Data { - Data() - : + Data() : mVetoed(FALSE) {} BOOL mVetoed; @@ -281,7 +285,8 @@ HRESULT VBoxVetoEvent::init(IEventSource *aSource, VBoxEventType_T aType) HRESULT rc = S_OK; // all veto events are waitable rc = VBoxEvent::init(aSource, aType, TRUE); - if (FAILED(rc)) return rc; + if (FAILED(rc)) + return rc; m->mVetoed = FALSE; m->mVetoList.clear(); @@ -300,7 +305,8 @@ void VBoxVetoEvent::uninit() STDMETHODIMP VBoxVetoEvent::AddVeto(IN_BSTR aVeto) { AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -312,12 +318,13 @@ STDMETHODIMP VBoxVetoEvent::AddVeto(IN_BSTR aVeto) return S_OK; } -STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL * aResult) +STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL *aResult) { CheckComArgOutPointerValid(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -326,13 +333,14 @@ STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL * aResult) return S_OK; } -STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) +STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) { if (ComSafeArrayOutIsNull(aVetos)) return E_POINTER; AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); com::SafeArray vetos(m->mVetoList.size()); @@ -351,8 +359,8 @@ STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) } static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1; -static const int LastEvent = (int)VBoxEventType_Last; -static const int NumEvents = LastEvent - FirstEvent; +static const int LastEvent = (int)VBoxEventType_Last; +static const int NumEvents = LastEvent - FirstEvent; /** * Class replacing std::list and able to provide required stability @@ -367,24 +375,19 @@ public: * We have to be double linked, as structural modifications in list are delayed * till element removed, so we have to know our previous one to update its next */ - EventMapRecord* mNext; + EventMapRecord *mNext; bool mAlive; private: - EventMapRecord* mPrev; - ListenerRecord* mRef; /* must be weak reference */ + EventMapRecord *mPrev; + ListenerRecord *mRef; /* must be weak reference */ int32_t mRefCnt; public: - EventMapRecord(ListenerRecord* aRef) - : - mNext(0), - mAlive(true), - mPrev(0), - mRef(aRef), - mRefCnt(1) + EventMapRecord(ListenerRecord *aRef) : + mNext(0), mAlive(true), mPrev(0), mRef(aRef), mRefCnt(1) {} - EventMapRecord(EventMapRecord& aOther) + EventMapRecord(EventMapRecord &aOther) { mNext = aOther.mNext; mPrev = aOther.mPrev; @@ -408,7 +411,8 @@ public: void release() { - if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this; + if (ASMAtomicDecS32(&mRefCnt) <= 0) + delete this; } // Called when an element is no longer needed @@ -418,7 +422,7 @@ public: release(); } - ListenerRecord* ref() + ListenerRecord *ref() { return mAlive ? mRef : 0; } @@ -473,7 +477,7 @@ public: EventMapRecord *pCur = mHead; while (pCur) { - EventMapRecord* aNext = pCur->mNext; + EventMapRecord *aNext = pCur->mNext; if (pCur->ref() == aRec) { if (pCur == mHead) @@ -495,13 +499,13 @@ public: { EventMapRecord *mCur; - iterator() - : mCur(0) + iterator() : + mCur(0) {} explicit - iterator(EventMapRecord *aCur) - : mCur(aCur) + iterator(EventMapRecord *aCur) : + mCur(aCur) { // Prevent element removal, till we're at it if (mCur) @@ -539,13 +543,13 @@ public: } bool - operator==(const EventMapList::iterator& aOther) const + operator==(const EventMapList::iterator &aOther) const { return mCur == aOther.mCur; } bool - operator!=(const EventMapList::iterator& aOther) const + operator!=(const EventMapList::iterator &aOther) const { return mCur != aOther.mCur; } @@ -563,7 +567,7 @@ public: }; typedef EventMapList EventMap[NumEvents]; -typedef std::map PendingEventsMap; +typedef std::map PendingEventsMap; typedef std::deque > PassiveQueue; class ListenerRecord @@ -571,7 +575,7 @@ class ListenerRecord private: ComPtr mListener; BOOL mActive; - EventSource* mOwner; + EventSource *mOwner; RTSEMEVENT mQEvent; RTCRITSECT mcsQLock; @@ -580,24 +584,29 @@ private: uint64_t mLastRead; public: - ListenerRecord(IEventListener* aListener, - com::SafeArray& aInterested, - BOOL aActive, - EventSource* aOwner); + ListenerRecord(IEventListener *aListener, + com::SafeArray &aInterested, + BOOL aActive, + EventSource *aOwner); ~ListenerRecord(); - HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit, AutoLockBase& alock); - HRESULT enqueue(IEvent* aEvent); - HRESULT dequeue(IEvent* *aEvent, LONG aTimeout, AutoLockBase& aAlock); - HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit); + HRESULT process(IEvent *aEvent, BOOL aWaitable, PendingEventsMap::iterator &pit, AutoLockBase &alock); + HRESULT enqueue(IEvent *aEvent); + HRESULT dequeue(IEvent **aEvent, LONG aTimeout, AutoLockBase &aAlock); + HRESULT eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit); + void shutdown(); + void addRef() { ASMAtomicIncS32(&mRefCnt); } + void release() { - if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this; + if (ASMAtomicDecS32(&mRefCnt) <= 0) + delete this; } + BOOL isActive() { return mActive; @@ -611,15 +620,13 @@ template class RecordHolder { public: - RecordHolder(Held* lr) - : - held(lr) + RecordHolder(Held *lr) : + held(lr) { addref(); } - RecordHolder(const RecordHolder& that) - : - held(that.held) + RecordHolder(const RecordHolder &that) : + held(that.held) { addref(); } @@ -633,7 +640,7 @@ public: release(); } - Held* obj() + Held *obj() { return held; } @@ -644,7 +651,7 @@ public: return *this; } private: - Held* held; + Held *held; void addref() { @@ -656,7 +663,7 @@ private: if (held) held->release(); } - void safe_assign (Held *that_p) + void safe_assign(Held *that_p) { if (that_p) that_p->addRef(); @@ -665,14 +672,17 @@ private: } }; -typedef std::map > Listeners; +typedef std::map > Listeners; struct EventSource::Data { - Data() {} + Data() : fShutdown(false) + {} + Listeners mListeners; EventMap mEvMap; PendingEventsMap mPendingMap; + bool fShutdown; }; /** @@ -685,42 +695,39 @@ static BOOL implies(VBoxEventType_T who, VBoxEventType_T what) case VBoxEventType_Any: return TRUE; case VBoxEventType_Vetoable: - return (what == VBoxEventType_OnExtraDataCanChange) - || (what == VBoxEventType_OnCanShowWindow); + return (what == VBoxEventType_OnExtraDataCanChange) + || (what == VBoxEventType_OnCanShowWindow); case VBoxEventType_MachineEvent: - return (what == VBoxEventType_OnMachineStateChanged) - || (what == VBoxEventType_OnMachineDataChanged) - || (what == VBoxEventType_OnMachineRegistered) - || (what == VBoxEventType_OnSessionStateChanged) - || (what == VBoxEventType_OnGuestPropertyChanged); + return (what == VBoxEventType_OnMachineStateChanged) + || (what == VBoxEventType_OnMachineDataChanged) + || (what == VBoxEventType_OnMachineRegistered) + || (what == VBoxEventType_OnSessionStateChanged) + || (what == VBoxEventType_OnGuestPropertyChanged); case VBoxEventType_SnapshotEvent: - return (what == VBoxEventType_OnSnapshotTaken) - || (what == VBoxEventType_OnSnapshotDeleted) - || (what == VBoxEventType_OnSnapshotChanged) - ; + return (what == VBoxEventType_OnSnapshotTaken) + || (what == VBoxEventType_OnSnapshotDeleted) + || (what == VBoxEventType_OnSnapshotChanged) ; case VBoxEventType_InputEvent: - return (what == VBoxEventType_OnKeyboardLedsChanged) - || (what == VBoxEventType_OnMousePointerShapeChanged) - || (what == VBoxEventType_OnMouseCapabilityChanged) - ; + return (what == VBoxEventType_OnKeyboardLedsChanged) + || (what == VBoxEventType_OnMousePointerShapeChanged) + || (what == VBoxEventType_OnMouseCapabilityChanged); case VBoxEventType_Invalid: return FALSE; default: - return who == what; + break; } + + return who == what; } -ListenerRecord::ListenerRecord(IEventListener* aListener, - com::SafeArray& aInterested, - BOOL aActive, - EventSource* aOwner) - : - mActive(aActive), - mOwner(aOwner), - mRefCnt(0) +ListenerRecord::ListenerRecord(IEventListener *aListener, + com::SafeArray &aInterested, + BOOL aActive, + EventSource *aOwner) : + mActive(aActive), mOwner(aOwner), mRefCnt(0) { mListener = aListener; - EventMap* aEvMap = &aOwner->m->mEvMap; + EventMap *aEvMap = &aOwner->m->mEvMap; for (size_t i = 0; i < aInterested.size(); ++i) { @@ -738,12 +745,12 @@ ListenerRecord::ListenerRecord(IEventListener* aListener, if (!mActive) { ::RTCritSectInit(&mcsQLock); - ::RTSemEventCreate (&mQEvent); + ::RTSemEventCreate(&mQEvent); mLastRead = RTTimeMilliTS(); } else { - mQEvent =NIL_RTSEMEVENT; + mQEvent = NIL_RTSEMEVENT; RT_ZERO(mcsQLock); mLastRead = 0; } @@ -752,7 +759,7 @@ ListenerRecord::ListenerRecord(IEventListener* aListener, ListenerRecord::~ListenerRecord() { /* Remove references to us from the event map */ - EventMap* aEvMap = &mOwner->m->mEvMap; + EventMap *aEvMap = &mOwner->m->mEvMap; for (int j = FirstEvent; j < LastEvent; j++) { (*aEvMap)[j - FirstEvent].remove(this); @@ -762,7 +769,7 @@ ListenerRecord::~ListenerRecord() { // at this moment nobody could add elements to our queue, so we can safely // clean it up, otherwise there will be pending events map elements - PendingEventsMap* aPem = &mOwner->m->mPendingMap; + PendingEventsMap *aPem = &mOwner->m->mPendingMap; while (true) { ComPtr aEvent; @@ -784,21 +791,21 @@ ListenerRecord::~ListenerRecord() } ::RTCritSectDelete(&mcsQLock); - ::RTSemEventDestroy(mQEvent); } + shutdown(); } -HRESULT ListenerRecord::process(IEvent* aEvent, - BOOL aWaitable, - PendingEventsMap::iterator& pit, - AutoLockBase& aAlock) +HRESULT ListenerRecord::process(IEvent *aEvent, + BOOL aWaitable, + PendingEventsMap::iterator &pit, + AutoLockBase &aAlock) { if (mActive) { /* * We release lock here to allow modifying ops on EventSource inside callback. */ - HRESULT rc = S_OK; + HRESULT rc = S_OK; if (mListener) { aAlock.release(); @@ -816,7 +823,7 @@ HRESULT ListenerRecord::process(IEvent* aEvent, } -HRESULT ListenerRecord::enqueue (IEvent* aEvent) +HRESULT ListenerRecord::enqueue(IEvent *aEvent) { AssertMsg(!mActive, ("must be passive\n")); @@ -827,7 +834,7 @@ HRESULT ListenerRecord::enqueue (IEvent* aEvent) // and events keep coming, or queue is oversized we shall unregister this listener. uint64_t sinceRead = RTTimeMilliTS() - mLastRead; size_t queueSize = mQueue.size(); - if ( (queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000))) + if ((queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000))) { ::RTCritSectLeave(&mcsQLock); return E_ABORT; @@ -843,15 +850,15 @@ HRESULT ListenerRecord::enqueue (IEvent* aEvent) ::RTCritSectLeave(&mcsQLock); - // notify waiters + // notify waiters ::RTSemEventSignal(mQEvent); return S_OK; } -HRESULT ListenerRecord::dequeue (IEvent* *aEvent, - LONG aTimeout, - AutoLockBase& aAlock) +HRESULT ListenerRecord::dequeue(IEvent **aEvent, + LONG aTimeout, + AutoLockBase &aAlock) { if (mActive) return VBOX_E_INVALID_OBJECT_STATE; @@ -863,7 +870,8 @@ HRESULT ListenerRecord::dequeue (IEvent* *aEvent, mLastRead = RTTimeMilliTS(); - if (mQueue.empty()) { + if (mQueue.empty()) + { ::RTCritSectLeave(&mcsQLock); // Speed up common case if (aTimeout == 0) @@ -891,7 +899,7 @@ HRESULT ListenerRecord::dequeue (IEvent* *aEvent, return S_OK; } -HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterator& pit) +HRESULT ListenerRecord::eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit) { if (--pit->second == 0) { @@ -903,6 +911,16 @@ HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterat return S_OK; } +void ListenerRecord::shutdown() +{ + if (mQEvent != NIL_RTSEMEVENT) + { + RTSEMEVENT tmp = mQEvent; + mQEvent = NIL_RTSEMEVENT; + ::RTSemEventDestroy(tmp); + } +} + EventSource::EventSource() {} @@ -922,7 +940,7 @@ void EventSource::FinalRelease() BaseFinalRelease(); } -HRESULT EventSource::init(IUnknown *) +HRESULT EventSource::init() { HRESULT rc = S_OK; @@ -936,32 +954,58 @@ HRESULT EventSource::init(IUnknown *) void EventSource::uninit() { + { + // First of all (before even thinking about entering the uninit span): + // make sure that all listeners are are shut down (no pending events or + // wait calls), because they cannot be alive without the associated + // event source. Otherwise API clients which use long-term (or + // indefinite) waits will block VBoxSVC termination (just one example) + // for a long time or even infinitely long. + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (!m->fShutdown) + { + m->fShutdown = true; + for (Listeners::iterator it = m->mListeners.begin(); + it != m->mListeners.end(); + ++it) + { + it->second.obj()->shutdown(); + } + } + } + AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; + m->mListeners.clear(); // m->mEvMap shall be cleared at this point too by destructors, assert? } -STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, +STDMETHODIMP EventSource::RegisterListener(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive) + BOOL aActive) { CheckComArgNotNull(aListener); CheckComArgSafeArrayNotNull(aInterested); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::const_iterator it = m->mListeners.find(aListener); if (it != m->mListeners.end()) return setError(E_INVALIDARG, tr("This listener already registered")); - com::SafeArray interested(ComSafeArrayInArg (aInterested)); + com::SafeArray interested(ComSafeArrayInArg(aInterested)); RecordHolder lrh(new ListenerRecord(aListener, interested, aActive, this)); m->mListeners.insert(Listeners::value_type(aListener, lrh)); } @@ -973,12 +1017,13 @@ STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, return S_OK; } -STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) +STDMETHODIMP EventSource::UnregisterListener(IEventListener *aListener) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc; { @@ -988,6 +1033,7 @@ STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) if (it != m->mListeners.end()) { + it->second.obj()->shutdown(); m->mListeners.erase(it); // destructor removes refs from the event map rc = S_OK; @@ -1009,15 +1055,16 @@ STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) return rc; } -STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed) +STDMETHODIMP EventSource::FireEvent(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed) { CheckComArgNotNull(aEvent); CheckComArgOutPointerValid(aProcessed); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT hrc; BOOL aWaitable = FALSE; @@ -1026,6 +1073,10 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, do { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + VBoxEventType_T evType; hrc = aEvent->COMGETTER(Type)(&evType); AssertComRCReturn(hrc, hrc); @@ -1072,7 +1123,10 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, { Listeners::iterator lit = m->mListeners.find(record.obj()->mListener); if (lit != m->mListeners.end()) + { + lit->second.obj()->shutdown(); m->mListeners.erase(lit); + } } // anything else to do with cbRc? } @@ -1088,18 +1142,23 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, } -STDMETHODIMP EventSource::GetEvent(IEventListener * aListener, - LONG aTimeout, - IEvent ** aEvent) +STDMETHODIMP EventSource::GetEvent(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::iterator it = m->mListeners.find(aListener); HRESULT rc; @@ -1115,17 +1174,22 @@ STDMETHODIMP EventSource::GetEvent(IEventListener * aListener, return rc; } -STDMETHODIMP EventSource::EventProcessed(IEventListener * aListener, - IEvent * aEvent) +STDMETHODIMP EventSource::EventProcessed(IEventListener *aListener, + IEvent *aEvent) { CheckComArgNotNull(aListener); CheckComArgNotNull(aEvent); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::iterator it = m->mListeners.find(aListener); HRESULT rc; @@ -1134,11 +1198,11 @@ STDMETHODIMP EventSource::EventProcessed(IEventListener * aListener, if (it != m->mListeners.end()) { - ListenerRecord* aRecord = it->second.obj(); + ListenerRecord *aRecord = it->second.obj(); if (aRecord->isActive()) return setError(E_INVALIDARG, - tr("Only applicable to passive listeners")); + tr("Only applicable to passive listeners")); if (aWaitable) { @@ -1244,14 +1308,14 @@ public: BaseFinalRelease(); } - HRESULT init(IEventSource* aSource) + HRESULT init(IEventSource *aSource) { mSource = aSource; return S_OK; } // IEventListener methods - STDMETHOD(HandleEvent)(IEvent * aEvent) + STDMETHOD(HandleEvent)(IEvent *aEvent) { BOOL fProcessed = FALSE; if (mSource) @@ -1267,7 +1331,7 @@ class ATL_NO_VTABLE EventSourceAggregator : { typedef std::list > EventSourceList; /* key is weak reference */ - typedef std::map > ProxyListenerMap; + typedef std::map > ProxyListenerMap; EventSourceList mEventSources; ProxyListenerMap mListenerProxies; @@ -1306,28 +1370,28 @@ public: HRESULT init(ComSafeArrayIn(IEventSource *, aSources)); // IEventSource methods - STDMETHOD(CreateListener)(IEventListener ** aListener); - STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aAggregator); - STDMETHOD(RegisterListener)(IEventListener * aListener, + STDMETHOD(CreateListener)(IEventListener **aListener); + STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aAggregator); + STDMETHOD(RegisterListener)(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive); - STDMETHOD(UnregisterListener)(IEventListener * aListener); - STDMETHOD(FireEvent)(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed); - STDMETHOD(GetEvent)(IEventListener * aListener, - LONG aTimeout, - IEvent * *aEvent); - STDMETHOD(EventProcessed)(IEventListener * aListener, - IEvent * aEvent); + BOOL aActive); + STDMETHOD(UnregisterListener)(IEventListener *aListener); + STDMETHOD(FireEvent)(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed); + STDMETHOD(GetEvent)(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent); + STDMETHOD(EventProcessed)(IEventListener *aListener, + IEvent *aEvent); protected: - HRESULT createProxyListener(IEventListener * aListener, - IEventListener * *aProxy); - HRESULT getProxyListener (IEventListener * aListener, - IEventListener * *aProxy); - HRESULT removeProxyListener(IEventListener * aListener); + HRESULT createProxyListener(IEventListener *aListener, + IEventListener **aProxy); + HRESULT getProxyListener(IEventListener *aListener, + IEventListener **aProxy); + HRESULT removeProxyListener(IEventListener *aListener); }; #ifdef VBOX_WITH_XPCOM @@ -1346,47 +1410,48 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSourceAggregator, IEventSource) #endif -STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener) +STDMETHODIMP EventSource::CreateListener(IEventListener **aListener) { CheckComArgOutPointerValid(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); ComObjPtr listener; HRESULT rc = listener.createObject(); - ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rrc)", rc), + ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rhrc)", rc), E_FAIL); listener.queryInterfaceTo(aListener); return S_OK; } -STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aResult) +STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aResult) { CheckComArgOutPointerValid(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); ComObjPtr agg; HRESULT rc = agg.createObject(); - ComAssertMsgRet(SUCCEEDED(rc), ("Could not create aggregator (%Rrc)", rc), + ComAssertMsgRet(SUCCEEDED(rc), ("Could not create aggregator (%Rhrc)", rc), E_FAIL); rc = agg->init(ComSafeArrayInArg(aSubordinates)); if (FAILED(rc)) return rc; - agg.queryInterfaceTo(aResult); return S_OK; } -HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) +HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource *, aSourcesIn)) { HRESULT rc; @@ -1394,10 +1459,10 @@ HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) AssertReturn(autoInitSpan.isOk(), E_FAIL); rc = mSource.createObject(); - ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rrc)", rc), + ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rhrc)", rc), E_FAIL); - rc = mSource->init((IEventSource*)this); - ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rrc)", rc), + rc = mSource->init(); + ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rhrc)", rc), E_FAIL); com::SafeIfaceArray aSources(ComSafeArrayInArg (aSourcesIn)); @@ -1416,26 +1481,27 @@ HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) return rc; } -STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener ** aListener) +STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener **aListener) { return mSource->CreateListener(aListener); } -STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aResult) +STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aResult) { return mSource->CreateAggregator(ComSafeArrayInArg(aSubordinates), aResult); } -STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener * aListener, +STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive) + BOOL aActive) { CheckComArgNotNull(aListener); CheckComArgSafeArrayNotNull(aInterested); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc; @@ -1460,12 +1526,13 @@ STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener * aListener, return rc; } -STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener * aListener) +STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener *aListener) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc = S_OK; @@ -1488,19 +1555,20 @@ STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener * aListene } -STDMETHODIMP EventSourceAggregator::FireEvent(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed) +STDMETHODIMP EventSourceAggregator::FireEvent(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed) { CheckComArgNotNull(aEvent); CheckComArgOutPointerValid(aProcessed); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc = S_OK; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Aggresgator event source shalln't have direct event firing, but we may + /* Aggregator event source shall not have direct event firing, but we may wish to support aggregation chains */ for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end(); ++it) @@ -1515,26 +1583,26 @@ STDMETHODIMP EventSourceAggregator::FireEvent(IEvent * aEvent, return S_OK; } -STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener * aListener, - LONG aTimeout, - IEvent ** aEvent) +STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent) { return mSource->GetEvent(aListener, aTimeout, aEvent); } -STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener * aListener, - IEvent * aEvent) +STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener *aListener, + IEvent *aEvent) { return mSource->EventProcessed(aListener, aEvent); } -HRESULT EventSourceAggregator::createProxyListener(IEventListener * aListener, - IEventListener * *aProxy) +HRESULT EventSourceAggregator::createProxyListener(IEventListener *aListener, + IEventListener **aProxy) { ComObjPtr proxy; HRESULT rc = proxy.createObject(); - ComAssertMsgRet(SUCCEEDED(rc), ("Could not create proxy (%Rrc)", rc), + ComAssertMsgRet(SUCCEEDED(rc), ("Could not create proxy (%Rhrc)", rc), E_FAIL); rc = proxy->init(mSource); @@ -1552,8 +1620,8 @@ HRESULT EventSourceAggregator::createProxyListener(IEventListener * aListener, return S_OK; } -HRESULT EventSourceAggregator::getProxyListener(IEventListener * aListener, - IEventListener * *aProxy) +HRESULT EventSourceAggregator::getProxyListener(IEventListener *aListener, + IEventListener **aProxy) { ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener); if (it == mListenerProxies.end()) @@ -1564,7 +1632,7 @@ HRESULT EventSourceAggregator::getProxyListener(IEventListener * aListener, return S_OK; } -HRESULT EventSourceAggregator::removeProxyListener(IEventListener * aListener) +HRESULT EventSourceAggregator::removeProxyListener(IEventListener *aListener) { ProxyListenerMap::iterator it = mListenerProxies.find(aListener); if (it == mListenerProxies.end()) diff --git a/src/VBox/Main/src-all/ExtPackManagerImpl.cpp b/src/VBox/Main/src-all/ExtPackManagerImpl.cpp index 5b1a6929..7fcc55cd 100644 --- a/src/VBox/Main/src-all/ExtPackManagerImpl.cpp +++ b/src/VBox/Main/src-all/ExtPackManagerImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -44,8 +44,11 @@ #include "AutoCaller.h" #include "Global.h" #include "ProgressImpl.h" -#include "SystemPropertiesImpl.h" -#include "VirtualBoxImpl.h" +#if defined(VBOX_COM_INPROC) +# include "ConsoleImpl.h" +#else +# include "VirtualBoxImpl.h" +#endif /******************************************************************************* @@ -80,6 +83,7 @@ public: Utf8Str strWhyUnusable; }; +#if !defined(VBOX_COM_INPROC) /** * Private extension pack data. */ @@ -101,6 +105,7 @@ public: RTMEMEF_NEW_AND_DELETE_OPERATORS(); }; +#endif /** * Private extension pack data. @@ -150,8 +155,10 @@ struct ExtPackManager::Data Utf8Str strCertificatDirPath; /** The list of installed extension packs. */ ExtPackList llInstalledExtPacks; +#if !defined(VBOX_COM_INPROC) /** Pointer to the VirtualBox object, our parent. */ VirtualBox *pVirtualBox; +#endif /** The current context. */ VBOXEXTPACKCTX enmContext; #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) @@ -162,6 +169,7 @@ struct ExtPackManager::Data RTMEMEF_NEW_AND_DELETE_OPERATORS(); }; +#if !defined(VBOX_COM_INPROC) /** * Extension pack installation job. */ @@ -705,6 +713,7 @@ STDMETHODIMP ExtPackFile::Install(BOOL a_fReplace, IN_BSTR a_bstrDisplayInfo, IP return hrc; } +#endif @@ -749,6 +758,7 @@ HRESULT ExtPack::initWithDir(VBOXEXTPACKCTX a_enmContext, const char *a_pszName, /* pfnFindModule = */ ExtPack::hlpFindModule, /* pfnGetFilePath = */ ExtPack::hlpGetFilePath, /* pfnGetContext = */ ExtPack::hlpGetContext, + /* pfnLoadHGCMService = */ ExtPack::hlpLoadHGCMService, /* pfnReserved1 = */ ExtPack::hlpReservedN, /* pfnReserved2 = */ ExtPack::hlpReservedN, /* pfnReserved3 = */ ExtPack::hlpReservedN, @@ -757,7 +767,6 @@ HRESULT ExtPack::initWithDir(VBOXEXTPACKCTX a_enmContext, const char *a_pszName, /* pfnReserved6 = */ ExtPack::hlpReservedN, /* pfnReserved7 = */ ExtPack::hlpReservedN, /* pfnReserved8 = */ ExtPack::hlpReservedN, - /* pfnReserved9 = */ ExtPack::hlpReservedN, /* u32EndMarker = */ VBOXEXTPACKHLP_VERSION }; @@ -1105,6 +1114,28 @@ HRESULT ExtPack::getVrdpLibraryName(Utf8Str *a_pstrVrdeLibrary) return hrc; } +/** + * Resolves the path to the module. + * + * @returns S_OK or COM error status with error information. + * @param a_pszModuleName The library. + * @param a_pstrLibrary Where to return the path on success. + * + * @remarks Caller holds the extension manager lock for reading, no locking + * necessary. + */ +HRESULT ExtPack::getLibraryName(const char *a_pszModuleName, Utf8Str *a_pstrLibrary) +{ + HRESULT hrc; + if (findModule(a_pszModuleName, NULL, VBOXEXTPACKMODKIND_R3, + a_pstrLibrary, NULL /*a_pfNative*/, NULL /*a_pObjInfo*/)) + hrc = S_OK; + else + hrc = setError(E_FAIL, tr("Failed to locate the module '%s' in extension pack '%s'"), + a_pszModuleName, m->Desc.strName.c_str()); + return hrc; +} + /** * Check if this extension pack wishes to be the default VRDE provider. * @@ -1571,6 +1602,33 @@ ExtPack::hlpGetContext(PCVBOXEXTPACKHLP pHlp) return pThis->m->enmContext; } +/*static*/ DECLCALLBACK(int) +ExtPack::hlpLoadHGCMService(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + const char *pszServiceLibrary, const char *pszServiceName) +{ +#ifdef VBOX_COM_INPROC + /* + * Validate the input and get our bearings. + */ + AssertPtrReturn(pszServiceLibrary, VERR_INVALID_POINTER); + AssertPtrReturn(pszServiceName, VERR_INVALID_POINTER); + + AssertPtrReturn(pHlp, VERR_INVALID_POINTER); + AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER); + ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp); + AssertPtrReturn(m, VERR_INVALID_POINTER); + ExtPack *pThis = m->pThis; + AssertPtrReturn(pThis, VERR_INVALID_POINTER); + AssertPtrReturn(pConsole, VERR_INVALID_POINTER); + + Console *pCon = (Console *)pConsole; + return pCon->hgcmLoadService(pszServiceLibrary, pszServiceName); +#else + NOREF(pHlp); NOREF(pConsole); NOREF(pszServiceLibrary); NOREF(pszServiceName); +#endif + return VERR_INVALID_STATE; +} + /*static*/ DECLCALLBACK(int) ExtPack::hlpReservedN(PCVBOXEXTPACKHLP pHlp) { @@ -1883,7 +1941,9 @@ HRESULT ExtPackManager::initExtPackManager(VirtualBox *a_pVirtualBox, VBOXEXTPAC m = new Data; m->strBaseDir = szBaseDir; m->strCertificatDirPath = szCertificatDir; +#if !defined(VBOX_COM_INPROC) m->pVirtualBox = a_pVirtualBox; +#endif m->enmContext = a_enmContext; /* @@ -2034,6 +2094,7 @@ STDMETHODIMP ExtPackManager::OpenExtPackFile(IN_BSTR a_bstrTarballAndDigest, IEx CheckComArgOutPointerValid(a_ppExtPackFile); AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); +#if !defined(VBOX_COM_INPROC) /* The API can optionally take a ::SHA-256= attribute at the end of the file name. This is just a temporary measure for backporting, in 4.2 we'll add another parameter to the method. */ @@ -2057,6 +2118,9 @@ STDMETHODIMP ExtPackManager::OpenExtPackFile(IN_BSTR a_bstrTarballAndDigest, IEx NewExtPackFile.queryInterfaceTo(a_ppExtPackFile); return hrc; +#else + return E_NOTIMPL; +#endif } STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval, IN_BSTR a_bstrDisplayInfo, @@ -2067,6 +2131,7 @@ STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval *a_ppProgress = NULL; Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); +#if !defined(VBOX_COM_INPROC) AutoCaller autoCaller(this); HRESULT hrc = autoCaller.rc(); if (SUCCEEDED(hrc)) @@ -2115,6 +2180,9 @@ STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval } return hrc; +#else + return E_NOTIMPL; +#endif } STDMETHODIMP ExtPackManager::Cleanup(void) @@ -2448,6 +2516,7 @@ void ExtPackManager::removeExtPack(const char *a_pszName) AssertMsgFailed(("%s\n", a_pszName)); } +#if !defined(VBOX_COM_INPROC) /** * Refreshes the specified extension pack. * @@ -2670,7 +2739,7 @@ HRESULT ExtPackManager::doInstall(ExtPackFile *a_pExtPackFile, bool a_fReplace, LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str())); else { - LogRel(("ExtPackManager: Installated hook for '%s' failed: %Rrc - %s\n", + LogRel(("ExtPackManager: Installed hook for '%s' failed: %Rrc - %s\n", pStrName->c_str(), ErrInfo.Core.rc, ErrInfo.Core.pszMsg)); /* @@ -2848,6 +2917,7 @@ void ExtPackManager::callAllVirtualBoxReadyHooks(void) it++; } } +#endif /** * Calls the pfnConsoleReady hook for all working extension packs. @@ -2875,6 +2945,7 @@ void ExtPackManager::callAllConsoleReadyHooks(IConsole *a_pConsole) } } +#if !defined(VBOX_COM_INPROC) /** * Calls the pfnVMCreated hook for all working extension packs. * @@ -2893,6 +2964,7 @@ void ExtPackManager::callAllVmCreatedHooks(IMachine *a_pMachine) for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); it++) (*it)->callVmCreatedHook(m->pVirtualBox, a_pMachine, &autoLock); } +#endif /** * Calls the pfnVMConfigureVMM hook for all working extension packs. @@ -3027,6 +3099,33 @@ int ExtPackManager::getVrdeLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, U return hrc; } +/** + * Gets the full path to the specified library of the specified extension pack. + * + * @returns S_OK if a path is returned, COM error status and message return if + * not. + * @param a_pszModuleName The library. + * @param a_pstrExtPack The extension pack. + * @param a_pstrVrdeLibrary Where to return the path. + */ +HRESULT ExtPackManager::getLibraryPathForExtPack(const char *a_pszModuleName, Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrLibrary) +{ + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); + + ExtPack *pExtPack = findExtPack(a_pstrExtPack->c_str()); + if (pExtPack) + hrc = pExtPack->getLibraryName(a_pszModuleName, a_pstrLibrary); + else + hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pstrExtPack->c_str()); + } + + return hrc; +} + /** * Gets the name of the default VRDE extension pack. * diff --git a/src/VBox/Main/src-all/ExtPackUtil.cpp b/src/VBox/Main/src-all/ExtPackUtil.cpp index c7a1dacb..3e7aaf92 100644 --- a/src/VBox/Main/src-all/ExtPackUtil.cpp +++ b/src/VBox/Main/src-all/ExtPackUtil.cpp @@ -322,7 +322,7 @@ RTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a if (RT_SUCCESS(rc)) { xml::XmlMemParser Parser; - RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME; + RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME; try { Parser.read(pvFile, cbFile, strFileName, Doc); diff --git a/src/VBox/Main/src-all/Global.cpp b/src/VBox/Main/src-all/Global.cpp index 6ae03726..fdfac74b 100644 --- a/src/VBox/Main/src-all/Global.cpp +++ b/src/VBox/Main/src-all/Global.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2012 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,13 +26,17 @@ /* static */ const Global::OSType Global::sOSTypes[] = { - /* NOTE1: we assume that unknown is always the first entry! + /* NOTE1: we assume that unknown is always the first two entries! * NOTE2: please use powers of 2 when specifying the size of harddisks since * '2GB' looks better than '1.95GB' (= 2000MB) */ { "Other", "Other", "Other", "Other/Unknown", VBOXOSTYPE_Unknown, VBOXOSHINT_NONE, 64, 4, 2 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, + { "Other", "Other", "Other_64", "Other/Unknown (64-bit)", + VBOXOSTYPE_Unknown_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC, + 64, 4, 2 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, + StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Windows", "Microsoft Windows", "Windows31", "Windows 3.1", VBOXOSTYPE_Win31, VBOXOSHINT_FLOPPY, 32, 4, 1 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, @@ -57,7 +61,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Win2k, VBOXOSHINT_USBTABLET, 168, 16, 4 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Windows", "Microsoft Windows", "WindowsXP", "Windows XP", + { "Windows", "Microsoft Windows", "WindowsXP", "Windows XP (32 bit)", VBOXOSTYPE_WinXP, VBOXOSHINT_USBTABLET, 192, 16, 10 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -65,7 +69,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_WinXP_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 192, 16, 10 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Windows", "Microsoft Windows", "Windows2003", "Windows 2003", + { "Windows", "Microsoft Windows", "Windows2003", "Windows 2003 (32 bit)", VBOXOSTYPE_Win2k3, VBOXOSHINT_USBTABLET, 256, 16, 20 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -73,7 +77,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Win2k3_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 256, 16, 20 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_HDA }, - { "Windows", "Microsoft Windows", "WindowsVista", "Windows Vista", + { "Windows", "Microsoft Windows", "WindowsVista", "Windows Vista (32 bit)", VBOXOSTYPE_WinVista, VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, @@ -81,7 +85,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_WinVista_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, - { "Windows", "Microsoft Windows", "Windows2008", "Windows 2008", + { "Windows", "Microsoft Windows", "Windows2008", "Windows 2008 (32 bit)", VBOXOSTYPE_Win2k8, VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, @@ -89,7 +93,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Win2k8_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, - { "Windows", "Microsoft Windows", "Windows7", "Windows 7", + { "Windows", "Microsoft Windows", "Windows7", "Windows 7 (32 bit)", VBOXOSTYPE_Win7, VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, @@ -97,7 +101,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Win7_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 512, 16, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, - { "Windows", "Microsoft Windows", "Windows8", "Windows 8", + { "Windows", "Microsoft Windows", "Windows8", "Windows 8 (32 bit)", VBOXOSTYPE_Win8, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET | VBOXOSHINT_PAE, 1024,128, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, @@ -105,19 +109,31 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Win8_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 2048,128, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, + { "Windows", "Microsoft Windows", "Windows81", "Windows 8.1 (32 bit)", + VBOXOSTYPE_Win8, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET | VBOXOSHINT_PAE, + 1024,128, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, + { "Windows", "Microsoft Windows", "Windows81_64", "Windows 8.1 (64 bit)", + VBOXOSTYPE_Win8_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, + 2048,128, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, { "Windows", "Microsoft Windows", "Windows2012_64", "Windows 2012 (64 bit)", VBOXOSTYPE_Win2k12_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 2048,128, 25 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_HDA }, - { "Windows", "Microsoft Windows", "WindowsNT", "Other Windows", + { "Windows", "Microsoft Windows", "WindowsNT", "Other Windows (32 bit)", VBOXOSTYPE_WinNT, VBOXOSHINT_NONE, 512, 16, 20 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, + { "Windows", "Microsoft Windows", "WindowsNT_64", "Other Windows (64-bit)", + VBOXOSTYPE_WinNT_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, + 512, 16, 20 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Linux", "Linux", "Linux22", "Linux 2.2", VBOXOSTYPE_Linux22, VBOXOSHINT_RTCUTC, 64, 4, 2 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Linux24", "Linux 2.4", + { "Linux", "Linux", "Linux24", "Linux 2.4 (32 bit)", VBOXOSTYPE_Linux24, VBOXOSHINT_RTCUTC, 128, 4, 4 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -125,31 +141,31 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Linux24_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, 128, 4, 4 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Linux26", "Linux 2.6", + { "Linux", "Linux", "Linux26", "Linux 2.6 / 3.x (32 bit)", VBOXOSTYPE_Linux26, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 4, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Linux26_64", "Linux 2.6 (64 bit)", + { "Linux", "Linux", "Linux26_64", "Linux 2.6 / 3.x (64 bit)", VBOXOSTYPE_Linux26_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 4, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "ArchLinux", "Arch Linux", + { "Linux", "Linux", "ArchLinux", "Arch Linux (32 bit)", VBOXOSTYPE_ArchLinux, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Linux", "Linux", "ArchLinux_64", "Arch Linux (64 bit)", VBOXOSTYPE_ArchLinux_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Debian", "Debian", + { "Linux", "Linux", "Debian", "Debian (32 bit)", VBOXOSTYPE_Debian, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 384, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Linux", "Linux", "Debian_64", "Debian (64 bit)", VBOXOSTYPE_Debian_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 384, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97}, - { "Linux", "Linux", "OpenSUSE", "openSUSE", + { "Linux", "Linux", "OpenSUSE", "openSUSE (32 bit)", VBOXOSTYPE_OpenSUSE, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -157,7 +173,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_OpenSUSE_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Fedora", "Fedora", + { "Linux", "Linux", "Fedora", "Fedora (32 bit)", VBOXOSTYPE_FedoraCore, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 768, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -165,15 +181,15 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_FedoraCore_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 768, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Gentoo", "Gentoo", + { "Linux", "Linux", "Gentoo", "Gentoo (32 bit)", VBOXOSTYPE_Gentoo, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Linux", "Linux", "Gentoo_64", "Gentoo (64 bit)", VBOXOSTYPE_Gentoo_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Mandriva", "Mandriva", + { "Linux", "Linux", "Mandriva", "Mandriva (32 bit)", VBOXOSTYPE_Mandriva, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -181,7 +197,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Mandriva_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "RedHat", "Red Hat", + { "Linux", "Linux", "RedHat", "Red Hat (32 bit)", VBOXOSTYPE_RedHat, VBOXOSHINT_RTCUTC | VBOXOSHINT_PAE, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -189,7 +205,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_RedHat_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Turbolinux", "Turbolinux", + { "Linux", "Linux", "Turbolinux", "Turbolinux (32 bit)", VBOXOSTYPE_Turbolinux, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 384, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -197,7 +213,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Turbolinux_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 384, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Ubuntu", "Ubuntu", + { "Linux", "Linux", "Ubuntu", "Ubuntu (32 bit)", VBOXOSTYPE_Ubuntu, VBOXOSHINT_RTCUTC | VBOXOSHINT_PAE | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -205,7 +221,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Ubuntu_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Xandros", "Xandros", + { "Linux", "Linux", "Xandros", "Xandros (32 bit)", VBOXOSTYPE_Xandros, VBOXOSHINT_RTCUTC, 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -213,7 +229,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Xandros_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, 256, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Oracle", "Oracle", + { "Linux", "Linux", "Oracle", "Oracle (32 bit)", VBOXOSTYPE_Oracle, VBOXOSHINT_RTCUTC | VBOXOSHINT_PAE, 512, 12, 12 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -221,11 +237,15 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Oracle_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, 512, 12, 12 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Linux", "Linux", "Linux", "Other Linux", + { "Linux", "Linux", "Linux", "Other Linux (32 bit)", VBOXOSTYPE_Linux, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, 256, 12, 8 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Solaris", "Solaris", "Solaris", "Oracle Solaris 10 5/09 and earlier", + { "Linux", "Linux", "Linux_64", "Other Linux (64-bit)", + VBOXOSTYPE_Linux_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 512, 12, 8 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, + { "Solaris", "Solaris", "Solaris", "Oracle Solaris 10 5/09 and earlier (32 bit)", VBOXOSTYPE_Solaris, VBOXOSHINT_NONE, 768, 12, 16 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -233,7 +253,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Solaris_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC, 1536, 12, 16 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "Solaris", "Solaris", "OpenSolaris", "Oracle Solaris 10 10/09 and later", + { "Solaris", "Solaris", "OpenSolaris", "Oracle Solaris 10 10/09 and later (32 bit)", VBOXOSTYPE_OpenSolaris, VBOXOSHINT_USBTABLET, 768, 12, 16 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -245,7 +265,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_Solaris11_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET, 1536, 12, 16 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "BSD", "BSD", "FreeBSD", "FreeBSD", + { "BSD", "BSD", "FreeBSD", "FreeBSD (32 bit)", VBOXOSTYPE_FreeBSD, VBOXOSHINT_NONE, 128, 4, 2 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -253,7 +273,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_FreeBSD_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC, 128, 4, 2 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "BSD", "BSD", "OpenBSD", "OpenBSD", + { "BSD", "BSD", "OpenBSD", "OpenBSD (32 bit)", VBOXOSTYPE_OpenBSD, VBOXOSHINT_HWVIRTEX, 64, 4, 2 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -261,7 +281,7 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_OpenBSD_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC, 64, 4, 2 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, - { "BSD", "BSD", "NetBSD", "NetBSD", + { "BSD", "BSD", "NetBSD", "NetBSD (32 bit)", VBOXOSTYPE_NetBSD, VBOXOSHINT_NONE, 64, 4, 2 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, @@ -289,15 +309,47 @@ const Global::OSType Global::sOSTypes[] = VBOXOSTYPE_OS2, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_FLOPPY | VBOXOSHINT_NOUSB, 96, 4, 2 * _1G64, NetworkAdapterType_Am79C973, 1, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_SB16 }, - { "MacOS", "Mac OS X", "MacOS", "Mac OS X", - VBOXOSTYPE_MacOS, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_USBTABLET, - 2048, 4, 20 * _1G64, NetworkAdapterType_I82543GC, 0, - StorageControllerType_ICH6, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, + { "MacOS", "Mac OS X", "MacOS", "Mac OS X (32 bit)", + VBOXOSTYPE_MacOS, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_ICH9, AudioControllerType_HDA }, { "MacOS", "Mac OS X", "MacOS_64", "Mac OS X (64 bit)", - VBOXOSTYPE_MacOS_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_USBTABLET, - 2048, 4, 20 * _1G64, NetworkAdapterType_I82543GC, 0, - StorageControllerType_ICH6, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA, + VBOXOSTYPE_MacOS_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, + ChipsetType_ICH9, AudioControllerType_HDA }, + { "MacOS", "Mac OS X", "MacOS106", "Mac OS X 10.6 Snow Leopard (32 bit)", + VBOXOSTYPE_MacOS106, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, + ChipsetType_ICH9, AudioControllerType_HDA }, + { "MacOS", "Mac OS X", "MacOS106_64", "Mac OS X 10.6 Snow Leopard (64 bit)", + VBOXOSTYPE_MacOS106_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, + ChipsetType_ICH9, AudioControllerType_HDA }, + { "MacOS", "Mac OS X", "MacOS107_64", "Mac OS X 10.7 Lion (64 bit)", + VBOXOSTYPE_MacOS107_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, + ChipsetType_ICH9, AudioControllerType_HDA }, + { "MacOS", "Mac OS X", "MacOS108_64", "Mac OS X 10.8 Mountain Lion (64 bit)", /* Aka "Mountain Kitten". */ + VBOXOSTYPE_MacOS108_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, + ChipsetType_ICH9, AudioControllerType_HDA }, + { "MacOS", "Mac OS X", "MacOS109_64", "Mac OS X 10.9 Mavericks (64 bit)", /* Not to be confused with McCain. */ + VBOXOSTYPE_MacOS109_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT + | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, + 2048, 4, 20 * _1G64, NetworkAdapterType_I82545EM, 0, + StorageControllerType_IntelAhci, StorageBus_SATA, StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_ICH9, AudioControllerType_HDA }, { "Other", "Other", "DOS", "DOS", VBOXOSTYPE_DOS, VBOXOSHINT_FLOPPY | VBOXOSHINT_NOUSB, @@ -312,7 +364,11 @@ const Global::OSType Global::sOSTypes[] = 64, 4, 2 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Other", "Other", "QNX", "QNX", +#ifdef VBOX_WITH_RAW_RING1 + VBOXOSTYPE_QNX, VBOXOSHINT_NONE, +#else VBOXOSTYPE_QNX, VBOXOSHINT_HWVIRTEX, +#endif 512, 4, 4 * _1G64, NetworkAdapterType_Am79C973, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE, ChipsetType_PIIX3, AudioControllerType_AC97 }, { "Other", "Other", "JRockitVE", "JRockitVE", @@ -434,6 +490,26 @@ Global::stringifyDeviceType(DeviceType_T aType) } } + +/*static*/ const char * +Global::stringifyReason(Reason_T aReason) +{ + switch (aReason) + { + case Reason_Unspecified: return "unspecified"; + case Reason_HostSuspend: return "host suspend"; + case Reason_HostResume: return "host resume"; + case Reason_HostBatteryLow: return "host battery low"; + default: + { + AssertMsgFailed(("%d (%#x)\n", aReason, aReason)); + static char s_szMsg[48]; + RTStrPrintf(s_szMsg, sizeof(s_szMsg), "invalid reason %#010x\n", aReason); + return s_szMsg; + } + } +} + /*static*/ int Global::vboxStatusCodeFromCOM(HRESULT aComStatus) { diff --git a/src/VBox/Main/src-all/Logging.cpp b/src/VBox/Main/src-all/Logging.cpp index 5b4095e6..21f9de65 100644 --- a/src/VBox/Main/src-all/Logging.cpp +++ b/src/VBox/Main/src-all/Logging.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/ProgressImpl.cpp b/src/VBox/Main/src-all/ProgressImpl.cpp index 3d78b2bc..fa3ecea8 100644 --- a/src/VBox/Main/src-all/ProgressImpl.cpp +++ b/src/VBox/Main/src-all/ProgressImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -18,15 +18,18 @@ #include + #if defined(VBOX_WITH_XPCOM) #include #include #include #endif /* defined(VBOX_WITH_XPCOM) */ -#include "ProgressCombinedImpl.h" +#include "ProgressImpl.h" -#include "VirtualBoxImpl.h" +#if !defined(VBOX_COM_INPROC) +# include "VirtualBoxImpl.h" +#endif #include "VirtualBoxErrorInfoImpl.h" #include "Logging.h" @@ -36,181 +39,25 @@ #include #include +#include "AutoCaller.h" -//////////////////////////////////////////////////////////////////////////////// -// ProgressBase class -//////////////////////////////////////////////////////////////////////////////// - -// constructor / destructor -//////////////////////////////////////////////////////////////////////////////// -ProgressBase::ProgressBase() +Progress::Progress() #if !defined(VBOX_COM_INPROC) : mParent(NULL) #endif { } -ProgressBase::~ProgressBase() -{ -} - - -/** - * Subclasses must call this method from their FinalConstruct() implementations. - */ -HRESULT ProgressBase::FinalConstruct() -{ - mCancelable = FALSE; - mCompleted = FALSE; - mCanceled = FALSE; - mResultCode = S_OK; - - m_cOperations - = m_ulTotalOperationsWeight - = m_ulOperationsCompletedWeight - = m_ulCurrentOperation - = m_ulCurrentOperationWeight - = m_ulOperationPercent - = m_cMsTimeout - = 0; - - // get creation timestamp - m_ullTimestamp = RTTimeMilliTS(); - - m_pfnCancelCallback = NULL; - m_pvCancelUserArg = NULL; - - return BaseFinalConstruct(); -} - -// protected initializer/uninitializer for internal purposes only -//////////////////////////////////////////////////////////////////////////////// - -/** - * Initializes the progress base object. - * - * Subclasses should call this or any other #protectedInit() method from their - * init() implementations. - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - * @param aParent Parent object (only for server-side Progress objects). - * @param aInitiator Initiator of the task (for server-side objects. Can be - * NULL which means initiator = parent, otherwise must not - * be NULL). - * @param aDescription ask description. - * @param aID Address of result GUID structure (optional). - * - * @return COM result indicator. - */ -HRESULT ProgressBase::protectedInit(AutoInitSpan &aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - OUT_GUID aId /* = NULL */) -{ - /* Guarantees subclasses call this method at the proper time */ - NOREF(aAutoInitSpan); - - AutoCaller autoCaller(this); - AssertReturn(autoCaller.state() == InInit, E_FAIL); - -#if !defined(VBOX_COM_INPROC) - AssertReturn(aParent, E_INVALIDARG); -#else - AssertReturn(aInitiator, E_INVALIDARG); -#endif - - AssertReturn(aDescription, E_INVALIDARG); - -#if !defined(VBOX_COM_INPROC) - /* share parent weakly */ - unconst(mParent) = aParent; -#endif - -#if !defined(VBOX_COM_INPROC) - /* assign (and therefore addref) initiator only if it is not VirtualBox - * (to avoid cycling); otherwise mInitiator will remain null which means - * that it is the same as the parent */ - if (aInitiator) - { - ComObjPtr pVirtualBox(mParent); - if (!(pVirtualBox == aInitiator)) - unconst(mInitiator) = aInitiator; - } -#else - unconst(mInitiator) = aInitiator; -#endif - - unconst(mId).create(); - if (aId) - mId.cloneTo(aId); - -#if !defined(VBOX_COM_INPROC) - /* add to the global collection of progress operations (note: after - * creating mId) */ - mParent->addProgress(this); -#endif - - unconst(mDescription) = aDescription; - - return S_OK; -} - -/** - * Initializes the progress base object. - * - * This is a special initializer that doesn't initialize any field. Used by one - * of the Progress::init() forms to create sub-progress operations combined - * together using a CombinedProgress instance, so it doesn't require the parent, - * initiator, description and doesn't create an ID. - * - * Subclasses should call this or any other #protectedInit() method from their - * init() implementations. - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - */ -HRESULT ProgressBase::protectedInit(AutoInitSpan &aAutoInitSpan) +Progress::~Progress() { - /* Guarantees subclasses call this method at the proper time */ - NOREF(aAutoInitSpan); - - return S_OK; } -/** - * Uninitializes the instance. - * - * Subclasses should call this from their uninit() implementations. - * - * @param aAutoUninitSpan AutoUninitSpan object instantiated by a subclass. - * - * @note Using the mParent member after this method returns is forbidden. - */ -void ProgressBase::protectedUninit(AutoUninitSpan &aAutoUninitSpan) -{ - /* release initiator (effective only if mInitiator has been assigned in - * init()) */ - unconst(mInitiator).setNull(); - -#if !defined(VBOX_COM_INPROC) - if (mParent) - { - /* remove the added progress on failure to complete the initialization */ - if (aAutoUninitSpan.initFailed() && !mId.isEmpty()) - mParent->removeProgress(mId.ref()); - - unconst(mParent) = NULL; - } -#endif -} // IProgress properties ///////////////////////////////////////////////////////////////////////////// -STDMETHODIMP ProgressBase::COMGETTER(Id)(BSTR *aId) +STDMETHODIMP Progress::COMGETTER(Id)(BSTR *aId) { CheckComArgOutPointerValid(aId); @@ -223,7 +70,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Id)(BSTR *aId) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Description)(BSTR *aDescription) +STDMETHODIMP Progress::COMGETTER(Description)(BSTR *aDescription) { CheckComArgOutPointerValid(aDescription); @@ -236,7 +83,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Description)(BSTR *aDescription) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Initiator)(IUnknown **aInitiator) +STDMETHODIMP Progress::COMGETTER(Initiator)(IUnknown **aInitiator) { CheckComArgOutPointerValid(aInitiator); @@ -260,7 +107,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Initiator)(IUnknown **aInitiator) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Cancelable)(BOOL *aCancelable) +STDMETHODIMP Progress::COMGETTER(Cancelable)(BOOL *aCancelable) { CheckComArgOutPointerValid(aCancelable); @@ -283,7 +130,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Cancelable)(BOOL *aCancelable) * * @return fractional percentage as a double value. */ -double ProgressBase::calcTotalPercent() +double Progress::calcTotalPercent() { // avoid division by zero if (m_ulTotalOperationsWeight == 0) @@ -301,7 +148,7 @@ double ProgressBase::calcTotalPercent() * * The caller should hold the object write lock. */ -void ProgressBase::checkForAutomaticTimeout(void) +void Progress::checkForAutomaticTimeout(void) { if ( m_cMsTimeout && mCancelable @@ -312,7 +159,7 @@ void ProgressBase::checkForAutomaticTimeout(void) } -STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) +STDMETHODIMP Progress::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) { CheckComArgOutPointerValid(aTimeRemaining); @@ -335,7 +182,7 @@ STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) uint64_t ullTimeTotal = (uint64_t)(ullTimeElapsed * 100 / dPercentDone); uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed; -// Log(("ProgressBase::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", +// Log(("Progress::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", // (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining)); *aTimeRemaining = (LONG)(ullTimeRemaining / 1000); @@ -345,7 +192,7 @@ STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Percent)(ULONG *aPercent) +STDMETHODIMP Progress::COMGETTER(Percent)(ULONG *aPercent) { CheckComArgOutPointerValid(aPercent); @@ -378,7 +225,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Percent)(ULONG *aPercent) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Completed)(BOOL *aCompleted) +STDMETHODIMP Progress::COMGETTER(Completed)(BOOL *aCompleted) { CheckComArgOutPointerValid(aCompleted); @@ -392,7 +239,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Completed)(BOOL *aCompleted) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Canceled)(BOOL *aCanceled) +STDMETHODIMP Progress::COMGETTER(Canceled)(BOOL *aCanceled) { CheckComArgOutPointerValid(aCanceled); @@ -406,7 +253,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Canceled)(BOOL *aCanceled) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(ResultCode)(LONG *aResultCode) +STDMETHODIMP Progress::COMGETTER(ResultCode)(LONG *aResultCode) { CheckComArgOutPointerValid(aResultCode); @@ -424,7 +271,7 @@ STDMETHODIMP ProgressBase::COMGETTER(ResultCode)(LONG *aResultCode) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) +STDMETHODIMP Progress::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) { CheckComArgOutPointerValid(aErrorInfo); @@ -442,7 +289,7 @@ STDMETHODIMP ProgressBase::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInf return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationCount)(ULONG *aOperationCount) +STDMETHODIMP Progress::COMGETTER(OperationCount)(ULONG *aOperationCount) { CheckComArgOutPointerValid(aOperationCount); @@ -456,7 +303,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationCount)(ULONG *aOperationCount) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Operation)(ULONG *aOperation) +STDMETHODIMP Progress::COMGETTER(Operation)(ULONG *aOperation) { CheckComArgOutPointerValid(aOperation); @@ -470,7 +317,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Operation)(ULONG *aOperation) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationDescription)(BSTR *aOperationDescription) +STDMETHODIMP Progress::COMGETTER(OperationDescription)(BSTR *aOperationDescription) { CheckComArgOutPointerValid(aOperationDescription); @@ -484,7 +331,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationDescription)(BSTR *aOperationDescr return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationPercent)(ULONG *aOperationPercent) +STDMETHODIMP Progress::COMGETTER(OperationPercent)(ULONG *aOperationPercent) { CheckComArgOutPointerValid(aOperationPercent); @@ -501,7 +348,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationPercent)(ULONG *aOperationPercent) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationWeight)(ULONG *aOperationWeight) +STDMETHODIMP Progress::COMGETTER(OperationWeight)(ULONG *aOperationWeight) { CheckComArgOutPointerValid(aOperationWeight); @@ -515,7 +362,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationWeight)(ULONG *aOperationWeight) return S_OK; } -STDMETHODIMP ProgressBase::COMSETTER(Timeout)(ULONG aTimeout) +STDMETHODIMP Progress::COMSETTER(Timeout)(ULONG aTimeout) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -531,7 +378,7 @@ STDMETHODIMP ProgressBase::COMSETTER(Timeout)(ULONG aTimeout) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Timeout)(ULONG *aTimeout) +STDMETHODIMP Progress::COMGETTER(Timeout)(ULONG *aTimeout) { CheckComArgOutPointerValid(aTimeout); @@ -558,7 +405,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Timeout)(ULONG *aTimeout) * @param pfnCallback The function to be called upon cancelation. * @param pvUser The callback argument. */ -bool ProgressBase::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) +bool Progress::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) { AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), false); @@ -574,13 +421,29 @@ bool ProgressBase::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) return true; } -//////////////////////////////////////////////////////////////////////////////// -// Progress class -//////////////////////////////////////////////////////////////////////////////// - HRESULT Progress::FinalConstruct() { - HRESULT rc = ProgressBase::FinalConstruct(); + mCancelable = FALSE; + mCompleted = FALSE; + mCanceled = FALSE; + mResultCode = S_OK; + + m_cOperations + = m_ulTotalOperationsWeight + = m_ulOperationsCompletedWeight + = m_ulCurrentOperation + = m_ulCurrentOperationWeight + = m_ulOperationPercent + = m_cMsTimeout + = 0; + + // get creation timestamp + m_ullTimestamp = RTTimeMilliTS(); + + m_pfnCancelCallback = NULL; + m_pvCancelUserArg = NULL; + + HRESULT rc = Progress::BaseFinalConstruct(); if (FAILED(rc)) return rc; mCompletedSem = NIL_RTSEMEVENTMULTI; @@ -636,16 +499,16 @@ void Progress::FinalRelease() * Even simpler, if you need no sub-operations at all, pass in cOperations = * ulTotalOperationsWeight = ulFirstOperationWeight = 1. * - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). + * @param aParent See Progress::init(). + * @param aInitiator See Progress::init(). + * @param aDescription See Progress::init(). * @param aCancelable Flag whether the task maybe canceled. * @param cOperations Number of operations within this task (at least 1). * @param ulTotalOperationsWeight Total weight of operations; must be the sum of ulFirstOperationWeight and * what is later passed with each subsequent setNextOperation() call. * @param bstrFirstOperationDescription Description of the first operation. * @param ulFirstOperationWeight Weight of first sub-operation. - * @param aId See ProgressBase::init(). + * @param aId See Progress::init(). */ HRESULT Progress::init( #if !defined(VBOX_COM_INPROC) @@ -676,11 +539,55 @@ HRESULT Progress::init( HRESULT rc = S_OK; - rc = ProgressBase::protectedInit(autoInitSpan, +// rc = Progress::init( +//#if !defined(VBOX_COM_INPROC) +// aParent, +//#endif +// aInitiator, aDescription, FALSE, aId); +// NA +#if !defined(VBOX_COM_INPROC) + AssertReturn(aParent, E_INVALIDARG); +#else + AssertReturn(aInitiator, E_INVALIDARG); +#endif + + AssertReturn(aDescription, E_INVALIDARG); + +#if !defined(VBOX_COM_INPROC) + /* share parent weakly */ + unconst(mParent) = aParent; +#endif + +#if !defined(VBOX_COM_INPROC) + /* assign (and therefore addref) initiator only if it is not VirtualBox + * * (to avoid cycling); otherwise mInitiator will remain null which means + * * that it is the same as the parent */ + if (aInitiator) + { + ComObjPtr pVirtualBox(mParent); + if (!(pVirtualBox == aInitiator)) + unconst(mInitiator) = aInitiator; + } +#else + unconst(mInitiator) = aInitiator; +#endif + + unconst(mId).create(); + if (aId) + mId.cloneTo(aId); + #if !defined(VBOX_COM_INPROC) - aParent, + /* add to the global collection of progress operations (note: after + * * creating mId) */ + mParent->addProgress(this); #endif - aInitiator, aDescription, aId); + + unconst(mDescription) = aDescription; + + +// end of assertion + + if (FAILED(rc)) return rc; mCancelable = aCancelable; @@ -710,7 +617,7 @@ HRESULT Progress::init( * the whole task. * * Objects initialized with this method are then combined together into the - * single task using a CombinedProgress instance, so it doesn't require the + * single task using a Progress instance, so it doesn't require the * parent, initiator, description and doesn't create an ID. Note that calling * respective getter methods on an object initialized with this method is * useless. Such objects are used only to provide a separate wait semaphore and @@ -731,8 +638,9 @@ HRESULT Progress::init(BOOL aCancelable, AssertReturn(autoInitSpan.isOk(), E_FAIL); HRESULT rc = S_OK; + /* Guarantees subclasses call this method at the proper time */ + NOREF(autoInitSpan); - rc = ProgressBase::protectedInit(autoInitSpan); if (FAILED(rc)) return rc; mCancelable = aCancelable; @@ -759,6 +667,7 @@ HRESULT Progress::init(BOOL aCancelable, return rc; } + /** * Uninitializes the instance and sets the ready flag to FALSE. * @@ -783,9 +692,23 @@ void Progress::uninit() RTSemEventMultiDestroy(mCompletedSem); - ProgressBase::protectedUninit(autoUninitSpan); + /* release initiator (effective only if mInitiator has been assigned in + * * init()) */ + unconst(mInitiator).setNull(); + +#if !defined(VBOX_COM_INPROC) + if (mParent) + { + /* remove the added progress on failure to complete the initialization */ + if (autoUninitSpan.initFailed() && mId.isValid() && !mId.isZero()) + mParent->removeProgress(mId.ref()); + + unconst(mParent) = NULL; + } +#endif } + // IProgress properties ///////////////////////////////////////////////////////////////////////////// @@ -962,7 +885,7 @@ STDMETHODIMP Progress::WaitForAsyncProgressCompletion(IProgress *pProgressAsync) * in the meantime more than one async operation was finished. So we * have to loop as long as we reached the same operation count. */ ULONG curOp; - for(;;) + for (;;) { rc = pProgressAsync->COMGETTER(Operation(&curOp)); if (FAILED(rc)) return rc; @@ -1321,571 +1244,3 @@ bool Progress::notifyPointOfNoReturn(void) return true; } -//////////////////////////////////////////////////////////////////////////////// -// CombinedProgress class -//////////////////////////////////////////////////////////////////////////////// - -HRESULT CombinedProgress::FinalConstruct() -{ - HRESULT rc = ProgressBase::FinalConstruct(); - if (FAILED(rc)) return rc; - - mProgress = 0; - mCompletedOperations = 0; - - return BaseFinalConstruct(); -} - -void CombinedProgress::FinalRelease() -{ - uninit(); - BaseFinalRelease(); -} - -// public initializer/uninitializer for internal purposes only -//////////////////////////////////////////////////////////////////////////////// - -/** - * Initializes this object based on individual combined progresses. - * Must be called only from #init()! - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). - * @param aId See ProgressBase::init(). - */ -HRESULT CombinedProgress::protectedInit(AutoInitSpan &aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, OUT_GUID aId) -{ - LogFlowThisFunc(("aDescription={%ls} mProgresses.size()=%d\n", - aDescription, mProgresses.size())); - - HRESULT rc = S_OK; - - rc = ProgressBase::protectedInit(aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - aParent, -#endif - aInitiator, aDescription, aId); - if (FAILED(rc)) return rc; - - mProgress = 0; /* the first object */ - mCompletedOperations = 0; - - mCompleted = FALSE; - mCancelable = TRUE; /* until any progress returns FALSE */ - mCanceled = FALSE; - - m_cOperations = 0; /* will be calculated later */ - - m_ulCurrentOperation = 0; - rc = mProgresses[0]->COMGETTER(OperationDescription)(m_bstrOperationDescription.asOutParam()); - if (FAILED(rc)) return rc; - - for (size_t i = 0; i < mProgresses.size(); i ++) - { - if (mCancelable) - { - BOOL cancelable = FALSE; - rc = mProgresses[i]->COMGETTER(Cancelable)(&cancelable); - if (FAILED(rc)) return rc; - - if (!cancelable) - mCancelable = FALSE; - } - - { - ULONG opCount = 0; - rc = mProgresses[i]->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) return rc; - - m_cOperations += opCount; - } - } - - rc = checkProgress(); - if (FAILED(rc)) return rc; - - return rc; -} - -/** - * Initializes the combined progress object given two normal progress - * objects. - * - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). - * @param aProgress1 First normal progress object. - * @param aProgress2 Second normal progress object. - * @param aId See ProgressBase::init(). - */ -HRESULT CombinedProgress::init( -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - IProgress *aProgress1, - IProgress *aProgress2, - OUT_GUID aId /* = NULL */) -{ - /* Enclose the state transition NotReady->InInit->Ready */ - AutoInitSpan autoInitSpan(this); - AssertReturn(autoInitSpan.isOk(), E_FAIL); - - mProgresses.resize(2); - mProgresses[0] = aProgress1; - mProgresses[1] = aProgress2; - - HRESULT rc = protectedInit(autoInitSpan, -#if !defined(VBOX_COM_INPROC) - aParent, -#endif - aInitiator, - aDescription, - aId); - - /* Confirm a successful initialization when it's the case */ - if (SUCCEEDED(rc)) - autoInitSpan.setSucceeded(); - - return rc; -} - -/** - * Uninitializes the instance and sets the ready flag to FALSE. - * - * Called either from FinalRelease() or by the parent when it gets destroyed. - */ -void CombinedProgress::uninit() -{ - LogFlowThisFunc(("\n")); - - /* Enclose the state transition Ready->InUninit->NotReady */ - AutoUninitSpan autoUninitSpan(this); - if (autoUninitSpan.uninitDone()) - return; - - mProgress = 0; - mProgresses.clear(); - - ProgressBase::protectedUninit(autoUninitSpan); -} - -// IProgress properties -//////////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP CombinedProgress::COMGETTER(Percent)(ULONG *aPercent) -{ - CheckComArgOutPointerValid(aPercent); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (mCompleted && SUCCEEDED(mResultCode)) - *aPercent = 100; - else - { - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - /* global percent = - * (100 / m_cOperations) * mOperation + - * ((100 / m_cOperations) / 100) * m_ulOperationPercent */ - *aPercent = (100 * m_ulCurrentOperation + m_ulOperationPercent) / m_cOperations; - } - - return S_OK; -} - -STDMETHODIMP CombinedProgress::COMGETTER(Completed)(BOOL *aCompleted) -{ - CheckComArgOutPointerValid(aCompleted); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Completed)(aCompleted); -} - -STDMETHODIMP CombinedProgress::COMGETTER(Canceled)(BOOL *aCanceled) -{ - CheckComArgOutPointerValid(aCanceled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Canceled)(aCanceled); -} - -STDMETHODIMP CombinedProgress::COMGETTER(ResultCode)(LONG *aResultCode) -{ - CheckComArgOutPointerValid(aResultCode); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(ResultCode)(aResultCode); -} - -STDMETHODIMP CombinedProgress::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) -{ - CheckComArgOutPointerValid(aErrorInfo); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(ErrorInfo)(aErrorInfo); -} - -STDMETHODIMP CombinedProgress::COMGETTER(Operation)(ULONG *aOperation) -{ - CheckComArgOutPointerValid(aOperation); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Operation)(aOperation); -} - -STDMETHODIMP CombinedProgress::COMGETTER(OperationDescription)(BSTR *aOperationDescription) -{ - CheckComArgOutPointerValid(aOperationDescription); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(OperationDescription)(aOperationDescription); -} - -STDMETHODIMP CombinedProgress::COMGETTER(OperationPercent)(ULONG *aOperationPercent) -{ - CheckComArgOutPointerValid(aOperationPercent); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(OperationPercent)(aOperationPercent); -} - -STDMETHODIMP CombinedProgress::COMSETTER(Timeout)(ULONG aTimeout) -{ - NOREF(aTimeout); - AssertFailed(); - return E_NOTIMPL; -} - -STDMETHODIMP CombinedProgress::COMGETTER(Timeout)(ULONG *aTimeout) -{ - CheckComArgOutPointerValid(aTimeout); - - AssertFailed(); - return E_NOTIMPL; -} - -// IProgress methods -///////////////////////////////////////////////////////////////////////////// - -/** - * @note XPCOM: when this method is called not on the main XPCOM thread, it - * simply blocks the thread until mCompletedSem is signalled. If the - * thread has its own event queue (hmm, what for?) that it must run, then - * calling this method will definitely freeze event processing. - */ -STDMETHODIMP CombinedProgress::WaitForCompletion(LONG aTimeout) -{ - LogFlowThisFuncEnter(); - LogFlowThisFunc(("aTtimeout=%d\n", aTimeout)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* if we're already completed, take a shortcut */ - if (!mCompleted) - { - HRESULT rc = S_OK; - bool forever = aTimeout < 0; - int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeMilliTS(); - - while (!mCompleted && (forever || timeLeft > 0)) - { - alock.release(); - rc = mProgresses.back()->WaitForCompletion(forever ? -1 : (LONG) timeLeft); - alock.acquire(); - - if (SUCCEEDED(rc)) - rc = checkProgress(); - - if (FAILED(rc)) break; - - if (!forever) - { - int64_t now = RTTimeMilliTS(); - timeLeft -= now - lastTime; - lastTime = now; - } - } - - if (FAILED(rc)) return rc; - } - - LogFlowThisFuncLeave(); - - return S_OK; -} - -/** - * @note XPCOM: when this method is called not on the main XPCOM thread, it - * simply blocks the thread until mCompletedSem is signalled. If the - * thread has its own event queue (hmm, what for?) that it must run, then - * calling this method will definitely freeze event processing. - */ -STDMETHODIMP CombinedProgress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout) -{ - LogFlowThisFuncEnter(); - LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (aOperation >= m_cOperations) - return setError(E_FAIL, - tr("Operation number must be in range [0, %d]"), m_ulCurrentOperation - 1); - - /* if we're already completed or if the given operation is already done, - * then take a shortcut */ - if (!mCompleted && aOperation >= m_ulCurrentOperation) - { - HRESULT rc = S_OK; - - /* find the right progress object to wait for */ - size_t progress = mProgress; - ULONG operation = 0, completedOps = mCompletedOperations; - do - { - ULONG opCount = 0; - rc = mProgresses[progress]->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) - return rc; - - if (completedOps + opCount > aOperation) - { - /* found the right progress object */ - operation = aOperation - completedOps; - break; - } - - completedOps += opCount; - progress ++; - ComAssertRet(progress < mProgresses.size(), E_FAIL); - } - while (1); - - LogFlowThisFunc(("will wait for mProgresses [%d] (%d)\n", - progress, operation)); - - bool forever = aTimeout < 0; - int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeMilliTS(); - - while (!mCompleted && aOperation >= m_ulCurrentOperation && - (forever || timeLeft > 0)) - { - alock.release(); - /* wait for the appropriate progress operation completion */ - rc = mProgresses[progress]-> WaitForOperationCompletion(operation, - forever ? -1 : (LONG) timeLeft); - alock.acquire(); - - if (SUCCEEDED(rc)) - rc = checkProgress(); - - if (FAILED(rc)) break; - - if (!forever) - { - int64_t now = RTTimeMilliTS(); - timeLeft -= now - lastTime; - lastTime = now; - } - } - - if (FAILED(rc)) return rc; - } - - LogFlowThisFuncLeave(); - - return S_OK; -} - -STDMETHODIMP CombinedProgress::Cancel() -{ - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (!mCancelable) - return setError(E_FAIL, tr("Operation cannot be canceled")); - - if (!mCanceled) - { - LogThisFunc(("Canceling\n")); - mCanceled = TRUE; -/** @todo Teleportation: Shouldn't this be propagated to mProgresses? If - * powerUp creates passes a combined progress object to the client, I - * won't get called back since I'm only getting the powerupProgress ... - * Or what? */ - if (m_pfnCancelCallback) - m_pfnCancelCallback(m_pvCancelUserArg); - - } - else - LogThisFunc(("Already canceled\n")); - - return S_OK; -} - -// private methods -//////////////////////////////////////////////////////////////////////////////// - -/** - * Fetches the properties of the current progress object and, if it is - * successfully completed, advances to the next uncompleted or unsuccessfully - * completed object in the vector of combined progress objects. - * - * @note Must be called from under this object's write lock! - */ -HRESULT CombinedProgress::checkProgress() -{ - /* do nothing if we're already marked ourselves as completed */ - if (mCompleted) - return S_OK; - - AssertReturn(mProgress < mProgresses.size(), E_FAIL); - - ComPtr progress = mProgresses[mProgress]; - ComAssertRet(!progress.isNull(), E_FAIL); - - HRESULT rc = S_OK; - BOOL fCompleted = FALSE; - - do - { - rc = progress->COMGETTER(Completed)(&fCompleted); - if (FAILED(rc)) - return rc; - - if (fCompleted) - { - rc = progress->COMGETTER(Canceled)(&mCanceled); - if (FAILED(rc)) - return rc; - - LONG iRc; - rc = progress->COMGETTER(ResultCode)(&iRc); - if (FAILED(rc)) - return rc; - mResultCode = iRc; - - if (FAILED(mResultCode)) - { - rc = progress->COMGETTER(ErrorInfo)(mErrorInfo.asOutParam()); - if (FAILED(rc)) - return rc; - } - - if (FAILED(mResultCode) || mCanceled) - { - mCompleted = TRUE; - } - else - { - ULONG opCount = 0; - rc = progress->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) - return rc; - - mCompletedOperations += opCount; - mProgress ++; - - if (mProgress < mProgresses.size()) - progress = mProgresses[mProgress]; - else - mCompleted = TRUE; - } - } - } - while (fCompleted && !mCompleted); - - rc = progress->COMGETTER(OperationPercent)(&m_ulOperationPercent); - if (SUCCEEDED(rc)) - { - ULONG operation = 0; - rc = progress->COMGETTER(Operation)(&operation); - if (SUCCEEDED(rc) && mCompletedOperations + operation > m_ulCurrentOperation) - { - m_ulCurrentOperation = mCompletedOperations + operation; - rc = progress->COMGETTER(OperationDescription)(m_bstrOperationDescription.asOutParam()); - } - } - - return rc; -} -/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-all/SharedFolderImpl.cpp b/src/VBox/Main/src-all/SharedFolderImpl.cpp index 2edf2a2e..9f4ad6c7 100644 --- a/src/VBox/Main/src-all/SharedFolderImpl.cpp +++ b/src/VBox/Main/src-all/SharedFolderImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -16,8 +16,10 @@ */ #include "SharedFolderImpl.h" -#include "VirtualBoxImpl.h" -#include "MachineImpl.h" +#if !defined(VBOX_COM_INPROC) +# include "VirtualBoxImpl.h" +# include "MachineImpl.h" +#endif #include "ConsoleImpl.h" #include "AutoCaller.h" @@ -50,9 +52,12 @@ struct SharedFolder::Data SharedFolder::SharedFolder() : mParent(NULL), +#if !defined(VBOX_COM_INPROC) mMachine(NULL), - mConsole(NULL), mVirtualBox(NULL) +#else + mConsole(NULL) +#endif { m = new Data; } @@ -77,6 +82,7 @@ void SharedFolder::FinalRelease() // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// +#if !defined(VBOX_COM_INPROC) /** * Initializes the shared folder object. * @@ -147,12 +153,14 @@ HRESULT SharedFolder::initCopy(Machine *aMachine, SharedFolder *aThat) return rc; } +# if 0 + /** * Initializes the shared folder object. * - * This variant initializes an instance that lives in the console address space. + * This variant initializes a global instance that lives in the server address space. It is not presently used. * - * @param aConsole Console parent object + * @param aVirtualBox VirtualBox parent object * @param aName logical name of the shared folder * @param aHostPath full path to the shared folder on the host * @param aWritable writable if true, readonly otherwise @@ -160,7 +168,7 @@ HRESULT SharedFolder::initCopy(Machine *aMachine, SharedFolder *aThat) * * @return COM result indicator */ -HRESULT SharedFolder::init(Console *aConsole, +HRESULT SharedFolder::init(VirtualBox *aVirtualBox, const Utf8Str &aName, const Utf8Str &aHostPath, bool aWritable, @@ -171,9 +179,9 @@ HRESULT SharedFolder::init(Console *aConsole, AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); - unconst(mConsole) = aConsole; + unconst(mVirtualBox) = aVirtualBox; - HRESULT rc = protectedInit(aConsole, aName, aHostPath, aWritable, aAutoMount, fFailOnError); + HRESULT rc = protectedInit(aVirtualBox, aName, aHostPath, aWritable, aAutoMount); /* Confirm a successful initialization when it's the case */ if (SUCCEEDED(rc)) @@ -182,14 +190,16 @@ HRESULT SharedFolder::init(Console *aConsole, return rc; } -#if 0 +# endif + +#else /** * Initializes the shared folder object. * - * This variant initializes a global instance that lives in the server address space. It is not presently used. + * This variant initializes an instance that lives in the console address space. * - * @param aVirtualBox VirtualBox parent object + * @param aConsole Console parent object * @param aName logical name of the shared folder * @param aHostPath full path to the shared folder on the host * @param aWritable writable if true, readonly otherwise @@ -197,7 +207,7 @@ HRESULT SharedFolder::init(Console *aConsole, * * @return COM result indicator */ -HRESULT SharedFolder::init(VirtualBox *aVirtualBox, +HRESULT SharedFolder::init(Console *aConsole, const Utf8Str &aName, const Utf8Str &aHostPath, bool aWritable, @@ -208,9 +218,9 @@ HRESULT SharedFolder::init(VirtualBox *aVirtualBox, AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); - unconst(mVirtualBox) = aVirtualBox; + unconst(mConsole) = aConsole; - HRESULT rc = protectedInit(aVirtualBox, aName, aHostPath, aWritable, aAutoMount); + HRESULT rc = protectedInit(aConsole, aName, aHostPath, aWritable, aAutoMount, fFailOnError); /* Confirm a successful initialization when it's the case */ if (SUCCEEDED(rc)) @@ -218,7 +228,6 @@ HRESULT SharedFolder::init(VirtualBox *aVirtualBox, return rc; } - #endif /** @@ -304,9 +313,12 @@ void SharedFolder::uninit() unconst(mParent) = NULL; +#if !defined(VBOX_COM_INPROC) unconst(mMachine) = NULL; - unconst(mConsole) = NULL; unconst(mVirtualBox) = NULL; +#else + unconst(mConsole) = NULL; +#endif } // ISharedFolder properties diff --git a/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp b/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp index 8aea252f..96ade446 100644 --- a/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp +++ b/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,6 +30,7 @@ HRESULT VirtualBoxErrorInfo::init(HRESULT aResultCode, IVirtualBoxErrorInfo *aNext) { m_resultCode = aResultCode; + m_resultDetail = 0; /* Not being used. */ m_IID = aIID; m_strComponent = pcszComponent; m_strText = strText; @@ -38,10 +39,24 @@ HRESULT VirtualBoxErrorInfo::init(HRESULT aResultCode, return S_OK; } +HRESULT VirtualBoxErrorInfo::initEx(HRESULT aResultCode, + LONG aResultDetail, + const GUID &aIID, + const char *pcszComponent, + const Utf8Str &strText, + IVirtualBoxErrorInfo *aNext) +{ + HRESULT hr = init(aResultCode, aIID, pcszComponent, strText, aNext); + m_resultDetail = aResultDetail; + + return hr; +} + HRESULT VirtualBoxErrorInfo::init(const com::ErrorInfo &info, IVirtualBoxErrorInfo *aNext) { m_resultCode = info.getResultCode(); + m_resultDetail = info.getResultDetail(); m_IID = info.getInterfaceID(); m_strComponent = info.getComponent(); m_strText = info.getText(); @@ -74,6 +89,14 @@ STDMETHODIMP VirtualBoxErrorInfo::COMGETTER(ResultCode)(LONG *aResultCode) return S_OK; } +STDMETHODIMP VirtualBoxErrorInfo::COMGETTER(ResultDetail)(LONG *aResultDetail) +{ + CheckComArgOutPointerValid(aResultDetail); + + *aResultDetail = m_resultDetail; + return S_OK; +} + STDMETHODIMP VirtualBoxErrorInfo::COMGETTER(InterfaceID)(BSTR *aIID) { CheckComArgOutPointerValid(aIID); @@ -123,6 +146,7 @@ HRESULT VirtualBoxErrorInfo::init(IErrorInfo *aInfo) * corresponding fields will simply remain null in this case). */ m_resultCode = S_OK; + m_resultDetail = 0; rc = aInfo->GetGUID(m_IID.asOutParam()); AssertComRC(rc); Bstr bstrComponent; @@ -187,6 +211,7 @@ HRESULT VirtualBoxErrorInfo::init(nsIException *aInfo) rc = aInfo->GetResult(&m_resultCode); AssertComRC(rc); + m_resultDetail = 0; /* Not being used. */ char *pszMsg; /* No Utf8Str.asOutParam, different allocator! */ rc = aInfo->GetMessage(&pszMsg); diff --git a/src/VBox/Main/src-all/win/VirtualBox_rgs.xsl b/src/VBox/Main/src-all/win/VirtualBox_rgs.xsl index 0b2e4ba9..08dc63fd 100644 --- a/src/VBox/Main/src-all/win/VirtualBox_rgs.xsl +++ b/src/VBox/Main/src-all/win/VirtualBox_rgs.xsl @@ -5,7 +5,7 @@ * registry definitions necessary to properly register * VirtualBox Main API COM components. - Copyright (C) 2007 Oracle Corporation + Copyright (C) 2007-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-all/win/comregister.cmd b/src/VBox/Main/src-all/win/comregister.cmd index 1f8e312f..65f51c3b 100644 --- a/src/VBox/Main/src-all/win/comregister.cmd +++ b/src/VBox/Main/src-all/win/comregister.cmd @@ -6,7 +6,7 @@ REM (both inproc and out-of-process) REM REM -REM Copyright (C) 2006-2011 Oracle Corporation +REM Copyright (C) 2006-2013 Oracle Corporation REM REM This file is part of VirtualBox Open Source Edition (OSE), as REM available from http://www.virtualbox.org. This file is free software; @@ -94,13 +94,31 @@ cd "%_SCRIPT_CURDIR%" REM REM Do the registrations. REM -:register +if "%ProgramW6432%x" == "x" goto register_x86 +goto register_amd64 + +:register_x86 @echo on -%_VBOX_DIR%VBoxSVC.exe /ReregServer +%_VBOX_DIR%VBoxSVC.exe /UnregServer regsvr32 /s /u %_VBOX_DIR%VBoxC.dll +@if "%1" == "-u" goto end +%_VBOX_DIR%VBoxSVC.exe /RegServer regsvr32 /s %_VBOX_DIR%VBoxC.dll @echo off +goto end + +REM Unregister both first, then register them. The order matters here. +:register_amd64 +@echo on +%_VBOX_DIR%VBoxSVC.exe /UnregServer +%windir%\syswow64\regsvr32 /s /u %_VBOX_DIR%VBoxClient-x86.dll +%windir%\system32\regsvr32 /s /u %_VBOX_DIR%VBoxC.dll +@if "%1" == "-u" goto end +%_VBOX_DIR%VBoxSVC.exe /RegServer +%windir%\system32\regsvr32 /s %_VBOX_DIR%VBoxC.dll +%windir%\syswow64\regsvr32 /s %_VBOX_DIR%VBoxClient-x86.dll +@echo off :end -endlocal +@endlocal diff --git a/src/VBox/Main/src-client/AudioSnifferInterface.cpp b/src/VBox/Main/src-client/AudioSnifferInterface.cpp index f1b64208..c5b902e4 100644 --- a/src/VBox/Main/src-client/AudioSnifferInterface.cpp +++ b/src/VBox/Main/src-client/AudioSnifferInterface.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -160,9 +160,9 @@ DECLCALLBACK(void *) AudioSniffer::drvQueryInterface(PPDMIBASE pInterface, const */ DECLCALLBACK(void) AudioSniffer::drvDestruct(PPDMDRVINS pDrvIns) { + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); PDRVAUDIOSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOSNIFFER); LogFlow(("AudioSniffer::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); - PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); if (pThis->pAudioSniffer) { @@ -178,10 +178,10 @@ DECLCALLBACK(void) AudioSniffer::drvDestruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) AudioSniffer::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); PDRVAUDIOSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOSNIFFER); LogFlow(("AudioSniffer::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); - PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Validate configuration. diff --git a/src/VBox/Main/src-client/BusAssignmentManager.cpp b/src/VBox/Main/src-client/BusAssignmentManager.cpp index 18e34741..068bb79e 100644 --- a/src/VBox/Main/src-client/BusAssignmentManager.cpp +++ b/src/VBox/Main/src-client/BusAssignmentManager.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -77,7 +77,8 @@ static const DeviceAssignmentRule aGenericRules[] = /* Network controllers */ /* the first network card gets the PCI ID 3, the next 3 gets 8..10, - * next 4 get 16..19. */ + * next 4 get 16..19. In "VMWare compatibility" mode the IDs 3 and 17 + * swap places, i.e. the first card goes to ID 17=0x11. */ {"nic", 0, 3, 0, 1}, {"nic", 0, 8, 0, 1}, {"nic", 0, 9, 0, 1}, @@ -86,8 +87,6 @@ static const DeviceAssignmentRule aGenericRules[] = {"nic", 0, 17, 0, 1}, {"nic", 0, 18, 0, 1}, {"nic", 0, 19, 0, 1}, - /* VMWare assigns first NIC to slot 11 */ - {"nic-vmware", 0, 11, 0, 1}, /* ISA/LPC controller */ {"lpc", 0, 31, 0, 0}, diff --git a/src/VBox/Main/src-client/ClientTokenHolder.cpp b/src/VBox/Main/src-client/ClientTokenHolder.cpp new file mode 100644 index 00000000..07ad83e2 --- /dev/null +++ b/src/VBox/Main/src-client/ClientTokenHolder.cpp @@ -0,0 +1,334 @@ +/** @file + * + * VirtualBox API client session token holder (in the client process) + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include +#include +#include + +#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER +# include +# include +# include +# include +# include +#endif + +#include + +#include "ClientTokenHolder.h" +#include "SessionImpl.h" + + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +/** client token holder thread */ +static DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD Thread, void *pvUser); +#endif + + +Session::ClientTokenHolder::ClientTokenHolder() +{ + AssertReleaseFailed(); +} + +Session::ClientTokenHolder::~ClientTokenHolder() +{ + /* release the client token */ +#if defined(RT_OS_WINDOWS) + + if (mSem && mThreadSem) + { + /* + * tell the thread holding the token to release it; + * it will close mSem handle + */ + ::SetEvent(mSem); + /* wait for the thread to finish */ + ::WaitForSingleObject(mThreadSem, INFINITE); + ::CloseHandle(mThreadSem); + + mThreadSem = NULL; + mSem = NULL; + mThread = NIL_RTTHREAD; + } + +#elif defined(RT_OS_OS2) + + if (mThread != NIL_RTTHREAD) + { + Assert(mSem != NIL_RTSEMEVENT); + + /* tell the thread holding the token to release it */ + int vrc = RTSemEventSignal(mSem); + AssertRC(vrc == NO_ERROR); + + /* wait for the thread to finish */ + vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT); + Assert(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); + + mThread = NIL_RTTHREAD; + } + + if (mSem != NIL_RTSEMEVENT) + { + RTSemEventDestroy(mSem); + mSem = NIL_RTSEMEVENT; + } + +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + + if (mSem >= 0) + { + ::sembuf sop = { 0, 1, SEM_UNDO }; + ::semop(mSem, &sop, 1); + + mSem = -1; + } + +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + + if (!mToken.isNull()) + { + mToken->Abandon(); + mToken.setNull(); + } + +#else +# error "Port me!" +#endif +} + +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER +Session::ClientTokenHolder::ClientTokenHolder(const Utf8Str &strTokenId) : + mClientTokenId(strTokenId) +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +Session::ClientTokenHolder::ClientTokenHolder(IToken *aToken) : + mToken(aToken) +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +{ +#ifdef CTHSEMTYPE + mSem = CTHSEMARG; +#endif +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + mThread = NIL_RTTHREAD; +#endif + +#if defined(RT_OS_WINDOWS) + mThreadSem = CTHTHREADSEMARG; + + Bstr bstrTokenId(strTokenId); + + /* + * Since there is no guarantee that the constructor and destructor will be + * called in the same thread, we need a separate thread to hold the token. + */ + + mThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); + AssertMsgReturnVoid(mThreadSem, + ("Cannot create an event sem, err=%d", ::GetLastError())); + + void *data[3]; + data[0] = (void*)(BSTR)bstrTokenId.raw(); + data[1] = (void*)mThreadSem; + data[2] = 0; /* will get an output from the thread */ + + /* create a thread to hold the token until signalled to release it */ + int vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); + AssertRCReturnVoid(vrc); + + /* wait until thread init is completed */ + DWORD wrc = ::WaitForSingleObject(mThreadSem, INFINITE); + AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError())); + Assert(data[2]); + + if (wrc == WAIT_OBJECT_0 && data[2]) + { + /* memorize the event sem we should signal in close() */ + mSem = (HANDLE)data[2]; + } + else + { + ::CloseHandle(mThreadSem); + mThreadSem = NULL; + } +#elif defined(RT_OS_OS2) + Bstr bstrTokenId(strTokenId); + + /* + * Since there is no guarantee that the constructor and destructor will be + * called in the same thread, we need a separate thread to hold the token. + */ + + int vrc = RTSemEventCreate(&mSem); + AssertRCReturnVoid(vrc); + + void *data[3]; + data[0] = (void*)bstrTokenId.raw(); + data[1] = (void*)mSem; + data[2] = (void*)false; /* will get the thread result here */ + + /* create a thread to hold the token until signalled to release it */ + vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void *) data, + 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); + AssertRCReturnVoid(vrc); + /* wait until thread init is completed */ + vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT); + AssertReturnVoid(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); + + /* the thread must succeed */ + AssertReturnVoid((bool)data[2]); + +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + +# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN + key_t key = RTStrToUInt32(strTokenId.c_str()); + AssertMsgReturnVoid(key != 0, + ("Key value of 0 is not valid for client token")); +# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ + char *pszSemName = NULL; + RTStrUtf8ToCurrentCP(&pszSemName, strTokenId); + key_t key = ::ftok(pszSemName, 'V'); + RTStrFree(pszSemName); +# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ + int s = ::semget(key, 0, 0); + AssertMsgReturnVoid(s >= 0, + ("Cannot open semaphore, errno=%d", errno)); + + /* grab the semaphore */ + ::sembuf sop = { 0, -1, SEM_UNDO }; + int rv = ::semop(s, &sop, 1); + AssertMsgReturnVoid(rv == 0, + ("Cannot grab semaphore, errno=%d", errno)); + mSem = s; + +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + + /* nothing to do */ + +#else +# error "Port me!" +#endif +} + +bool Session::ClientTokenHolder::isReady() +{ +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + return mSem != CTHSEMARG; +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + return !mToken.isNull(); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +} + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +/** client token holder thread */ +DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD Thread, void *pvUser) +{ + LogFlowFuncEnter(); + + Assert(pvUser); + + void **data = (void **)pvUser; + +# if defined(RT_OS_WINDOWS) + BSTR sessionId = (BSTR)data[0]; + HANDLE initDoneSem = (HANDLE)data[1]; + + HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, sessionId); + AssertMsg(mutex, ("cannot open token, err=%d\n", ::GetLastError())); + + if (mutex) + { + /* grab the token */ + DWORD wrc = ::WaitForSingleObject(mutex, 0); + AssertMsg(wrc == WAIT_OBJECT_0, ("cannot grab token, err=%d\n", wrc)); + if (wrc == WAIT_OBJECT_0) + { + HANDLE finishSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); + AssertMsg(finishSem, ("cannot create event sem, err=%d\n", ::GetLastError())); + if (finishSem) + { + data[2] = (void*)finishSem; + /* signal we're done with init */ + ::SetEvent(initDoneSem); + /* wait until we're signaled to release the token */ + ::WaitForSingleObject(finishSem, INFINITE); + /* release the token */ + LogFlow(("ClientTokenHolderThread(): releasing token...\n")); + BOOL success = ::ReleaseMutex(mutex); + AssertMsg(success, ("cannot release token, err=%d\n", ::GetLastError())); + ::CloseHandle(mutex); + ::CloseHandle(finishSem); + } + } + } + + /* signal we're done */ + ::SetEvent(initDoneSem); +# elif defined(RT_OS_OS2) + Utf8Str sessionId = (BSTR)data[0]; + RTSEMEVENT finishSem = (RTSEMEVENT)data[1]; + + LogFlowFunc(("sessionId='%s', finishSem=%p\n", sessionId.raw(), finishSem)); + + HMTX mutex = NULLHANDLE; + APIRET arc = ::DosOpenMutexSem((PSZ)sessionId.raw(), &mutex); + AssertMsg(arc == NO_ERROR, ("cannot open token, arc=%ld\n", arc)); + + if (arc == NO_ERROR) + { + /* grab the token */ + LogFlowFunc(("grabbing token...\n")); + arc = ::DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN); + AssertMsg(arc == NO_ERROR, ("cannot grab token, arc=%ld\n", arc)); + if (arc == NO_ERROR) + { + /* store the answer */ + data[2] = (void*)true; + /* signal we're done */ + int vrc = RTThreadUserSignal(Thread); + AssertRC(vrc); + + /* wait until we're signaled to release the token */ + LogFlowFunc(("waiting for termination signal..\n")); + vrc = RTSemEventWait(finishSem, RT_INDEFINITE_WAIT); + Assert(arc == ERROR_INTERRUPT || ERROR_TIMEOUT); + + /* release the token */ + LogFlowFunc(("releasing token...\n")); + arc = ::DosReleaseMutexSem(mutex); + AssertMsg(arc == NO_ERROR, ("cannot release token, arc=%ld\n", arc)); + } + ::DosCloseMutexSem(mutex); + } + + /* store the answer */ + data[1] = (void*)false; + /* signal we're done */ + int vrc = RTThreadUserSignal(Thread); + AssertRC(vrc); +# else +# error "Port me!" +# endif + + LogFlowFuncLeave(); + + return 0; +} +#endif + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp index 6c29a2dd..d0c74c24 100644 --- a/src/VBox/Main/src-client/ConsoleImpl.cpp +++ b/src/VBox/Main/src-client/ConsoleImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2012 Oracle Corporation + * Copyright (C) 2005-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,19 +57,17 @@ #include "SharedFolderImpl.h" #include "AudioSnifferInterface.h" #include "Nvram.h" -#ifdef VBOX_WITH_USB_VIDEO -# include "UsbWebcamInterface.h" -#endif #ifdef VBOX_WITH_USB_CARDREADER # include "UsbCardReader.h" #endif -#include "ProgressCombinedImpl.h" +#include "ProgressImpl.h" #include "ConsoleVRDPServer.h" #include "VMMDev.h" #ifdef VBOX_WITH_EXTPACK # include "ExtPackManagerImpl.h" #endif #include "BusAssignmentManager.h" +#include "EmulatedUSBImpl.h" #include "VBoxEvents.h" #include "AutoCaller.h" @@ -155,7 +153,7 @@ struct VMTask mConsoleCaller(aConsole), mProgress(aProgress), mServerProgress(aServerProgress), - mpVM(NULL), + mpUVM(NULL), mRC(E_FAIL), mpSafeVMPtr(NULL) { @@ -167,7 +165,7 @@ struct VMTask { mpSafeVMPtr = new Console::SafeVMPtr(aConsole); if (mpSafeVMPtr->isOk()) - mpVM = mpSafeVMPtr->raw(); + mpUVM = mpSafeVMPtr->rawUVM(); else mRC = mpSafeVMPtr->rc(); } @@ -196,7 +194,7 @@ struct VMTask const ComObjPtr mProgress; Utf8Str mErrorMsg; const ComPtr mServerProgress; - PVM mpVM; + PUVM mpUVM; private: HRESULT mRC; @@ -262,16 +260,20 @@ struct VMSaveTask : public VMTask VMSaveTask(Console *aConsole, const ComPtr &aServerProgress, const Utf8Str &aSavedStateFile, - MachineState_T aMachineStateBefore) + MachineState_T aMachineStateBefore, + Reason_T aReason) : VMTask(aConsole, NULL /* aProgress */, aServerProgress, true /* aUsesVMPtr */), mSavedStateFile(aSavedStateFile), - mMachineStateBefore(aMachineStateBefore) + mMachineStateBefore(aMachineStateBefore), + mReason(aReason) {} Utf8Str mSavedStateFile; /* The local machine state we had before. Required if something fails */ MachineState_T mMachineStateBefore; + /* The reason for saving state */ + Reason_T mReason; }; // Handler for global events @@ -344,13 +346,34 @@ public: break; } + case VBoxEventType_OnExtraDataChanged: + { + ComPtr pEDCEv = aEvent; + Bstr strMachineId; + Bstr strKey; + Bstr strVal; + HRESULT hrc = S_OK; + + hrc = pEDCEv->COMGETTER(MachineId)(strMachineId.asOutParam()); + if (FAILED(hrc)) break; + + hrc = pEDCEv->COMGETTER(Key)(strKey.asOutParam()); + if (FAILED(hrc)) break; + + hrc = pEDCEv->COMGETTER(Value)(strVal.asOutParam()); + if (FAILED(hrc)) break; + + mConsole->onExtraDataChange(strMachineId.raw(), strKey.raw(), strVal.raw()); + break; + } + default: AssertFailed(); } return S_OK; } private: - Console *mConsole; + ComObjPtr mConsole; }; typedef ListenerImpl VmEventListenerImpl; @@ -365,6 +388,8 @@ VBOX_LISTENER_DECLARE(VmEventListenerImpl) Console::Console() : mSavedStateDataLoaded(false) , mConsoleVRDPServer(NULL) + , mfVRDEChangeInProcess(false) + , mfVRDEChangePending(false) , mpUVM(NULL) , mVMCallers(0) , mVMZeroCallersSem(NIL_RTSEMEVENT) @@ -374,13 +399,12 @@ Console::Console() , mfSnapshotFolderSizeWarningShown(false) , mfSnapshotFolderExt4WarningShown(false) , mfSnapshotFolderDiskTypeShown(false) + , mfVMHasUsbController(false) + , mfPowerOffCausedByReset(false) , mpVmm2UserMethods(NULL) , m_pVMMDev(NULL) , mAudioSniffer(NULL) , mNvram(NULL) -#ifdef VBOX_WITH_USB_VIDEO - , mUsbWebcamInterface(NULL) -#endif #ifdef VBOX_WITH_USB_CARDREADER , mUsbCardReader(NULL) #endif @@ -398,10 +422,10 @@ HRESULT Console::FinalConstruct() { LogFlowThisFunc(("\n")); - memset(mapStorageLeds, 0, sizeof(mapStorageLeds)); - memset(mapNetworkLeds, 0, sizeof(mapNetworkLeds)); - memset(&mapUSBLed, 0, sizeof(mapUSBLed)); - memset(&mapSharedFolderLed, 0, sizeof(mapSharedFolderLed)); + RT_ZERO(mapStorageLeds); + RT_ZERO(mapNetworkLeds); + RT_ZERO(mapUSBLed); + RT_ZERO(mapSharedFolderLed); for (unsigned i = 0; i < RT_ELEMENTS(maStorageDevType); ++i) maStorageDevType[i] = DeviceType_Null; @@ -416,6 +440,7 @@ HRESULT Console::FinalConstruct() pVmm2UserMethods->pfnNotifyEmtTerm = Console::vmm2User_NotifyEmtTerm; pVmm2UserMethods->pfnNotifyPdmtInit = Console::vmm2User_NotifyPdmtInit; pVmm2UserMethods->pfnNotifyPdmtTerm = Console::vmm2User_NotifyPdmtTerm; + pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff = Console::vmm2User_NotifyResetTurnedIntoPowerOff; pVmm2UserMethods->u32EndMagic = VMM2USERMETHODS_MAGIC; pVmm2UserMethods->pConsole = this; mpVmm2UserMethods = pVmm2UserMethods; @@ -464,7 +489,7 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc // Event source may be needed by other children unconst(mEventSource).createObject(); - rc = mEventSource->init(static_cast(this)); + rc = mEventSource->init(); AssertComRCReturnRC(rc); mcAudioRefs = 0; @@ -498,6 +523,10 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc rc = mVRDEServerInfo->init(this); AssertComRCReturnRC(rc); + unconst(mEmulatedUSB).createObject(); + rc = mEmulatedUSB->init(this); + AssertComRCReturnRC(rc); + /* Grab global and machine shared folder lists */ rc = fetchSharedFolders(true /* aGlobal */); @@ -548,10 +577,6 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc AssertReturn(mNvram, E_FAIL); } -#ifdef VBOX_WITH_USB_VIDEO - unconst(mUsbWebcamInterface) = new UsbWebcamInterface(this); - AssertReturn(mUsbWebcamInterface, E_FAIL); -#endif #ifdef VBOX_WITH_USB_CARDREADER unconst(mUsbCardReader) = new UsbCardReader(this); AssertReturn(mUsbCardReader, E_FAIL); @@ -569,6 +594,7 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc com::SafeArray eventTypes; eventTypes.push_back(VBoxEventType_OnNATRedirect); eventTypes.push_back(VBoxEventType_OnHostPCIDevicePlug); + eventTypes.push_back(VBoxEventType_OnExtraDataChanged); rc = pES->RegisterListener(aVmListener, ComSafeArrayAsInParam(eventTypes), true); AssertComRC(rc); } @@ -649,14 +675,6 @@ void Console::uninit() unconst(mNvram) = NULL; } -#ifdef VBOX_WITH_USB_VIDEO - if (mUsbWebcamInterface) - { - delete mUsbWebcamInterface; - unconst(mUsbWebcamInterface) = NULL; - } -#endif - #ifdef VBOX_WITH_USB_CARDREADER if (mUsbCardReader) { @@ -697,6 +715,12 @@ void Console::uninit() unconst(mVRDEServerInfo).setNull(); } + if (mEmulatedUSB) + { + mEmulatedUSB->uninit(); + unconst(mEmulatedUSB).setNull(); + } + if (mDebugger) { mDebugger->uninit(); @@ -778,8 +802,7 @@ void Console::guestPropertiesHandleVMReset(void) /* Delete all properties which have the flag "TRANSRESET". */ if (Utf8Str(arrFlags[i]).contains("TRANSRESET", Utf8Str::CaseInsensitive)) { - hrc = mMachine->SetGuestProperty(arrNames[i], Bstr("").raw() /* Value */, - Bstr("").raw() /* Flags */); + hrc = mMachine->DeleteGuestProperty(arrNames[i]); if (FAILED(hrc)) LogRel(("RESET: Could not delete transient property \"%ls\", rc=%Rhrc\n", arrNames[i], hrc)); @@ -989,6 +1012,17 @@ void Console::guestPropertiesVRDPUpdateDisconnect(uint32_t u32ClientId) #endif /* VBOX_WITH_GUEST_PROPS */ +bool Console::isResetTurnedIntoPowerOff(void) +{ + Bstr value; + HRESULT hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/TurnResetIntoPowerOff").raw(), + value.asOutParam()); + if ( hrc == S_OK + && value == "1") + return true; + return false; +} + #ifdef VBOX_WITH_EXTPACK /** * Used by VRDEServer and others to talke to the extension pack manager. @@ -1229,9 +1263,13 @@ int Console::VRDPClientLogon(uint32_t u32ClientId, const char *pszUser, const ch { uint32_t u32GuestFlags = VMMDEV_SETCREDENTIALS_GUESTLOGON; - int rc = m_pVMMDev->getVMMDevPort()->pfnSetCredentials(m_pVMMDev->getVMMDevPort(), - pszUser, pszPassword, pszDomain, u32GuestFlags); - AssertRC(rc); + PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort(); + if (pDevPort) + { + int rc = pDevPort->pfnSetCredentials(m_pVMMDev->getVMMDevPort(), + pszUser, pszPassword, pszDomain, u32GuestFlags); + AssertRC(rc); + } } return VINF_SUCCESS; @@ -1697,8 +1735,8 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension, PHOSTCALLBACKDATA pCBData = reinterpret_cast(pvParms); AssertReturn(sizeof(HOSTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER); AssertReturn(HOSTCALLBACKMAGIC == pCBData->u32Magic, VERR_INVALID_PARAMETER); - Log5(("Console::doGuestPropNotification: pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n", - pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags)); + LogFlow(("Console::doGuestPropNotification: pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n", + pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags)); int rc; Bstr name(pCBData->pcszName); @@ -1713,7 +1751,7 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension, rc = VINF_SUCCESS; else { - LogFunc(("Console::doGuestPropNotification: hrc=%Rhrc pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n", + LogFlow(("Console::doGuestPropNotification: hrc=%Rhrc pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n", hrc, pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags)); rc = Global::vboxStatusCodeFromCOM(hrc); } @@ -1968,12 +2006,25 @@ STDMETHODIMP Console::COMGETTER(VRDEServerInfo)(IVRDEServerInfo **aVRDEServerInf AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* mDisplay is constant during life time, no need to lock */ + /* mVRDEServerInfo is constant during life time, no need to lock */ mVRDEServerInfo.queryInterfaceTo(aVRDEServerInfo); return S_OK; } +STDMETHODIMP Console::COMGETTER(EmulatedUSB)(IEmulatedUSB **aEmulatedUSB) +{ + CheckComArgOutPointerValid(aEmulatedUSB); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* mEmulatedUSB is constant during life time, no need to lock */ + mEmulatedUSB.queryInterfaceTo(aEmulatedUSB); + + return S_OK; +} + STDMETHODIMP Console::COMGETTER(SharedFolders)(ComSafeArrayOut(ISharedFolder *, aSharedFolders)) { @@ -2074,7 +2125,6 @@ STDMETHODIMP Console::PowerUpPaused(IProgress **aProgress) STDMETHODIMP Console::PowerDown(IProgress **aProgress) { LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); CheckComArgOutPointerValid(aProgress); @@ -2083,6 +2133,7 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); switch (mMachineState) { case MachineState_Running: @@ -2144,6 +2195,20 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress) { ComPtr pProgress; +#ifdef VBOX_WITH_GUEST_PROPS + alock.release(); + + if (isResetTurnedIntoPowerOff()) + { + mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw()); + mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(), + Bstr("PowerOff").raw(), Bstr("RDONLYGUEST").raw()); + mMachine->SaveSettings(); + } + + alock.acquire(); +#endif + /* * request a progress object from the server * (this will set the machine state to Stopping on the server to block @@ -2206,13 +2271,13 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress) STDMETHODIMP Console::Reset() { LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); if ( mMachineState != MachineState_Running && mMachineState != MachineState_Teleporting && mMachineState != MachineState_LiveSnapshotting @@ -2228,7 +2293,7 @@ STDMETHODIMP Console::Reset() /* release the lock before a VMR3* call (EMT will call us back)! */ alock.release(); - int vrc = VMR3Reset(ptrVM); + int vrc = VMR3Reset(ptrVM.rawUVM()); HRESULT rc = RT_SUCCESS(vrc) ? S_OK : setError(VBOX_E_VM_ERROR, @@ -2240,30 +2305,30 @@ STDMETHODIMP Console::Reset() return rc; } -/*static*/ DECLCALLBACK(int) Console::unplugCpu(Console *pThis, PVM pVM, unsigned uCpu) +/*static*/ DECLCALLBACK(int) Console::unplugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu) { - LogFlowFunc(("pThis=%p pVM=%p uCpu=%u\n", pThis, pVM, uCpu)); + LogFlowFunc(("pThis=%p pVM=%p idCpu=%u\n", pThis, pUVM, idCpu)); AssertReturn(pThis, VERR_INVALID_PARAMETER); - int vrc = PDMR3DeviceDetach(pVM, "acpi", 0, uCpu, 0); + int vrc = PDMR3DeviceDetach(pUVM, "acpi", 0, idCpu, 0); Log(("UnplugCpu: rc=%Rrc\n", vrc)); return vrc; } -HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) +HRESULT Console::doCPURemove(ULONG aCpu, PUVM pUVM) { HRESULT rc = S_OK; LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); AssertReturn(m_pVMMDev, E_FAIL); PPDMIVMMDEVPORT pVmmDevPort = m_pVMMDev->getVMMDevPort(); AssertReturn(pVmmDevPort, E_FAIL); @@ -2288,7 +2353,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) /* Check if the CPU is unlocked */ PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(pVM, "acpi", 0, aCpu, &pBase); + int vrc = PDMR3QueryDeviceLun(pUVM, "acpi", 0, aCpu, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -2296,7 +2361,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) /* Notify the guest if possible. */ uint32_t idCpuCore, idCpuPackage; - vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc); + vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc); if (RT_SUCCESS(vrc)) vrc = pVmmDevPort->pfnCpuHotUnplug(pVmmDevPort, idCpuCore, idCpuPackage); if (RT_SUCCESS(vrc)) @@ -2328,9 +2393,9 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) * using VMR3ReqCall. */ PVMREQ pReq; - vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::unplugCpu, 3, - this, pVM, aCpu); + vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)unplugCpu, 3, + this, pUVM, (VMCPUID)aCpu); if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc)) { vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT); @@ -2343,7 +2408,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) if (RT_SUCCESS(vrc)) { /* Detach it from the VM */ - vrc = VMR3HotUnplugCpu(pVM, aCpu); + vrc = VMR3HotUnplugCpu(pUVM, aCpu); AssertRC(vrc); } else @@ -2359,25 +2424,25 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) return rc; } -/*static*/ DECLCALLBACK(int) Console::plugCpu(Console *pThis, PVM pVM, unsigned uCpu) +/*static*/ DECLCALLBACK(int) Console::plugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu) { - LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu)); + LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, idCpu)); AssertReturn(pThis, VERR_INVALID_PARAMETER); - int rc = VMR3HotPlugCpu(pVM, uCpu); + int rc = VMR3HotPlugCpu(pUVM, idCpu); AssertRC(rc); - PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices/acpi/0/"); + PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "Devices/acpi/0/"); AssertRelease(pInst); /* nuke anything which might have been left behind. */ - CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%d", uCpu)); + CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", idCpu)); #define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; } } while (0) PCFGMNODE pLunL0; PCFGMNODE pCfg; - rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%d", uCpu); RC_CHECK(); + rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", idCpu); RC_CHECK(); rc = CFGMR3InsertString(pLunL0, "Driver", "ACPICpu"); RC_CHECK(); rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK(); @@ -2385,7 +2450,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) * Attach the driver. */ PPDMIBASE pBase; - rc = PDMR3DeviceAttach(pVM, "acpi", 0, uCpu, 0, &pBase); RC_CHECK(); + rc = PDMR3DeviceAttach(pUVM, "acpi", 0, idCpu, 0, &pBase); RC_CHECK(); Log(("PlugCpu: rc=%Rrc\n", rc)); @@ -2396,18 +2461,18 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM) return VINF_SUCCESS; } -HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM) +HRESULT Console::doCPUAdd(ULONG aCpu, PUVM pUVM) { HRESULT rc = S_OK; LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); if ( mMachineState != MachineState_Running && mMachineState != MachineState_Teleporting && mMachineState != MachineState_LiveSnapshotting @@ -2434,9 +2499,9 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM) * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::plugCpu, 3, - this, pVM, aCpu); + int vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)plugCpu, 3, + this, pUVM, aCpu); /* release the lock before a VMR3* call (EMT will call us back)! */ alock.release(); @@ -2459,7 +2524,7 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM) { /* Notify the guest if possible. */ uint32_t idCpuCore, idCpuPackage; - vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc); + vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc); if (RT_SUCCESS(vrc)) vrc = pDevPort->pfnCpuHotPlug(pDevPort, idCpuCore, idCpuPackage); /** @todo warning if the guest doesn't support it */ @@ -2474,89 +2539,18 @@ STDMETHODIMP Console::Pause() { LogFlowThisFuncEnter(); - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - switch (mMachineState) - { - case MachineState_Running: - case MachineState_Teleporting: - case MachineState_LiveSnapshotting: - break; - - case MachineState_Paused: - case MachineState_TeleportingPausedVM: - case MachineState_Saving: - return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused")); - - default: - return setInvalidMachineStateError(); - } - - /* get the VM handle. */ - SafeVMPtr ptrVM(this); - if (!ptrVM.isOk()) - return ptrVM.rc(); - - LogFlowThisFunc(("Sending PAUSE request...\n")); - - /* release the lock before a VMR3* call (EMT will call us back)! */ - alock.release(); - - int vrc = VMR3Suspend(ptrVM); - - HRESULT hrc = S_OK; - if (RT_FAILURE(vrc)) - hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); + HRESULT rc = pause(Reason_Unspecified); - LogFlowThisFunc(("hrc=%Rhrc\n", hrc)); + LogFlowThisFunc(("rc=%Rhrc\n", rc)); LogFlowThisFuncLeave(); - return hrc; + return rc; } STDMETHODIMP Console::Resume() { LogFlowThisFuncEnter(); - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (mMachineState != MachineState_Paused) - return setError(VBOX_E_INVALID_VM_STATE, - tr("Cannot resume the machine as it is not paused (machine state: %s)"), - Global::stringifyMachineState(mMachineState)); - - /* get the VM handle. */ - SafeVMPtr ptrVM(this); - if (!ptrVM.isOk()) - return ptrVM.rc(); - - LogFlowThisFunc(("Sending RESUME request...\n")); - - /* release the lock before a VMR3* call (EMT will call us back)! */ - alock.release(); - -#ifdef VBOX_WITH_EXTPACK - int vrc = mptrExtPackManager->callAllVmPowerOnHooks(this, ptrVM); /** @todo called a few times too many... */ -#else - int vrc = VINF_SUCCESS; -#endif - if (RT_SUCCESS(vrc)) - { - if (VMR3GetState(ptrVM) == VMSTATE_CREATED) - vrc = VMR3PowerOn(ptrVM); /* (PowerUpPaused) */ - else - vrc = VMR3Resume(ptrVM); - } - - HRESULT rc = RT_SUCCESS(vrc) ? S_OK : - setError(VBOX_E_VM_ERROR, - tr("Could not resume the machine execution (%Rrc)"), - vrc); + HRESULT rc = resume(Reason_Unspecified); LogFlowThisFunc(("rc=%Rhrc\n", rc)); LogFlowThisFuncLeave(); @@ -2587,7 +2581,7 @@ STDMETHODIMP Console::PowerButton() /* get the acpi device interface and press the button. */ PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase); + int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -2635,7 +2629,7 @@ STDMETHODIMP Console::GetPowerButtonHandled(BOOL *aHandled) /* get the acpi device interface and check if the button press was handled. */ PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase); + int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -2690,7 +2684,7 @@ STDMETHODIMP Console::GetGuestEnteredACPIMode(BOOL *aEntered) /* get the acpi device interface and query the information. */ PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase); + int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -2719,7 +2713,9 @@ STDMETHODIMP Console::SleepButton() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if (mMachineState != MachineState_Running) /** @todo Live Migration: ??? */ + if ( mMachineState != MachineState_Running + && mMachineState != MachineState_Teleporting + && mMachineState != MachineState_LiveSnapshotting) return setInvalidMachineStateError(); /* get the VM handle. */ @@ -2731,7 +2727,7 @@ STDMETHODIMP Console::SleepButton() /* get the acpi device interface and press the sleep button. */ PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase); + int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -2755,235 +2751,93 @@ STDMETHODIMP Console::SleepButton() STDMETHODIMP Console::SaveState(IProgress **aProgress) { LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); - CheckComArgOutPointerValid(aProgress); + HRESULT rc = saveState(Reason_Unspecified, aProgress); + + LogFlowThisFunc(("rc=%Rhrc\n", rc)); + LogFlowThisFuncLeave(); + return rc; +} + +STDMETHODIMP Console::AdoptSavedState(IN_BSTR aSavedStateFile) +{ + CheckComArgStrNotEmptyOrNull(aSavedStateFile); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if ( mMachineState != MachineState_Running - && mMachineState != MachineState_Paused) - { + if ( mMachineState != MachineState_PoweredOff + && mMachineState != MachineState_Teleported + && mMachineState != MachineState_Aborted + ) return setError(VBOX_E_INVALID_VM_STATE, - tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"), + tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"), Global::stringifyMachineState(mMachineState)); - } - /* memorize the current machine state */ - MachineState_T lastMachineState = mMachineState; + return mControl->AdoptSavedState(aSavedStateFile); +} - if (mMachineState == MachineState_Running) - { - /* get the VM handle. */ - SafeVMPtr ptrVM(this); - if (!ptrVM.isOk()) - return ptrVM.rc(); +STDMETHODIMP Console::DiscardSavedState(BOOL aRemoveFile) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* release the lock before a VMR3* call (EMT will call us back)! */ - alock.release(); - int vrc = VMR3Suspend(ptrVM); - alock.acquire(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - HRESULT hrc = S_OK; - if (RT_FAILURE(vrc)) - hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); - if (FAILED(hrc)) - return hrc; - } + if (mMachineState != MachineState_Saved) + return setError(VBOX_E_INVALID_VM_STATE, + tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"), + Global::stringifyMachineState(mMachineState)); - HRESULT rc = S_OK; - bool fBeganSavingState = false; - bool fTaskCreationFailed = false; + HRESULT rc = mControl->SetRemoveSavedStateFile(aRemoveFile); + if (FAILED(rc)) return rc; - do - { - ComPtr pProgress; - Bstr stateFilePath; + /* + * Saved -> PoweredOff transition will be detected in the SessionMachine + * and properly handled. + */ + rc = setMachineState(MachineState_PoweredOff); - /* - * request a saved state file path from the server - * (this will set the machine state to Saving on the server to block - * others from accessing this machine) - */ - rc = mControl->BeginSavingState(pProgress.asOutParam(), - stateFilePath.asOutParam()); - if (FAILED(rc)) - break; + return rc; +} - fBeganSavingState = true; +/** read the value of a LED. */ +inline uint32_t readAndClearLed(PPDMLED pLed) +{ + if (!pLed) + return 0; + uint32_t u32 = pLed->Actual.u32 | pLed->Asserted.u32; + pLed->Asserted.u32 = 0; + return u32; +} - /* sync the state with the server */ - setMachineStateLocally(MachineState_Saving); +STDMETHODIMP Console::GetDeviceActivity(DeviceType_T aDeviceType, + DeviceActivity_T *aDeviceActivity) +{ + CheckComArgNotNull(aDeviceActivity); - /* ensure the directory for the saved state file exists */ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* + * Note: we don't lock the console object here because + * readAndClearLed() should be thread safe. + */ + + /* Get LED array to read */ + PDMLEDCORE SumLed = {0}; + switch (aDeviceType) + { + case DeviceType_Floppy: + case DeviceType_DVD: + case DeviceType_HardDisk: { - Utf8Str dir = stateFilePath; - dir.stripFilename(); - if (!RTDirExists(dir.c_str())) - { - int vrc = RTDirCreateFullPath(dir.c_str(), 0700); - if (RT_FAILURE(vrc)) - { - rc = setError(VBOX_E_FILE_ERROR, - tr("Could not create a directory '%s' to save the state to (%Rrc)"), - dir.c_str(), vrc); - break; - } - } - } - - /* create a task object early to ensure mpVM protection is successful */ - std::auto_ptr task(new VMSaveTask(this, pProgress, - stateFilePath, - lastMachineState)); - rc = task->rc(); - /* - * If we fail here it means a PowerDown() call happened on another - * thread while we were doing Pause() (which releases the Console lock). - * We assign PowerDown() a higher precedence than SaveState(), - * therefore just return the error to the caller. - */ - if (FAILED(rc)) - { - fTaskCreationFailed = true; - break; - } - - /* create a thread to wait until the VM state is saved */ - int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *)task.get(), - 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave"); - if (RT_FAILURE(vrc)) - { - rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc); - break; - } - - /* task is now owned by saveStateThread(), so release it */ - task.release(); - - /* return the progress to the caller */ - pProgress.queryInterfaceTo(aProgress); - } while (0); - - if (FAILED(rc) && !fTaskCreationFailed) - { - /* preserve existing error info */ - ErrorInfoKeeper eik; - - if (fBeganSavingState) - { - /* - * cancel the requested save state procedure. - * This will reset the machine state to the state it had right - * before calling mControl->BeginSavingState(). - */ - mControl->EndSavingState(eik.getResultCode(), eik.getText().raw()); - } - - if (lastMachineState == MachineState_Running) - { - /* restore the paused state if appropriate */ - setMachineStateLocally(MachineState_Paused); - /* restore the running state if appropriate */ - SafeVMPtr ptrVM(this); - if (ptrVM.isOk()) - { - alock.release(); - VMR3Resume(ptrVM); - alock.acquire(); - } - } - else - setMachineStateLocally(lastMachineState); - } - - LogFlowThisFunc(("rc=%Rhrc\n", rc)); - LogFlowThisFuncLeave(); - return rc; -} - -STDMETHODIMP Console::AdoptSavedState(IN_BSTR aSavedStateFile) -{ - CheckComArgStrNotEmptyOrNull(aSavedStateFile); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if ( mMachineState != MachineState_PoweredOff - && mMachineState != MachineState_Teleported - && mMachineState != MachineState_Aborted - ) - return setError(VBOX_E_INVALID_VM_STATE, - tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"), - Global::stringifyMachineState(mMachineState)); - - return mControl->AdoptSavedState(aSavedStateFile); -} - -STDMETHODIMP Console::DiscardSavedState(BOOL aRemoveFile) -{ - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (mMachineState != MachineState_Saved) - return setError(VBOX_E_INVALID_VM_STATE, - tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"), - Global::stringifyMachineState(mMachineState)); - - HRESULT rc = mControl->SetRemoveSavedStateFile(aRemoveFile); - if (FAILED(rc)) return rc; - - /* - * Saved -> PoweredOff transition will be detected in the SessionMachine - * and properly handled. - */ - rc = setMachineState(MachineState_PoweredOff); - - return rc; -} - -/** read the value of a LED. */ -inline uint32_t readAndClearLed(PPDMLED pLed) -{ - if (!pLed) - return 0; - uint32_t u32 = pLed->Actual.u32 | pLed->Asserted.u32; - pLed->Asserted.u32 = 0; - return u32; -} - -STDMETHODIMP Console::GetDeviceActivity(DeviceType_T aDeviceType, - DeviceActivity_T *aDeviceActivity) -{ - CheckComArgNotNull(aDeviceActivity); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* - * Note: we don't lock the console object here because - * readAndClearLed() should be thread safe. - */ - - /* Get LED array to read */ - PDMLEDCORE SumLed = {0}; - switch (aDeviceType) - { - case DeviceType_Floppy: - case DeviceType_DVD: - case DeviceType_HardDisk: - { - for (unsigned i = 0; i < RT_ELEMENTS(mapStorageLeds); ++i) - if (maStorageDevType[i] == aDeviceType) - SumLed.u32 |= readAndClearLed(mapStorageLeds[i]); - break; + for (unsigned i = 0; i < RT_ELEMENTS(mapStorageLeds); ++i) + if (maStorageDevType[i] == aDeviceType) + SumLed.u32 |= readAndClearLed(mapStorageLeds[i]); + break; } case DeviceType_Network: @@ -3049,10 +2903,8 @@ STDMETHODIMP Console::AttachUSBDevice(IN_BSTR aId) if (!ptrVM.isOk()) return ptrVM.rc(); - /* Don't proceed unless we've found the usb controller. */ - PPDMIBASE pBase = NULL; - int vrc = PDMR3QueryLun(ptrVM, "usb-ohci", 0, 0, &pBase); - if (RT_FAILURE(vrc)) + /* Don't proceed unless we have a USB controller. */ + if (!mfVMHasUsbController) return setError(VBOX_E_PDM_ERROR, tr("The virtual machine does not have a USB controller")); @@ -3176,7 +3028,7 @@ STDMETHODIMP Console::FindUSBDeviceByAddress(IN_BSTR aAddress, IUSBDevice **aDev STDMETHODIMP Console::FindUSBDeviceById(IN_BSTR aId, IUSBDevice **aDevice) { #ifdef VBOX_WITH_USB - CheckComArgExpr(aId, Guid(aId).isEmpty() == false); + CheckComArgExpr(aId, Guid(aId).isValid()); CheckComArgOutPointerValid(aDevice); *aDevice = NULL; @@ -3359,7 +3211,6 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName, IProgress **aProgress) { LogFlowThisFuncEnter(); - LogFlowThisFunc(("aName='%ls' mMachineState=%d\n", aName, mMachineState)); CheckComArgStrNotEmptyOrNull(aName); CheckComArgOutPointerValid(aProgress); @@ -3368,6 +3219,7 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName, if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("aName='%ls' mMachineState=%d\n", aName, mMachineState)); if (Global::IsTransient(mMachineState)) return setError(VBOX_E_INVALID_VM_STATE, @@ -3488,7 +3340,7 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName, STDMETHODIMP Console::DeleteSnapshot(IN_BSTR aId, IProgress **aProgress) { - CheckComArgExpr(aId, Guid(aId).isEmpty() == false); + CheckComArgExpr(aId, Guid(aId).isValid()); CheckComArgOutPointerValid(aProgress); AutoCaller autoCaller(this); @@ -3511,7 +3363,7 @@ STDMETHODIMP Console::DeleteSnapshot(IN_BSTR aId, IProgress **aProgress) STDMETHODIMP Console::DeleteSnapshotAndAllChildren(IN_BSTR aId, IProgress **aProgress) { - CheckComArgExpr(aId, Guid(aId).isEmpty() == false); + CheckComArgExpr(aId, Guid(aId).isValid()); CheckComArgOutPointerValid(aProgress); AutoCaller autoCaller(this); @@ -3534,8 +3386,8 @@ STDMETHODIMP Console::DeleteSnapshotAndAllChildren(IN_BSTR aId, IProgress **aPro STDMETHODIMP Console::DeleteSnapshotRange(IN_BSTR aStartId, IN_BSTR aEndId, IProgress **aProgress) { - CheckComArgExpr(aStartId, Guid(aStartId).isEmpty() == false); - CheckComArgExpr(aEndId, Guid(aEndId).isEmpty() == false); + CheckComArgExpr(aStartId, Guid(aStartId).isValid()); + CheckComArgExpr(aEndId, Guid(aEndId).isValid()); CheckComArgOutPointerValid(aProgress); AutoCaller autoCaller(this); @@ -3653,17 +3505,94 @@ HRESULT Console::convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG // private methods ///////////////////////////////////////////////////////////////////////////// + +/** + * Suspend the VM before we do any medium or network attachment change. + * + * @param pUVM Safe VM handle. + * @param pAlock The automatic lock instance. This is for when we have + * to leave it in order to avoid deadlocks. + * @param pfSuspend where to store the information if we need to resume + * afterwards. + */ +HRESULT Console::suspendBeforeConfigChange(PUVM pUVM, AutoWriteLock *pAlock, bool *pfResume) +{ + *pfResume = false; + VMSTATE enmVMState = VMR3GetStateU(pUVM); + switch (enmVMState) + { + case VMSTATE_RESETTING: + case VMSTATE_RUNNING: + { + LogFlowFunc(("Suspending the VM...\n")); + /* disable the callback to prevent Console-level state change */ + mVMStateChangeCallbackDisabled = true; + if (pAlock) + pAlock->release(); + int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); + if (pAlock) + pAlock->acquire(); + mVMStateChangeCallbackDisabled = false; + if (RT_FAILURE(rc)) + return setErrorInternal(VBOX_E_INVALID_VM_STATE, + COM_IIDOF(IConsole), + getStaticComponentName(), + Utf8StrFmt("Couldn't suspend VM for medium change (%Rrc)", rc), + false /*aWarning*/, + true /*aLogIt*/); + *pfResume = true; + break; + } + case VMSTATE_SUSPENDED: + break; + default: + return setErrorInternal(VBOX_E_INVALID_VM_STATE, + COM_IIDOF(IConsole), + getStaticComponentName(), + Utf8StrFmt("Invalid VM state '%s' for changing medium", + VMR3GetStateName(enmVMState)), + false /*aWarning*/, + true /*aLogIt*/); + } + + return S_OK; +} + +/** + * Resume the VM after we did any medium or network attachment change. + * This is the counterpart to Console::suspendBeforeConfigChange(). + * + * @param pUVM Safe VM handle. + */ +void Console::resumeAfterConfigChange(PUVM pUVM) +{ + LogFlowFunc(("Resuming the VM...\n")); + /* disable the callback to prevent Console-level state change */ + mVMStateChangeCallbackDisabled = true; + int rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); + mVMStateChangeCallbackDisabled = false; + AssertRC(rc); + if (RT_FAILURE(rc)) + { + VMSTATE enmVMState = VMR3GetStateU(pUVM); + if (enmVMState == VMSTATE_SUSPENDED) + { + /* too bad, we failed. try to sync the console state with the VMM state */ + vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, this); + } + } +} /** * Process a medium change. * * @param aMediumAttachment The medium attachment with the new medium state. * @param fForce Force medium chance, if it is locked or not. - * @param pVM Safe VM handle. + * @param pUVM Safe VM handle. * * @note Locks this object for writing. */ -HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PVM pVM) +HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PUVM pUVM) { AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); @@ -3721,27 +3650,24 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache); AssertComRC(rc); + /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCall(pVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::changeRemovableMedium, - 8, - this, - pVM, - pszDevice, - uInstance, - enmBus, - fUseHostIOCache, - aMediumAttachment, - fForce); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)changeRemovableMedium, 8, + this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fForce); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -3755,6 +3681,9 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -3777,7 +3706,7 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc * @returns VBox status code. * * @param pThis Pointer to the Console object. - * @param pVM The VM handle. + * @param pUVM The VM handle. * @param pcszDevice The PDM device name. * @param uInstance The PDM device instance. * @param uLun The PDM LUN number of the drive. @@ -3790,9 +3719,10 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole, - PVM pVM, +DECLCALLBACK(int) Console::changeRemovableMedium(Console *pThis, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, @@ -3800,112 +3730,49 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole, IMediumAttachment *aMediumAtt, bool fForce) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; - VMSTATE enmVMState = VMR3GetState(pVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + VMSTATE enmVMState = VMR3GetStateU(pUVM); + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; - pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance); + pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; - - rcRet = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - false /* fSetupMerge */, - false /* fBuiltinIOCache */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAtt, - pConsole->mMachineState, - NULL /* phrc */, - true /* fAttachDetach */, - fForce /* fForceUnmount */, - false /* fHotplug */, - pVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume - // error (if any) will be hidden from the caller. For proper reporting - // of such multiple errors to the caller we need to enhance the - // IVirtualBoxError interface. For now, give the first error the higher - // priority. - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + false /* fSetupMerge */, + false /* fBuiltinIOCache */, + 0 /* uMergeSource */, + 0 /* uMergeTarget */, + aMediumAtt, + pThis->mMachineState, + NULL /* phrc */, + true /* fAttachDetach */, + fForce /* fForceUnmount */, + false /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } @@ -3913,11 +3780,12 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole, * Attach a new storage device to the VM. * * @param aMediumAttachment The medium attachment which is added. - * @param pVM Safe VM handle. + * @param pUVM Safe VM handle. + * @param fSilent Flag whether to notify the guest about the attached device. * * @note Locks this object for writing. */ -HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM) +HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent) { AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); @@ -3975,26 +3843,24 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache); AssertComRC(rc); + /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCall(pVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::attachStorageDevice, - 7, - this, - pVM, - pszDevice, - uInstance, - enmBus, - fUseHostIOCache, - aMediumAttachment); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)attachStorageDevice, 8, + this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fSilent); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -4008,6 +3874,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -4031,138 +3900,78 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM * @returns VBox status code. * * @param pThis Pointer to the Console object. - * @param pVM The VM handle. + * @param pUVM The VM handle. * @param pcszDevice The PDM device name. * @param uInstance The PDM device instance. + * @param fSilent Flag whether to inform the guest about the attached device. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole, - PVM pVM, +DECLCALLBACK(int) Console::attachStorageDevice(Console *pThis, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, bool fUseHostIOCache, - IMediumAttachment *aMediumAtt) + IMediumAttachment *aMediumAtt, + bool fSilent) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; - VMSTATE enmVMState = VMR3GetState(pVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + VMSTATE enmVMState = VMR3GetStateU(pUVM); + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; - pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance); + pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; - - rcRet = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - false /* fSetupMerge */, - false /* fBuiltinIOCache */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAtt, - pConsole->mMachineState, - NULL /* phrc */, - true /* fAttachDetach */, - false /* fForceUnmount */, - true /* fHotplug */, - pVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /** @todo: if we failed with drive mount, then the VMR3Resume - * error (if any) will be hidden from the caller. For proper reporting - * of such multiple errors to the caller we need to enhance the - * IVirtualBoxError interface. For now, give the first error the higher - * priority. - */ - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + false /* fSetupMerge */, + false /* fBuiltinIOCache */, + 0 /* uMergeSource */, + 0 /* uMergeTarget */, + aMediumAtt, + pThis->mMachineState, + NULL /* phrc */, + true /* fAttachDetach */, + false /* fForceUnmount */, + !fSilent /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } /** * Attach a new storage device to the VM. * * @param aMediumAttachment The medium attachment which is added. - * @param pVM Safe VM handle. + * @param pUVM Safe VM handle. + * @param fSilent Flag whether to notify the guest about the detached device. * * @note Locks this object for writing. */ -HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM) +HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent) { AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); @@ -4217,25 +4026,24 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM rc = pStorageController->COMGETTER(Instance)(&uInstance); AssertComRC(rc); + /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCall(pVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::detachStorageDevice, - 6, - this, - pVM, - pszDevice, - uInstance, - enmBus, - aMediumAttachment); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)detachStorageDevice, 7, + this, pUVM, pszDevice, uInstance, enmBus, aMediumAttachment, fSilent); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -4249,6 +4057,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -4271,72 +4082,39 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM * @returns VBox status code. * * @param pThis Pointer to the Console object. - * @param pVM The VM handle. + * @param pUVM The VM handle. * @param pcszDevice The PDM device name. * @param uInstance The PDM device instance. + * @param fSilent Flag whether to notify the guest about the detached device. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, - PVM pVM, +DECLCALLBACK(int) Console::detachStorageDevice(Console *pThis, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, - IMediumAttachment *pMediumAtt) + IMediumAttachment *pMediumAtt, + bool fSilent) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; - VMSTATE enmVMState = VMR3GetState(pVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + VMSTATE enmVMState = VMR3GetStateU(pUVM); + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; - pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance); + pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); #define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE) @@ -4362,14 +4140,19 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN); if (pLunL0) { - rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, 0); + uint32_t fFlags = 0; + + if (fSilent) + fFlags |= PDM_TACH_FLAGS_NOT_HOT_PLUG; + + rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fFlags); if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN) rc = VINF_SUCCESS; AssertRCReturn(rc, rc); CFGMR3RemoveNode(pLunL0); Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN); - pConsole->mapMediumAttachments.erase(devicePath); + pThis->mapMediumAttachments.erase(devicePath); } else @@ -4377,32 +4160,6 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, CFGMR3Dump(pCtlInst); - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pVM); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /** @todo: if we failed with drive mount, then the VMR3Resume - * error (if any) will be hidden from the caller. For proper reporting - * of such multiple errors to the caller we need to enhance the - * IVirtualBoxError interface. For now, give the first error the higher - * priority. - */ - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - LogFlowFunc(("Returning %Rrc\n", rcRet)); return rcRet; } @@ -4423,7 +4180,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c HRESULT rc = S_OK; - /* don't trigger network change if the VM isn't running */ + /* don't trigger network changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { @@ -4456,7 +4213,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c alock.release(); PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase); + int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase); if (RT_SUCCESS(vrc)) { Assert(pBase); @@ -4473,7 +4230,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c } if (RT_SUCCESS(vrc) && changeAdapter) { - VMSTATE enmVMState = VMR3GetState(ptrVM); + VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM()); if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbid or deal correctly with the _LS variants */ || enmVMState == VMSTATE_SUSPENDED) { @@ -4483,7 +4240,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c ComAssertRC(vrc); } - rc = doNetworkAdapterChange(ptrVM, pszAdapterName, ulInstance, 0, aNetworkAdapter); + rc = doNetworkAdapterChange(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, aNetworkAdapter); if (fTraceEnabled && fCableConnected && pINetCfg) { @@ -4536,7 +4293,7 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove, HRESULT rc = S_OK; - /* don't trigger nat engine change if the VM isn't running */ + /* don't trigger NAT engine changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { @@ -4563,7 +4320,7 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove, const char *pszAdapterName = networkAdapterTypeToName(adapterType); PPDMIBASE pBase; - int vrc = PDMR3QueryLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase); + int vrc = PDMR3QueryLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase); if (RT_FAILURE(vrc)) { ComAssertRC(vrc); @@ -4596,8 +4353,8 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove, bool fUdp = aProto == NATProtocol_UDP; vrc = pNetNatCfg->pfnRedirectRuleCommand(pNetNatCfg, !!aNatRuleRemove, fUdp, - Utf8Str(aHostIP).c_str(), aHostPort, Utf8Str(aGuestIP).c_str(), - aGuestPort); + Utf8Str(aHostIP).c_str(), (uint16_t)aHostPort, Utf8Str(aGuestIP).c_str(), + (uint16_t)aGuestPort); if (RT_FAILURE(vrc)) rc = E_FAIL; } while (0); /* break loop */ @@ -4608,19 +4365,28 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove, return rc; } +VMMDevMouseInterface *Console::getVMMDevMouseInterface() +{ + return m_pVMMDev; +} + +DisplayMouseInterface *Console::getDisplayMouseInterface() +{ + return mDisplay; +} /** * Process a network adaptor change. * * @returns COM status code. * - * @parma pVM The VM handle (caller hold this safely). + * @parma pUVM The VM handle (caller hold this safely). * @param pszDevice The PDM device name. * @param uInstance The PDM device instance. * @param uLun The PDM LUN number of the drive. * @param aNetworkAdapter The network adapter whose attachment needs to be changed */ -HRESULT Console::doNetworkAdapterChange(PVM pVM, +HRESULT Console::doNetworkAdapterChange(PUVM pUVM, const char *pszDevice, unsigned uInstance, unsigned uLun, @@ -4632,10 +4398,13 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM, AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); - /* Get the VM handle. */ - SafeVMPtr ptrVM(this); - if (!ptrVM.isOk()) - return ptrVM.rc(); + /* + * Suspend the VM first. + */ + bool fResume = false; + int rc = suspendBeforeConfigChange(pUVM, NULL, &fResume); + if (FAILED(rc)) + return rc; /* * Call worker in EMT, that's faster and safer than doing everything @@ -4643,9 +4412,9 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM, * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCall(pVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT) Console::changeNetworkAttachment, 6, - this, ptrVM.raw(), pszDevice, uInstance, uLun, aNetworkAdapter); + int vrc = VMR3ReqCallU(pUVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)changeNetworkAttachment, 6, + this, pUVM, pszDevice, uInstance, uLun, aNetworkAdapter); if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc)) { @@ -4656,6 +4425,9 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM, } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -4674,7 +4446,7 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM, * @returns VBox status code. * * @param pThis Pointer to the Console object. - * @param pVM The VM handle. + * @param pUVM The VM handle. * @param pszDevice The PDM device name. * @param uInstance The PDM device instance. * @param uLun The PDM LUN number of the drive. @@ -4682,9 +4454,10 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM, * * @thread EMT * @note Locks the Console object for writing. + * @note The VM must not be running. */ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis, - PVM pVM, + PUVM pUVM, const char *pszDevice, unsigned uInstance, unsigned uLun, @@ -4717,76 +4490,21 @@ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis, Log(("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance)); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; - VMSTATE enmVMState = VMR3GetState(pVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pThis->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pVM); - pThis->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - default: - AssertLogRelMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } - - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; + VMSTATE enmVMState = VMR3GetStateU(pUVM); + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */ PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */ - PCFGMNODE pInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%d/", pszDevice, uInstance); + PCFGMNODE pInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%d/", pszDevice, uInstance); AssertRelease(pInst); - rcRet = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst, - true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pThis->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pVM); - pThis->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, pThis); - } - /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume - // error (if any) will be hidden from the caller. For proper reporting - // of such multiple errors to the caller we need to enhance the - // IVirtualBoxError interface. For now, give the first error the higher - // priority. - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } + int rc = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst, + true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/); - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } @@ -4850,11 +4568,11 @@ HRESULT Console::onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForc HRESULT rc = S_OK; - /* don't trigger medium change if the VM isn't running */ + /* don't trigger medium changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { - rc = doMediumChange(aMediumAttachment, !!aForce, ptrVM); + rc = doMediumChange(aMediumAttachment, !!aForce, ptrVM.rawUVM()); ptrVM.release(); } @@ -4880,14 +4598,14 @@ HRESULT Console::onCPUChange(ULONG aCPU, BOOL aRemove) HRESULT rc = S_OK; - /* don't trigger CPU change if the VM isn't running */ + /* don't trigger CPU changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { if (aRemove) - rc = doCPURemove(aCPU, ptrVM); + rc = doCPURemove(aCPU, ptrVM.rawUVM()); else - rc = doCPUAdd(aCPU, ptrVM); + rc = doCPUAdd(aCPU, ptrVM.rawUVM()); ptrVM.release(); } @@ -4925,7 +4643,7 @@ HRESULT Console::onCPUExecutionCapChange(ULONG aExecutionCap) ) { /* No need to call in the EMT thread. */ - rc = VMR3SetCpuExecutionCap(ptrVM, aExecutionCap); + rc = VMR3SetCpuExecutionCap(ptrVM.rawUVM(), aExecutionCap); } else rc = setInvalidMachineStateError(); @@ -4959,7 +4677,7 @@ HRESULT Console::onClipboardModeChange(ClipboardMode_T aClipboardMode) HRESULT rc = S_OK; - /* don't trigger the Clipboard mode change if the VM isn't running */ + /* don't trigger the clipboard mode change if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { @@ -4999,7 +4717,7 @@ HRESULT Console::onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode) HRESULT rc = S_OK; - /* don't trigger the Drag'n'drop mode change if the VM isn't running */ + /* don't trigger the drag'n'drop mode change if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { @@ -5037,42 +4755,63 @@ HRESULT Console::onVRDEServerChange(BOOL aRestart) HRESULT rc = S_OK; - if ( mVRDEServer - && ( mMachineState == MachineState_Running - || mMachineState == MachineState_Teleporting - || mMachineState == MachineState_LiveSnapshotting - ) - ) + /* don't trigger VRDE server changes if the VM isn't running */ + SafeVMPtrQuiet ptrVM(this); + if (ptrVM.isOk()) { - BOOL vrdpEnabled = FALSE; + /* Serialize. */ + if (mfVRDEChangeInProcess) + mfVRDEChangePending = true; + else + { + do { + mfVRDEChangeInProcess = true; + mfVRDEChangePending = false; + + if ( mVRDEServer + && ( mMachineState == MachineState_Running + || mMachineState == MachineState_Teleporting + || mMachineState == MachineState_LiveSnapshotting + || mMachineState == MachineState_Paused + ) + ) + { + BOOL vrdpEnabled = FALSE; - rc = mVRDEServer->COMGETTER(Enabled)(&vrdpEnabled); - ComAssertComRCRetRC(rc); + rc = mVRDEServer->COMGETTER(Enabled)(&vrdpEnabled); + ComAssertComRCRetRC(rc); - if (aRestart) - { - /* VRDP server may call this Console object back from other threads (VRDP INPUT or OUTPUT). */ - alock.release(); + if (aRestart) + { + /* VRDP server may call this Console object back from other threads (VRDP INPUT or OUTPUT). */ + alock.release(); - if (vrdpEnabled) - { - // If there was no VRDP server started the 'stop' will do nothing. - // However if a server was started and this notification was called, - // we have to restart the server. - mConsoleVRDPServer->Stop(); + if (vrdpEnabled) + { + // If there was no VRDP server started the 'stop' will do nothing. + // However if a server was started and this notification was called, + // we have to restart the server. + mConsoleVRDPServer->Stop(); + + if (RT_FAILURE(mConsoleVRDPServer->Launch())) + rc = E_FAIL; + else + mConsoleVRDPServer->EnableConnections(); + } + else + mConsoleVRDPServer->Stop(); - if (RT_FAILURE(mConsoleVRDPServer->Launch())) - rc = E_FAIL; + alock.acquire(); + } + } else - mConsoleVRDPServer->EnableConnections(); - } - else - { - mConsoleVRDPServer->Stop(); - } + rc = setInvalidMachineStateError(); - alock.acquire(); + mfVRDEChangeInProcess = false; + } while (mfVRDEChangePending && SUCCEEDED(rc)); } + + ptrVM.release(); } /* notify console callbacks on success */ @@ -5093,6 +4832,55 @@ void Console::onVRDEServerInfoChange() fireVRDEServerInfoChangedEvent(mEventSource); } +HRESULT Console::onVideoCaptureChange() +{ + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = S_OK; + + /* don't trigger video capture changes if the VM isn't running */ + SafeVMPtrQuiet ptrVM(this); + if (ptrVM.isOk()) + { + BOOL fEnabled; + rc = mMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled); + SafeArray screens; + if (SUCCEEDED(rc)) + rc = mMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens)); + if (mDisplay) + { + int vrc = VINF_SUCCESS; + if (SUCCEEDED(rc)) + vrc = mDisplay->VideoCaptureEnableScreens(ComSafeArrayAsInParam(screens)); + if (RT_SUCCESS(vrc)) + { + if (fEnabled) + { + vrc = mDisplay->VideoCaptureStart(); + if (RT_FAILURE(vrc)) + rc = setError(E_FAIL, tr("Unable to start video capturing (%Rrc)"), vrc); + } + else + mDisplay->VideoCaptureStop(); + } + else + rc = setError(E_FAIL, tr("Unable to set screens for capturing (%Rrc)"), vrc); + } + ptrVM.release(); + } + + /* notify console callbacks on success */ + if (SUCCEEDED(rc)) + { + alock.release(); + fireVideoCaptureChangedEvent(mEventSource); + } + + return rc; +} /** * Called by IInternalSessionControl::OnUSBControllerChange(). @@ -5181,7 +4969,7 @@ HRESULT Console::onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aE } /* Don't proceed unless there's at least one USB hub. */ - if (!PDMR3USBHasHub(ptrVM)) + if (!PDMR3UsbHasHub(ptrVM.rawUVM())) { LogFlowThisFunc(("Attach request ignored (no USB controller).\n")); return E_FAIL; @@ -5318,7 +5106,7 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) HRESULT rc = S_OK; - /* don't trigger the CPU priority change if the VM isn't running */ + /* don't trigger bandwidth group changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { @@ -5341,12 +5129,10 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) { int vrc = VINF_SUCCESS; if (enmType == BandwidthGroupType_Disk) - vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM, Utf8Str(strName).c_str(), - cMax); + vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM.rawUVM(), Utf8Str(strName).c_str(), (uint32_t)cMax); #ifdef VBOX_WITH_NETSHAPER else if (enmType == BandwidthGroupType_Network) - vrc = PDMR3NsBwGroupSetLimit(ptrVM, Utf8Str(strName).c_str(), - cMax); + vrc = PDMR3NsBwGroupSetLimit(ptrVM.rawUVM(), Utf8Str(strName).c_str(), cMax); else rc = E_NOTIMPL; #endif /* VBOX_WITH_NETSHAPER */ @@ -5374,7 +5160,7 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) * * @note Locks this object for writing. */ -HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove) +HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent) { LogFlowThisFunc(("\n")); @@ -5383,25 +5169,67 @@ HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOO HRESULT rc = S_OK; - /* don't trigger medium change if the VM isn't running */ + /* don't trigger medium changes if the VM isn't running */ SafeVMPtrQuiet ptrVM(this); if (ptrVM.isOk()) { if (aRemove) - rc = doStorageDeviceDetach(aMediumAttachment, ptrVM); + rc = doStorageDeviceDetach(aMediumAttachment, ptrVM.rawUVM(), RT_BOOL(aSilent)); else - rc = doStorageDeviceAttach(aMediumAttachment, ptrVM); + rc = doStorageDeviceAttach(aMediumAttachment, ptrVM.rawUVM(), RT_BOOL(aSilent)); ptrVM.release(); } /* notify console callbacks on success */ if (SUCCEEDED(rc)) - fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove); + fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove, aSilent); LogFlowThisFunc(("Leaving rc=%#x\n", rc)); return rc; } +HRESULT Console::onExtraDataChange(IN_BSTR aMachineId, IN_BSTR aKey, IN_BSTR aVal) +{ + LogFlowThisFunc(("\n")); + + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + if (!aMachineId) + return S_OK; + + HRESULT hrc = S_OK; + Bstr idMachine(aMachineId); + Bstr idSelf; + hrc = mMachine->COMGETTER(Id)(idSelf.asOutParam()); + if ( FAILED(hrc) + || idMachine != idSelf) + return hrc; + + /* don't do anything if the VM isn't running */ + SafeVMPtrQuiet ptrVM(this); + if (ptrVM.isOk()) + { + Bstr strKey(aKey); + Bstr strVal(aVal); + + if (strKey == "VBoxInternal2/TurnResetIntoPowerOff") + { + int vrc = VMR3SetPowerOffInsteadOfReset(ptrVM.rawUVM(), strVal == "1"); + AssertRC(vrc); + } + + ptrVM.release(); + } + + /* notify console callbacks on success */ + if (SUCCEEDED(hrc)) + fireExtraDataChangedEvent(mEventSource, aMachineId, aKey, aVal); + + LogFlowThisFunc(("Leaving hrc=%#x\n", hrc)); + return hrc; +} + /** * @note Temporarily locks this object for writing. */ @@ -5423,12 +5251,13 @@ HRESULT Console::getGuestProperty(IN_BSTR aName, BSTR *aValue, AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); - /* protect mpVM (if not NULL) */ - AutoVMCallerWeak autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* protect mpUVM (if not NULL) */ + SafeVMPtrQuiet ptrVM(this); + if (FAILED(ptrVM.rc())) + return ptrVM.rc(); /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by - * autoVMCaller, so there is no need to hold a lock of this */ + * ptrVM, so there is no need to hold a lock of this */ HRESULT rc = E_UNEXPECTED; using namespace guestProp; @@ -5492,51 +5321,56 @@ HRESULT Console::setGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags) #ifndef VBOX_WITH_GUEST_PROPS ReturnComNotImplemented(); #else /* VBOX_WITH_GUEST_PROPS */ - if (!VALID_PTR(aName)) - return E_INVALIDARG; - if ((aValue != NULL) && !VALID_PTR(aValue)) - return E_INVALIDARG; - if ((aFlags != NULL) && !VALID_PTR(aFlags)) - return E_INVALIDARG; + if (!RT_VALID_PTR(aName)) + return setError(E_INVALIDARG, tr("Name cannot be NULL or an invalid pointer")); + if (aValue != NULL && !RT_VALID_PTR(aValue)) + return setError(E_INVALIDARG, tr("Invalid value pointer")); + if (aFlags != NULL && !RT_VALID_PTR(aFlags)) + return setError(E_INVALIDARG, tr("Invalid flags pointer")); AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); - /* protect mpVM (if not NULL) */ - AutoVMCallerWeak autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* protect mpUVM (if not NULL) */ + SafeVMPtrQuiet ptrVM(this); + if (FAILED(ptrVM.rc())) + return ptrVM.rc(); /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by - * autoVMCaller, so there is no need to hold a lock of this */ + * ptrVM, so there is no need to hold a lock of this */ - HRESULT rc = E_UNEXPECTED; using namespace guestProp; VBOXHGCMSVCPARM parm[3]; - Utf8Str Utf8Name = aName; - int vrc = VINF_SUCCESS; + Utf8Str Utf8Name = aName; parm[0].type = VBOX_HGCM_SVC_PARM_PTR; parm[0].u.pointer.addr = (void*)Utf8Name.c_str(); /* The + 1 is the null terminator */ parm[0].u.pointer.size = (uint32_t)Utf8Name.length() + 1; - Utf8Str Utf8Value = aValue; + + Utf8Str Utf8Value; if (aValue != NULL) { + Utf8Value = aValue; parm[1].type = VBOX_HGCM_SVC_PARM_PTR; - parm[1].u.pointer.addr = (void*)Utf8Value.c_str(); + parm[1].u.pointer.addr = (void *)Utf8Value.c_str(); /* The + 1 is the null terminator */ parm[1].u.pointer.size = (uint32_t)Utf8Value.length() + 1; } - Utf8Str Utf8Flags = aFlags; + + Utf8Str Utf8Flags; if (aFlags != NULL) { + Utf8Flags = aFlags; parm[2].type = VBOX_HGCM_SVC_PARM_PTR; parm[2].u.pointer.addr = (void*)Utf8Flags.c_str(); /* The + 1 is the null terminator */ parm[2].u.pointer.size = (uint32_t)Utf8Flags.length() + 1; } - if ((aValue != NULL) && (aFlags != NULL)) + + int vrc; + if (aValue != NULL && aFlags != NULL) vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", SET_PROP_HOST, 3, &parm[0]); else if (aValue != NULL) @@ -5545,13 +5379,12 @@ HRESULT Console::setGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags) else vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", DEL_PROP_HOST, 1, &parm[0]); + HRESULT hrc; if (RT_SUCCESS(vrc)) - rc = S_OK; + hrc = S_OK; else - rc = setError(E_UNEXPECTED, - tr("The service call failed with the error %Rrc"), - vrc); - return rc; + hrc = setError(E_UNEXPECTED, tr("The service call failed with the error %Rrc"), vrc); + return hrc; #endif /* VBOX_WITH_GUEST_PROPS */ } @@ -5582,9 +5415,10 @@ HRESULT Console::enumerateGuestProperties(IN_BSTR aPatterns, AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); - /* protect mpVM (if not NULL) */ + /* protect mpUVM (if not NULL) */ AutoVMCallerWeak autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + if (FAILED(autoVMCaller.rc())) + return autoVMCaller.rc(); /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by * autoVMCaller, so there is no need to hold a lock of this */ @@ -5614,10 +5448,6 @@ static int onlineMergeMediumProgress(void *pvUser, unsigned uPercentage) */ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, ULONG aSourceIdx, ULONG aTargetIdx, - IMedium *aSource, IMedium *aTarget, - BOOL aMergeForward, - IMedium *aParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent), IProgress *aProgress) { AutoCaller autoCaller(this); @@ -5711,34 +5541,22 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, alock.release(); /* Pause the VM, as it might have pending IO on this drive */ - VMSTATE enmVMState = VMR3GetState(ptrVM); + VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM()); if (mMachineState == MachineState_DeletingSnapshotOnline) { LogFlowFunc(("Suspending the VM...\n")); /* disable the callback to prevent Console-level state change */ mVMStateChangeCallbackDisabled = true; - int vrc2 = VMR3Suspend(ptrVM); + int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG); mVMStateChangeCallbackDisabled = false; AssertRCReturn(vrc2, E_FAIL); } - vrc = VMR3ReqCallWait(ptrVM, - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - this, - ptrVM.raw(), - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - true /* fSetupMerge */, - aSourceIdx, - aTargetIdx, - aMediumAttachment, - mMachineState, - &rc); + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, true /* fSetupMerge */, aSourceIdx, aTargetIdx, + aMediumAttachment, mMachineState, &rc); /* error handling is after resuming the VM */ if (mMachineState == MachineState_DeletingSnapshotOnline) @@ -5746,13 +5564,13 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, LogFlowFunc(("Resuming the VM...\n")); /* disable the callback to prevent Console-level state change */ mVMStateChangeCallbackDisabled = true; - int vrc2 = VMR3Resume(ptrVM); + int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG); mVMStateChangeCallbackDisabled = false; if (RT_FAILURE(vrc2)) { /* too bad, we failed. try to sync the console state with the VMM state */ AssertLogRelRC(vrc2); - vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this); + vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this); } } @@ -5763,7 +5581,7 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, PPDMIBASE pIBase = NULL; PPDMIMEDIA pIMedium = NULL; - vrc = PDMR3QueryDriverOnLun(ptrVM, pcszDevice, uInstance, uLUN, "VD", &pIBase); + vrc = PDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, uInstance, uLUN, "VD", &pIBase); if (RT_SUCCESS(vrc)) { if (pIBase) @@ -5782,39 +5600,25 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, return setError(E_FAIL, tr("Failed to perform an online medium merge (%Rrc)"), vrc); /* Pause the VM, as it might have pending IO on this drive */ - enmVMState = VMR3GetState(ptrVM); + enmVMState = VMR3GetStateU(ptrVM.rawUVM()); if (mMachineState == MachineState_DeletingSnapshotOnline) { LogFlowFunc(("Suspending the VM...\n")); /* disable the callback to prevent Console-level state change */ mVMStateChangeCallbackDisabled = true; - int vrc2 = VMR3Suspend(ptrVM); + int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG); mVMStateChangeCallbackDisabled = false; AssertRCReturn(vrc2, E_FAIL); } /* Update medium chain and state now, so that the VM can continue. */ - rc = mControl->FinishOnlineMergeMedium(aMediumAttachment, aSource, aTarget, - aMergeForward, aParentForTarget, - ComSafeArrayInArg(aChildrenToReparent)); - - vrc = VMR3ReqCallWait(ptrVM, - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - this, - ptrVM.raw(), - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - false /* fSetupMerge */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAttachment, - mMachineState, - &rc); + rc = mControl->FinishOnlineMergeMedium(); + + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */, + 0 /* uMergeTarget */, aMediumAttachment, mMachineState, &rc); /* error handling is after resuming the VM */ if (mMachineState == MachineState_DeletingSnapshotOnline) @@ -5822,13 +5626,13 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, LogFlowFunc(("Resuming the VM...\n")); /* disable the callback to prevent Console-level state change */ mVMStateChangeCallbackDisabled = true; - int vrc2 = VMR3Resume(ptrVM); + int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG); mVMStateChangeCallbackDisabled = false; AssertRC(vrc2); if (RT_FAILURE(vrc2)) { /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this); + vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this); } } @@ -5841,6 +5645,23 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, } +/** + * Load an HGCM service. + * + * Main purpose of this method is to allow extension packs to load HGCM + * service modules, which they can't, because the HGCM functionality lives + * in module VBoxC (and ConsoleImpl.cpp is part of it and thus can call it). + * Extension modules must not link directly against VBoxC, (XP)COM is + * handling this. + */ +int Console::hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName) +{ + /* Everyone seems to delegate all HGCM calls to VMMDev, so stick to this + * convention. Adds one level of indirection for no obvious reason. */ + AssertPtrReturn(m_pVMMDev, VERR_INVALID_STATE); + return m_pVMMDev->hgcmLoadService(pszServiceLibrary, pszServiceName); +} + /** * Merely passes the call to Guest::enableVMMStatistics(). */ @@ -5850,6 +5671,289 @@ void Console::enableVMMStatistics(BOOL aEnable) mGuest->enableVMMStatistics(aEnable); } +/** + * Worker for Console::Pause and internal entry point for pausing a VM for + * a specific reason. + */ +HRESULT Console::pause(Reason_T aReason) +{ + LogFlowThisFuncEnter(); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + switch (mMachineState) + { + case MachineState_Running: + case MachineState_Teleporting: + case MachineState_LiveSnapshotting: + break; + + case MachineState_Paused: + case MachineState_TeleportingPausedVM: + case MachineState_Saving: + return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused")); + + default: + return setInvalidMachineStateError(); + } + + /* get the VM handle. */ + SafeVMPtr ptrVM(this); + if (!ptrVM.isOk()) + return ptrVM.rc(); + + /* release the lock before a VMR3* call (EMT will call us back)! */ + alock.release(); + + LogFlowThisFunc(("Sending PAUSE request...\n")); + if (aReason != Reason_Unspecified) + LogRel(("Pausing VM execution, reason \"%s\"\n", Global::stringifyReason(aReason))); + + /** @todo r=klaus make use of aReason */ + VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER; + if (aReason == Reason_HostSuspend) + enmReason = VMSUSPENDREASON_HOST_SUSPEND; + else if (aReason == Reason_HostBatteryLow) + enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW; + int vrc = VMR3Suspend(ptrVM.rawUVM(), enmReason); + + HRESULT hrc = S_OK; + if (RT_FAILURE(vrc)) + hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); + + LogFlowThisFunc(("hrc=%Rhrc\n", hrc)); + LogFlowThisFuncLeave(); + return hrc; +} + +/** + * Worker for Console::Resume and internal entry point for resuming a VM for + * a specific reason. + */ +HRESULT Console::resume(Reason_T aReason) +{ + LogFlowThisFuncEnter(); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (mMachineState != MachineState_Paused) + return setError(VBOX_E_INVALID_VM_STATE, + tr("Cannot resume the machine as it is not paused (machine state: %s)"), + Global::stringifyMachineState(mMachineState)); + + /* get the VM handle. */ + SafeVMPtr ptrVM(this); + if (!ptrVM.isOk()) + return ptrVM.rc(); + + /* release the lock before a VMR3* call (EMT will call us back)! */ + alock.release(); + + LogFlowThisFunc(("Sending RESUME request...\n")); + if (aReason != Reason_Unspecified) + LogRel(("Resuming VM execution, reason \"%s\"\n", Global::stringifyReason(aReason))); + + int vrc; + if (VMR3GetStateU(ptrVM.rawUVM()) == VMSTATE_CREATED) + { +#ifdef VBOX_WITH_EXTPACK + vrc = mptrExtPackManager->callAllVmPowerOnHooks(this, VMR3GetVM(ptrVM.rawUVM())); +#else + vrc = VINF_SUCCESS; +#endif + if (RT_SUCCESS(vrc)) + vrc = VMR3PowerOn(ptrVM.rawUVM()); /* (PowerUpPaused) */ + } + else + { + VMRESUMEREASON enmReason = VMRESUMEREASON_USER; + if (aReason == Reason_HostResume) + enmReason = VMRESUMEREASON_HOST_RESUME; + vrc = VMR3Resume(ptrVM.rawUVM(), enmReason); + } + + HRESULT rc = RT_SUCCESS(vrc) ? S_OK : + setError(VBOX_E_VM_ERROR, + tr("Could not resume the machine execution (%Rrc)"), + vrc); + + LogFlowThisFunc(("rc=%Rhrc\n", rc)); + LogFlowThisFuncLeave(); + return rc; +} + +/** + * Worker for Console::SaveState and internal entry point for saving state of + * a VM for a specific reason. + */ +HRESULT Console::saveState(Reason_T aReason, IProgress **aProgress) +{ + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aProgress); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); + if ( mMachineState != MachineState_Running + && mMachineState != MachineState_Paused) + { + return setError(VBOX_E_INVALID_VM_STATE, + tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"), + Global::stringifyMachineState(mMachineState)); + } + + if (aReason != Reason_Unspecified) + LogRel(("Saving state of VM, reason \"%s\"\n", Global::stringifyReason(aReason))); + + /* memorize the current machine state */ + MachineState_T lastMachineState = mMachineState; + + if (mMachineState == MachineState_Running) + { + /* get the VM handle. */ + SafeVMPtr ptrVM(this); + if (!ptrVM.isOk()) + return ptrVM.rc(); + + /* release the lock before a VMR3* call (EMT will call us back)! */ + alock.release(); + VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER; + if (aReason == Reason_HostSuspend) + enmReason = VMSUSPENDREASON_HOST_SUSPEND; + else if (aReason == Reason_HostBatteryLow) + enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW; + int vrc = VMR3Suspend(ptrVM.rawUVM(), enmReason); + alock.acquire(); + + HRESULT hrc = S_OK; + if (RT_FAILURE(vrc)) + hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc); + if (FAILED(hrc)) + return hrc; + } + + HRESULT rc = S_OK; + bool fBeganSavingState = false; + bool fTaskCreationFailed = false; + + do + { + ComPtr pProgress; + Bstr stateFilePath; + + /* + * request a saved state file path from the server + * (this will set the machine state to Saving on the server to block + * others from accessing this machine) + */ + rc = mControl->BeginSavingState(pProgress.asOutParam(), + stateFilePath.asOutParam()); + if (FAILED(rc)) + break; + + fBeganSavingState = true; + + /* sync the state with the server */ + setMachineStateLocally(MachineState_Saving); + + /* ensure the directory for the saved state file exists */ + { + Utf8Str dir = stateFilePath; + dir.stripFilename(); + if (!RTDirExists(dir.c_str())) + { + int vrc = RTDirCreateFullPath(dir.c_str(), 0700); + if (RT_FAILURE(vrc)) + { + rc = setError(VBOX_E_FILE_ERROR, + tr("Could not create a directory '%s' to save the state to (%Rrc)"), + dir.c_str(), vrc); + break; + } + } + } + + /* Create a task object early to ensure mpUVM protection is successful. */ + std::auto_ptr task(new VMSaveTask(this, pProgress, + stateFilePath, + lastMachineState, + aReason)); + rc = task->rc(); + /* + * If we fail here it means a PowerDown() call happened on another + * thread while we were doing Pause() (which releases the Console lock). + * We assign PowerDown() a higher precedence than SaveState(), + * therefore just return the error to the caller. + */ + if (FAILED(rc)) + { + fTaskCreationFailed = true; + break; + } + + /* create a thread to wait until the VM state is saved */ + int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *)task.get(), + 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave"); + if (RT_FAILURE(vrc)) + { + rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc); + break; + } + + /* task is now owned by saveStateThread(), so release it */ + task.release(); + + /* return the progress to the caller */ + pProgress.queryInterfaceTo(aProgress); + } while (0); + + if (FAILED(rc) && !fTaskCreationFailed) + { + /* preserve existing error info */ + ErrorInfoKeeper eik; + + if (fBeganSavingState) + { + /* + * cancel the requested save state procedure. + * This will reset the machine state to the state it had right + * before calling mControl->BeginSavingState(). + */ + mControl->EndSavingState(eik.getResultCode(), eik.getText().raw()); + } + + if (lastMachineState == MachineState_Running) + { + /* restore the paused state if appropriate */ + setMachineStateLocally(MachineState_Paused); + /* restore the running state if appropriate */ + SafeVMPtr ptrVM(this); + if (ptrVM.isOk()) + { + alock.release(); + VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED); + alock.acquire(); + } + } + else + setMachineStateLocally(lastMachineState); + } + + LogFlowThisFunc(("rc=%Rhrc\n", rc)); + LogFlowThisFuncLeave(); + return rc; +} + /** * Gets called by Session::UpdateMachineState() * (IInternalSessionControl::updateMachineState()). @@ -5933,7 +6037,8 @@ void Console::onMousePointerShapeChange(bool fVisible, bool fAlpha, * @note Locks this object for writing. */ #endif -void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, BOOL needsHostCursor) +void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, + BOOL supportsMT, BOOL needsHostCursor) { LogFlowThisFunc(("supportsAbsolute=%d supportsRelative=%d needsHostCursor=%d\n", supportsAbsolute, supportsRelative, needsHostCursor)); @@ -5954,14 +6059,13 @@ void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelati } #endif - fireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, needsHostCursor); + fireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, supportsMT, needsHostCursor); } void Console::onStateChange(MachineState_T machineState) { AutoCaller autoCaller(this); AssertComRCReturnVoid(autoCaller.rc()); - fireStateChangedEvent(mEventSource, machineState); } @@ -6098,25 +6202,27 @@ HRESULT Console::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId) //////////////////////////////////////////////////////////////////////////////// /** - * Increases the usage counter of the mpVM pointer. Guarantees that - * VMR3Destroy() will not be called on it at least until releaseVMCaller() - * is called. + * Increases the usage counter of the mpUVM pointer. + * + * Guarantees that VMR3Destroy() will not be called on it at least until + * releaseVMCaller() is called. * - * If this method returns a failure, the caller is not allowed to use mpVM - * and may return the failed result code to the upper level. This method sets - * the extended error info on failure if \a aQuiet is false. + * If this method returns a failure, the caller is not allowed to use mpUVM and + * may return the failed result code to the upper level. This method sets the + * extended error info on failure if \a aQuiet is false. * * Setting \a aQuiet to true is useful for methods that don't want to return * the failed result code to the caller when this method fails (e.g. need to - * silently check for the mpVM availability). + * silently check for the mpUVM availability). * - * When mpVM is NULL but \a aAllowNullVM is true, a corresponding error will be + * When mpUVM is NULL but \a aAllowNullVM is true, a corresponding error will be * returned instead of asserting. Having it false is intended as a sanity check - * for methods that have checked mMachineState and expect mpVM *NOT* to be NULL. + * for methods that have checked mMachineState and expect mpUVM *NOT* to be + * NULL. * * @param aQuiet true to suppress setting error info - * @param aAllowNullVM true to accept mpVM being NULL and return a failure - * (otherwise this method will assert if mpVM is NULL) + * @param aAllowNullVM true to accept mpUVM being NULL and return a failure + * (otherwise this method will assert if mpUVM is NULL) * * @note Locks this object for writing. */ @@ -6153,8 +6259,10 @@ HRESULT Console::addVMCaller(bool aQuiet /* = false */, } /** - * Decreases the usage counter of the mpVM pointer. Must always complete - * the addVMCaller() call after the mpVM pointer is no more necessary. + * Decreases the usage counter of the mpUVM pointer. + * + * Must always complete the addVMCaller() call after the mpUVM pointer is no + * more necessary. * * @note Locks this object for writing. */ @@ -6178,9 +6286,8 @@ void Console::releaseVMCaller() } -HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet) +HRESULT Console::safeVMPtrRetainer(PUVM *a_ppUVM, bool a_Quiet) { - *a_ppVM = NULL; *a_ppUVM = NULL; AutoCaller autoCaller(this); @@ -6192,13 +6299,13 @@ HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet) */ if (mVMDestroying) /* powerDown() is waiting for all callers to finish */ return a_Quiet - ? E_ACCESSDENIED - : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down")); + ? E_ACCESSDENIED + : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down")); PUVM pUVM = mpUVM; if (!pUVM) return a_Quiet - ? E_ACCESSDENIED - : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off")); + ? E_ACCESSDENIED + : setError(E_ACCESSDENIED, tr("The virtual machine is powered off")); /* * Retain a reference to the user mode VM handle and get the global handle. @@ -6207,28 +6314,17 @@ HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet) if (cRefs == UINT32_MAX) return a_Quiet ? E_ACCESSDENIED - : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off")); - - PVM pVM = VMR3GetVM(pUVM); - if (!pVM) - { - VMR3ReleaseUVM(pUVM); - return a_Quiet - ? E_ACCESSDENIED - : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off")); - } + : setError(E_ACCESSDENIED, tr("The virtual machine is powered off")); /* done */ - *a_ppVM = pVM; *a_ppUVM = pUVM; return S_OK; } -void Console::safeVMPtrReleaser(PVM *a_ppVM, PUVM *a_ppUVM) +void Console::safeVMPtrReleaser(PUVM *a_ppUVM) { - if (*a_ppVM && *a_ppUVM) + if (*a_ppUVM) VMR3ReleaseUVM(*a_ppUVM); - *a_ppVM = NULL; *a_ppUVM = NULL; } @@ -6298,7 +6394,7 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr aMachine) char szError[RTPATH_MAX + 128]; int vrc = com::VBoxLogRelCreate("VM", logFile.c_str(), RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS, - "all all.restrict default.unrestricted", + "all all.restrict -default.restrict", "VBOX_RELEASE_LOG", RTLOGDEST_FILE, 32768 /* cMaxEntriesPerGroup */, 0 /* cHistory */, 0 /* uHistoryFileTime */, @@ -6328,8 +6424,8 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr aMachine) */ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) { + LogFlowThisFuncEnter(); - LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); CheckComArgOutPointerValid(aProgress); @@ -6338,22 +6434,34 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); HRESULT rc = S_OK; ComObjPtr pPowerupProgress; bool fBeganPoweringUp = false; + LONG cOperations = 1; + LONG ulTotalOperationsWeight = 1; + try { + if (Global::IsOnlineOrTransient(mMachineState)) throw setError(VBOX_E_INVALID_VM_STATE, tr("The virtual machine is already running or busy (machine state: %s)"), Global::stringifyMachineState(mMachineState)); + /* Set up release logging as early as possible after the check if + * there is already a running VM which we shouldn't disturb. */ + rc = consoleInitReleaseLog(mMachine); + if (FAILED(rc)) + throw rc; + /* test and clear the TeleporterEnabled property */ BOOL fTeleporterEnabled; rc = mMachine->COMGETTER(TeleporterEnabled)(&fTeleporterEnabled); if (FAILED(rc)) throw rc; + #if 0 /** @todo we should save it afterwards, but that isn't necessarily a good idea. Find a better place for this (VBoxSVC). */ if (fTeleporterEnabled) { @@ -6384,101 +6492,28 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) progressDesc = tr("Fault Tolerance syncing of remote virtual machine"); else progressDesc = tr("Starting virtual machine"); - if ( mMachineState == MachineState_Saved - || (!fTeleporterEnabled && !fFaultToleranceSyncEnabled)) - rc = pPowerupProgress->init(static_cast(this), - progressDesc.raw(), - FALSE /* aCancelable */); - else - if (fTeleporterEnabled) - rc = pPowerupProgress->init(static_cast(this), - progressDesc.raw(), - TRUE /* aCancelable */, - 3 /* cOperations */, - 10 /* ulTotalOperationsWeight */, - Bstr(tr("Teleporting virtual machine")).raw(), - 1 /* ulFirstOperationWeight */, - NULL); - else - if (fFaultToleranceSyncEnabled) - rc = pPowerupProgress->init(static_cast(this), - progressDesc.raw(), - TRUE /* aCancelable */, - 3 /* cOperations */, - 10 /* ulTotalOperationsWeight */, - Bstr(tr("Fault Tolerance syncing of remote virtual machine")).raw(), - 1 /* ulFirstOperationWeight */, - NULL); - - if (FAILED(rc)) - throw rc; - /* Tell VBoxSVC and Machine about the progress object so they can - combine/proxy it to any openRemoteSession caller. */ - LogFlowThisFunc(("Calling BeginPowerUp...\n")); - rc = mControl->BeginPowerUp(pPowerupProgress); - if (FAILED(rc)) - { - LogFlowThisFunc(("BeginPowerUp failed\n")); - throw rc; - } - fBeganPoweringUp = true; + Bstr savedStateFile; - /** @todo this code prevents starting a VM with unavailable bridged - * networking interface. The only benefit is a slightly better error - * message, which should be moved to the driver code. This is the - * only reason why I left the code in for now. The driver allows - * unavailable bridged networking interfaces in certain circumstances, - * and this is sabotaged by this check. The VM will initially have no - * network connectivity, but the user can fix this at runtime. */ -#if 0 - /* the network cards will undergo a quick consistency check */ - for (ULONG slot = 0; - slot < maxNetworkAdapters; - ++slot) + /* + * Saved VMs will have to prove that their saved states seem kosher. + */ + if (mMachineState == MachineState_Saved) { - ComPtr pNetworkAdapter; - mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam()); - BOOL enabled = FALSE; - pNetworkAdapter->COMGETTER(Enabled)(&enabled); - if (!enabled) - continue; - - NetworkAttachmentType_T netattach; - pNetworkAdapter->COMGETTER(AttachmentType)(&netattach); - switch (netattach) - { - case NetworkAttachmentType_Bridged: - { - /* a valid host interface must have been set */ - Bstr hostif; - pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam()); - if (hostif.isEmpty()) - { - throw setError(VBOX_E_HOST_ERROR, - tr("VM cannot start because host interface networking requires a host interface name to be set")); - } - ComPtr pVirtualBox; - mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam()); - ComPtr pHost; - pVirtualBox->COMGETTER(Host)(pHost.asOutParam()); - ComPtr pHostInterface; - if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(), - pHostInterface.asOutParam()))) - { - throw setError(VBOX_E_HOST_ERROR, - tr("VM cannot start because the host interface '%ls' does not exist"), - hostif.raw()); - } - break; - } - default: - break; - } + rc = mMachine->COMGETTER(StateFilePath)(savedStateFile.asOutParam()); + if (FAILED(rc)) + throw rc; + ComAssertRet(!savedStateFile.isEmpty(), E_FAIL); + int vrc = SSMR3ValidateFile(Utf8Str(savedStateFile).c_str(), false /* fChecksumIt */); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("VM cannot start because the saved state file '%ls' is invalid (%Rrc). Delete the saved state prior to starting the VM"), + savedStateFile.raw(), vrc); } -#endif // 0 - /* Read console data stored in the saved state file (if not yet done) */ + /* Read console data, including console shared folders, stored in the + * saved state file (if not yet done). + */ rc = loadDataFromSavedState(); if (FAILED(rc)) throw rc; @@ -6502,55 +6537,24 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) { const SharedFolderData &d = it->second; sharedFolders[it->first] = d; - } - - /* third, insert console folders */ - for (SharedFolderMap::const_iterator it = m_mapSharedFolders.begin(); - it != m_mapSharedFolders.end(); - ++it) - { - SharedFolder *pSF = it->second; - AutoCaller sfCaller(pSF); - AutoReadLock sfLock(pSF COMMA_LOCKVAL_SRC_POS); - sharedFolders[it->first] = SharedFolderData(pSF->getHostPath(), - pSF->isWritable(), - pSF->isAutoMounted()); - } - } - - Bstr savedStateFile; - - /* - * Saved VMs will have to prove that their saved states seem kosher. - */ - if (mMachineState == MachineState_Saved) - { - rc = mMachine->COMGETTER(StateFilePath)(savedStateFile.asOutParam()); - if (FAILED(rc)) - throw rc; - ComAssertRet(!savedStateFile.isEmpty(), E_FAIL); - int vrc = SSMR3ValidateFile(Utf8Str(savedStateFile).c_str(), false /* fChecksumIt */); - if (RT_FAILURE(vrc)) - throw setError(VBOX_E_FILE_ERROR, - tr("VM cannot start because the saved state file '%ls' is invalid (%Rrc). Delete the saved state prior to starting the VM"), - savedStateFile.raw(), vrc); - } + } - LogFlowThisFunc(("Checking if canceled...\n")); - BOOL fCanceled; - rc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled); - if (FAILED(rc)) - throw rc; - if (fCanceled) - { - LogFlowThisFunc(("Canceled in BeginPowerUp\n")); - throw setError(E_FAIL, tr("Powerup was canceled")); + /* third, insert console folders */ + for (SharedFolderMap::const_iterator it = m_mapSharedFolders.begin(); + it != m_mapSharedFolders.end(); + ++it) + { + SharedFolder *pSF = it->second; + AutoCaller sfCaller(pSF); + AutoReadLock sfLock(pSF COMMA_LOCKVAL_SRC_POS); + sharedFolders[it->first] = SharedFolderData(pSF->getHostPath(), + pSF->isWritable(), + pSF->isAutoMounted()); + } } - LogFlowThisFunc(("Not canceled yet.\n")); - - /* setup task object and thread to carry out the operation - * asynchronously */ + /* Setup task object and thread to carry out the operaton + * Asycnhronously */ std::auto_ptr task(new VMPowerUpTask(this, pPowerupProgress)); ComAssertComRCRetRC(task->rc()); @@ -6628,9 +6632,9 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) else LogFlowThisFunc(("Machine has a current snapshot which is online, skipping immutable images reset\n")); - rc = consoleInitReleaseLog(mMachine); - if (FAILED(rc)) - throw rc; + /* setup task object and thread to carry out the operation + * asynchronously */ + #ifdef VBOX_WITH_EXTPACK mptrExtPackManager->dumpAllToReleaseLog(); #endif @@ -6649,15 +6653,11 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) uint32_t fCoreFlags = 0; if ( coreDumpReplaceSys.isEmpty() == false && Utf8Str(coreDumpReplaceSys).toUInt32() == 1) - { fCoreFlags |= RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP; - } if ( coreDumpLive.isEmpty() == false && Utf8Str(coreDumpLive).toUInt32() == 1) - { fCoreFlags |= RTCOREDUMPER_FLAGS_LIVE_CORE; - } Utf8Str strDumpDir(coreDumpDir); const char *pszDumpDir = strDumpDir.c_str(); @@ -6685,29 +6685,143 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) } #endif - /* pass the progress object to the caller if requested */ - if (aProgress) - { - if (task->hardDiskProgresses.size() == 0) + + // If there is immutable drive the process that. + VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses); + if (aProgress && progresses.size() > 0){ + + for (VMPowerUpTask::ProgressList::const_iterator it = progresses.begin(); it != progresses.end(); ++it) { - /* there are no other operations to track, return the powerup - * progress only */ - pPowerupProgress.queryInterfaceTo(aProgress); + ++cOperations; + ulTotalOperationsWeight += 1; } - else + rc = pPowerupProgress->init(static_cast(this), + progressDesc.raw(), + TRUE, // Cancelable + cOperations, + ulTotalOperationsWeight, + Bstr(tr("Starting Hard Disk operations")).raw(), + 1, + NULL); + AssertComRCReturnRC(rc); + } + else if ( mMachineState == MachineState_Saved + || (!fTeleporterEnabled && !fFaultToleranceSyncEnabled)) + { + rc = pPowerupProgress->init(static_cast(this), + progressDesc.raw(), + FALSE /* aCancelable */); + } + else if (fTeleporterEnabled) + { + rc = pPowerupProgress->init(static_cast(this), + progressDesc.raw(), + TRUE /* aCancelable */, + 3 /* cOperations */, + 10 /* ulTotalOperationsWeight */, + Bstr(tr("Teleporting virtual machine")).raw(), + 1 /* ulFirstOperationWeight */, + NULL); + } + else if (fFaultToleranceSyncEnabled) + { + rc = pPowerupProgress->init(static_cast(this), + progressDesc.raw(), + TRUE /* aCancelable */, + 3 /* cOperations */, + 10 /* ulTotalOperationsWeight */, + Bstr(tr("Fault Tolerance syncing of remote virtual machine")).raw(), + 1 /* ulFirstOperationWeight */, + NULL); + } + + if (FAILED(rc)) + throw rc; + + /* Tell VBoxSVC and Machine about the progress object so they can + combine/proxy it to any openRemoteSession caller. */ + LogFlowThisFunc(("Calling BeginPowerUp...\n")); + rc = mControl->BeginPowerUp(pPowerupProgress); + if (FAILED(rc)) + { + LogFlowThisFunc(("BeginPowerUp failed\n")); + throw rc; + } + fBeganPoweringUp = true; + + LogFlowThisFunc(("Checking if canceled...\n")); + BOOL fCanceled; + rc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled); + if (FAILED(rc)) + throw rc; + + if (fCanceled) + { + LogFlowThisFunc(("Canceled in BeginPowerUp\n")); + throw setError(E_FAIL, tr("Powerup was canceled")); + } + LogFlowThisFunc(("Not canceled yet.\n")); + + /** @todo this code prevents starting a VM with unavailable bridged + * networking interface. The only benefit is a slightly better error + * message, which should be moved to the driver code. This is the + * only reason why I left the code in for now. The driver allows + * unavailable bridged networking interfaces in certain circumstances, + * and this is sabotaged by this check. The VM will initially have no + * network connectivity, but the user can fix this at runtime. */ +#if 0 + /* the network cards will undergo a quick consistency check */ + for (ULONG slot = 0; + slot < maxNetworkAdapters; + ++slot) + { + ComPtr pNetworkAdapter; + mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam()); + BOOL enabled = FALSE; + pNetworkAdapter->COMGETTER(Enabled)(&enabled); + if (!enabled) + continue; + + NetworkAttachmentType_T netattach; + pNetworkAdapter->COMGETTER(AttachmentType)(&netattach); + switch (netattach) { - /* create a combined progress object */ - ComObjPtr pProgress; - pProgress.createObject(); - VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses); - progresses.push_back(ComPtr (pPowerupProgress)); - rc = pProgress->init(static_cast(this), - progressDesc.raw(), progresses.begin(), - progresses.end()); - AssertComRCReturnRC(rc); - pProgress.queryInterfaceTo(aProgress); + case NetworkAttachmentType_Bridged: + { + /* a valid host interface must have been set */ + Bstr hostif; + pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam()); + if (hostif.isEmpty()) + { + throw setError(VBOX_E_HOST_ERROR, + tr("VM cannot start because host interface networking requires a host interface name to be set")); + } + ComPtr pVirtualBox; + mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam()); + ComPtr pHost; + pVirtualBox->COMGETTER(Host)(pHost.asOutParam()); + ComPtr pHostInterface; + if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(), + pHostInterface.asOutParam()))) + { + throw setError(VBOX_E_HOST_ERROR, + tr("VM cannot start because the host interface '%ls' does not exist"), + hostif.raw()); + } + break; + } + default: + break; } } +#endif // 0 + + /* setup task object and thread to carry out the operation + * asynchronously */ + if (aProgress){ + rc = pPowerupProgress.queryInterfaceTo(aProgress); + AssertComRCReturnRC(rc); + } int vrc = RTThreadCreate(NULL, Console::powerUpThread, (void *)task.get(), 0, @@ -6724,7 +6838,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) if (mMachineState == MachineState_Saved) setMachineState(MachineState_Restoring); else if (fTeleporterEnabled) - setMachineState(MachineState_TeleportingIn); + setMachineState(MachineState_TeleportingIn); else if (enmFaultToleranceState == FaultToleranceState_Standby) setMachineState(MachineState_FaultTolerantSyncing); else @@ -6771,7 +6885,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) * * Calling it in situations other than the above will cause unexpected behavior. * - * Note that this method should be the only one that destroys mpVM and sets it + * Note that this method should be the only one that destroys mpUVM and sets it * to NULL. * * @param aProgress Progress object to run (may be NULL). @@ -6878,8 +6992,8 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) /* ---------------------------------------------------------------------- - * Now, wait for all mpVM callers to finish their work if there are still - * some on other threads. NO methods that need mpVM (or initiate other calls + * Now, wait for all mpUVM callers to finish their work if there are still + * some on other threads. NO methods that need mpUVM (or initiate other calls * that need it) may be called after this point * ---------------------------------------------------------------------- */ @@ -6892,8 +7006,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) if (mVMZeroCallersSem == NIL_RTSEMEVENT) RTSemEventCreate(&mVMZeroCallersSem); - LogFlowThisFunc(("Waiting for mpVM callers (%d) to drop to zero...\n", - mVMCallers)); + LogFlowThisFunc(("Waiting for mpUVM callers (%d) to drop to zero...\n", mVMCallers)); alock.release(); @@ -6920,7 +7033,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) { LogFlowThisFunc(("Powering off the VM...\n")); alock.release(); - vrc = VMR3PowerOff(VMR3GetVM(pUVM)); + vrc = VMR3PowerOff(pUVM); #ifdef VBOX_WITH_EXTPACK mptrExtPackManager->callAllVmPowerOffHooks(this, VMR3GetVM(pUVM)); #endif @@ -6957,26 +7070,20 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) * on failure (this will most likely fail too, but what to do?..) */ if (RT_SUCCESS(vrc) || autoCaller.state() == InUninit) { - /* If the machine has an USB controller, release all USB devices + /* If the machine has a USB controller, release all USB devices * (symmetric to the code in captureUSBDevices()) */ - bool fHasUSBController = false; + if (mfVMHasUsbController) { - PPDMIBASE pBase; - vrc = PDMR3QueryLun(VMR3GetVM(pUVM), "usb-ohci", 0, 0, &pBase); - if (RT_SUCCESS(vrc)) - { - fHasUSBController = true; - alock.release(); - detachAllUSBDevices(false /* aDone */); - alock.acquire(); - } + alock.release(); + detachAllUSBDevices(false /* aDone */); + alock.acquire(); } - /* Now we've got to destroy the VM as well. (mpVM is not valid beyond + /* Now we've got to destroy the VM as well. (mpUVM is not valid beyond * this point). We release the lock before calling VMR3Destroy() because * it will result into calling destructors of drivers associated with * Console children which may in turn try to lock Console (e.g. by - * instantiating SafeVMPtr to access mpVM). It's safe here because + * instantiating SafeVMPtr to access mpUVM). It's safe here because * mVMDestroying is set which should prevent any activity. */ /* Set mpUVM to NULL early just in case if some old code is not using @@ -6988,7 +7095,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) alock.release(); - vrc = VMR3Destroy(VMR3GetVM(pUVM)); + vrc = VMR3Destroy(pUVM); /* take the lock again */ alock.acquire(); @@ -7000,7 +7107,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Machine has been destroyed (mMachineState=%d)\n", - mMachineState)); + mMachineState)); /* Note: the Console-level machine state change happens on the * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If * powerDown() is called from EMT (i.e. from vmstateChangeCallback() @@ -7020,7 +7127,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) } /* Complete the detaching of the USB devices. */ - if (fHasUSBController) + if (mfVMHasUsbController) { alock.release(); detachAllUSBDevices(true /* aDone */); @@ -7046,7 +7153,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/) * something like Stopping, so most Console methods will return an error * to the caller. */ - if (mpUVM != NULL) + if (pUVM != NULL) VMR3ReleaseUVM(pUVM); else mVMDestroying = false; @@ -7281,8 +7388,9 @@ HRESULT Console::fetchSharedFolders(BOOL aGlobal) } catch (HRESULT rc2) { + rc = rc2; if (online) - setVMRuntimeErrorCallbackF(ptrVM, this, 0, "BrokenSharedFolder", + setVMRuntimeErrorCallbackF(0, "BrokenSharedFolder", N_("Broken shared folder!")); } @@ -7326,7 +7434,7 @@ bool Console::findOtherSharedFolder(const Utf8Str &strName, * @param aName Shared folder name. * @param aHostPath Shared folder path. * - * @note Must be called from under AutoVMCaller and when mpVM != NULL! + * @note Must be called from under AutoVMCaller and when mpUVM != NULL! * @note Doesn't lock anything. */ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData) @@ -7356,14 +7464,15 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa aData.m_strHostPath.c_str(), hostPathFull, sizeof(hostPathFull)); + + bool fMissing = false; if (RT_FAILURE(vrc)) return setError(E_INVALIDARG, tr("Invalid shared folder path: '%s' (%Rrc)"), aData.m_strHostPath.c_str(), vrc); if (!RTPathExists(hostPathFull)) - return setError(E_INVALIDARG, - tr("Shared folder path '%s' does not exist on the host"), - aData.m_strHostPath.c_str()); + fMissing = true; + /* Check whether the path is full (absolute) */ if (RTPathCompare(aData.m_strHostPath.c_str(), hostPathFull) != 0) return setError(E_INVALIDARG, @@ -7409,7 +7518,9 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa parms[2].type = VBOX_HGCM_SVC_PARM_32BIT; parms[2].u.uint32 = (aData.m_fWritable ? SHFL_ADD_MAPPING_F_WRITABLE : 0) | (aData.m_fAutoMount ? SHFL_ADD_MAPPING_F_AUTOMOUNT : 0) - | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0); + | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0) + | (fMissing ? SHFL_ADD_MAPPING_F_MISSING : 0) + ; vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_ADD_MAPPING, @@ -7422,6 +7533,11 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa tr("Could not create a shared folder '%s' mapped to '%s' (%Rrc)"), strName.c_str(), aData.m_strHostPath.c_str(), vrc); + if (fMissing) + return setError(E_INVALIDARG, + tr("Shared folder path '%s' does not exist on the host"), + aData.m_strHostPath.c_str()); + return S_OK; } @@ -7430,7 +7546,7 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa * * @param aName Shared folder name. * - * @note Must be called from under AutoVMCaller and when mpVM != NULL! + * @note Must be called from under AutoVMCaller and when mpUVM != NULL! * @note Doesn't lock anything. */ HRESULT Console::removeSharedFolder(const Utf8Str &strName) @@ -7474,31 +7590,18 @@ HRESULT Console::removeSharedFolder(const Utf8Str &strName) return S_OK; } -/** - * VM state callback function. Called by the VMM - * using its state machine states. +/** @callback_method_impl{FNVMATSTATE} * - * Primarily used to handle VM initiated power off, suspend and state saving, - * but also for doing termination completed work (VMSTATE_TERMINATE). - * - * In general this function is called in the context of the EMT. - * - * @param aVM The VM handle. - * @param aState The new state. - * @param aOldState The old state. - * @param aUser The user argument (pointer to the Console object). - * - * @note Locks the Console object for writing. + * @note Locks the Console object for writing. + * @remarks The @a pUVM parameter can be NULL in one case where powerUpThread() + * calls after the VM was destroyed. */ -DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, - VMSTATE aState, - VMSTATE aOldState, - void *aUser) +DECLCALLBACK(void) Console::vmstateChangeCallback(PUVM pUVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser) { - LogFlowFunc(("Changing state from %s to %s (aVM=%p)\n", - VMR3GetStateName(aOldState), VMR3GetStateName(aState), aVM)); + LogFlowFunc(("Changing state from %s to %s (pUVM=%p)\n", + VMR3GetStateName(enmOldState), VMR3GetStateName(enmState), pUVM)); - Console *that = static_cast(aUser); + Console *that = static_cast(pvUser); AssertReturnVoid(that); AutoCaller autoCaller(that); @@ -7510,17 +7613,34 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, AssertReturnVoid( autoCaller.isOk() || autoCaller.state() == InUninit); - switch (aState) + switch (enmState) { /* * The VM has terminated */ case VMSTATE_OFF: { +#ifdef VBOX_WITH_GUEST_PROPS + if (that->isResetTurnedIntoPowerOff()) + { + Bstr strPowerOffReason; + + if (that->mfPowerOffCausedByReset) + strPowerOffReason = Bstr("Reset"); + else + strPowerOffReason = Bstr("PowerOff"); + + that->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw()); + that->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(), + strPowerOffReason.raw(), Bstr("RDONLYGUEST").raw()); + that->mMachine->SaveSettings(); + } +#endif + AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS); if (that->mVMStateChangeCallbackDisabled) - break; + return; /* Do we still think that it is running? It may happen if this is a * VM-(guest-)initiated shutdown/poweroff. @@ -7536,7 +7656,11 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, { LogFlowFunc(("VM has powered itself off but Console still thinks it is running. Notifying.\n")); - /* prevent powerDown() from calling VMR3PowerOff() again */ + /* + * Prevent powerDown() from calling VMR3PowerOff() again if this was called from + * the power off state change. + * When called from the Reset state make sure to call VMR3PowerOff() first. + */ Assert(that->mVMPoweredOff == false); that->mVMPoweredOff = true; @@ -7554,11 +7678,10 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, /* Setup task object and thread to carry out the operation * asynchronously (if we call powerDown() right here but there - * is one or more mpVM callers (added with addVMCaller()) we'll + * is one or more mpUVM callers (added with addVMCaller()) we'll * deadlock). */ - std::auto_ptr task(new VMPowerDownTask(that, - pProgress)); + std::auto_ptr task(new VMPowerDownTask(that, pProgress)); /* If creating a task failed, this can currently mean one of * two: either Console::uninit() has been called just a ms @@ -7569,14 +7692,14 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, if (!task->isOk()) { LogFlowFunc(("Console is already being uninitialized.\n")); - break; + return; } int vrc = RTThreadCreate(NULL, Console::powerDownThread, - (void *) task.get(), 0, + (void *)task.get(), 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMPwrDwn"); - AssertMsgRCBreak(vrc, ("Could not create VMPowerDown thread (%Rrc)\n", vrc)); + AssertMsgRCReturnVoid(vrc, ("Could not create VMPowerDown thread (%Rrc)\n", vrc)); /* task is now owned by powerDownThread(), so release it */ task.release(); @@ -7598,12 +7721,12 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, if (that->mVMStateChangeCallbackDisabled) break; - /* Terminate host interface networking. If aVM is NULL, we've been + /* Terminate host interface networking. If pUVM is NULL, we've been * manually called from powerUpThread() either before calling * VMR3Create() or after VMR3Create() failed, so no need to touch * networking. */ - if (aVM) + if (pUVM) that->powerDownHostInterfaces(); /* From now on the machine is officially powered down or remains in @@ -7718,7 +7841,7 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, break; default: - AssertMsgFailed(("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) )); + AssertMsgFailed(("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) )); that->setMachineState(MachineState_Paused); break; } @@ -7727,9 +7850,9 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, case VMSTATE_RUNNING: { - if ( aOldState == VMSTATE_POWERING_ON - || aOldState == VMSTATE_RESUMING - || aOldState == VMSTATE_RUNNING_FT) + if ( enmOldState == VMSTATE_POWERING_ON + || enmOldState == VMSTATE_RESUMING + || enmOldState == VMSTATE_RUNNING_FT) { AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS); @@ -7738,15 +7861,15 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, Assert( ( ( that->mMachineState == MachineState_Starting || that->mMachineState == MachineState_Paused) - && aOldState == VMSTATE_POWERING_ON) + && enmOldState == VMSTATE_POWERING_ON) || ( ( that->mMachineState == MachineState_Restoring || that->mMachineState == MachineState_TeleportingIn || that->mMachineState == MachineState_Paused || that->mMachineState == MachineState_Saving ) - && aOldState == VMSTATE_RESUMING) + && enmOldState == VMSTATE_RESUMING) || ( that->mMachineState == MachineState_FaultTolerantSyncing - && aOldState == VMSTATE_RUNNING_FT)); + && enmOldState == VMSTATE_RUNNING_FT)); that->setMachineState(MachineState_Running); } @@ -7757,12 +7880,12 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM, case VMSTATE_RUNNING_LS: AssertMsg( that->mMachineState == MachineState_LiveSnapshotting || that->mMachineState == MachineState_Teleporting, - ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) )); + ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) )); break; case VMSTATE_RUNNING_FT: AssertMsg(that->mMachineState == MachineState_FaultTolerantSyncing, - ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) )); + ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) )); break; case VMSTATE_FATAL_ERROR: @@ -7859,15 +7982,15 @@ void Console::changeDragAndDropMode(DragAndDropMode_T aDragAndDropMode) LogRel(("Drag'n'drop mode: Off\n")); parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_OFF; break; - case ClipboardMode_GuestToHost: + case DragAndDropMode_GuestToHost: LogRel(("Drag'n'drop mode: Guest to Host\n")); parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST; break; - case ClipboardMode_HostToGuest: + case DragAndDropMode_HostToGuest: LogRel(("Drag'n'drop mode: Host to Guest\n")); parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST; break; - case ClipboardMode_Bidirectional: + case DragAndDropMode_Bidirectional: LogRel(("Drag'n'drop mode: Bidirectional\n")); parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL; break; @@ -7934,10 +8057,10 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs) AssertComRCReturnRC(hrc); Assert(portVersion == 1 || portVersion == 2); - int vrc = VMR3ReqCallWait(ptrVM, 0 /* idDstCpu (saved state, see #6232) */, - (PFNRT)usbAttachCallback, 9, - this, ptrVM.raw(), aHostDevice, uuid.raw(), fRemote, Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs); - + int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */, + (PFNRT)usbAttachCallback, 9, + this, ptrVM.rawUVM(), aHostDevice, uuid.raw(), fRemote, + Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs); if (RT_SUCCESS(vrc)) { /* Create a OUSBDevice and add it to the device list */ @@ -7962,17 +8085,13 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs) switch (vrc) { case VERR_VUSB_NO_PORTS: - hrc = setError(E_FAIL, - tr("Failed to attach the USB device. (No available ports on the USB controller).")); + hrc = setError(E_FAIL, tr("Failed to attach the USB device. (No available ports on the USB controller).")); break; case VERR_VUSB_USBFS_PERMISSION: - hrc = setError(E_FAIL, - tr("Not permitted to open the USB device, check usbfs options")); + hrc = setError(E_FAIL, tr("Not permitted to open the USB device, check usbfs options")); break; default: - hrc = setError(E_FAIL, - tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"), - vrc); + hrc = setError(E_FAIL, tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"), vrc); break; } } @@ -7991,7 +8110,8 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs) */ //static DECLCALLBACK(int) -Console::usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs) +Console::usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, + const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs) { LogFlowFuncEnter(); LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid)); @@ -7999,7 +8119,7 @@ Console::usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRT AssertReturn(that && aUuid, VERR_INVALID_PARAMETER); AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); - int vrc = PDMR3USBCreateProxyDevice(pVM, aUuid, aRemote, aAddress, pvRemoteBackend, + int vrc = PDMR3UsbCreateProxyDevice(pUVM, aUuid, aRemote, aAddress, pvRemoteBackend, aPortVersion == 1 ? VUSB_STDVER_11 : VUSB_STDVER_20, aMaskedIfs); LogFlowFunc(("vrc=%Rrc\n", vrc)); LogFlowFuncLeave(); @@ -8025,7 +8145,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr &aHostDevice) return ptrVM.rc(); /* if the device is attached, then there must at least one USB hub. */ - AssertReturn(PDMR3USBHasHub(ptrVM), E_FAIL); + AssertReturn(PDMR3UsbHasHub(ptrVM.rawUVM()), E_FAIL); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("Detaching USB proxy device {%RTuuid}...\n", @@ -8049,9 +8169,9 @@ HRESULT Console::detachUSBDevice(const ComObjPtr &aHostDevice) } alock.release(); - int vrc = VMR3ReqCallWait(ptrVM, 0 /* idDstCpu (saved state, see #6232) */, - (PFNRT)usbDetachCallback, 5, - this, ptrVM.raw(), pUuid); + int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */, + (PFNRT)usbDetachCallback, 5, + this, ptrVM.rawUVM(), pUuid); if (RT_SUCCESS(vrc)) { LogFlowFunc(("Detached device {%RTuuid}\n", pUuid)); @@ -8067,6 +8187,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr &aHostDevice) /** * USB device detach callback used by DetachUSBDevice(). + * * Note that DetachUSBDevice() doesn't return until this callback is executed, * so we don't use AutoCaller and don't care about reference counters of * interface pointers passed in. @@ -8075,7 +8196,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr &aHostDevice) */ //static DECLCALLBACK(int) -Console::usbDetachCallback(Console *that, PVM pVM, PCRTUUID aUuid) +Console::usbDetachCallback(Console *that, PUVM pUVM, PCRTUUID aUuid) { LogFlowFuncEnter(); LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid)); @@ -8083,7 +8204,7 @@ Console::usbDetachCallback(Console *that, PVM pVM, PCRTUUID aUuid) AssertReturn(that && aUuid, VERR_INVALID_PARAMETER); AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); - int vrc = PDMR3USBDetachDevice(pVM, aUuid); + int vrc = PDMR3UsbDetachDevice(pUVM, aUuid); LogFlowFunc(("vrc=%Rrc\n", vrc)); LogFlowFuncLeave(); @@ -8134,7 +8255,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter) * Set/obtain the tap interface. */ struct ifreq IfReq; - memset(&IfReq, 0, sizeof(IfReq)); + RT_ZERO(IfReq); /* The name of the TAP interface we are using */ Bstr tapDeviceName; rc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam()); @@ -8150,10 +8271,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter) { /* If we are using a static TAP device then try to open it. */ Utf8Str str(tapDeviceName); - if (str.length() <= sizeof(IfReq.ifr_name)) - strcpy(IfReq.ifr_name, str.c_str()); - else - memcpy(IfReq.ifr_name, str.c_str(), sizeof(IfReq.ifr_name) - 1); /** @todo bitch about names which are too long... */ + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), str.c_str()); /** @todo bitch about names which are too long... */ IfReq.ifr_flags = IFF_TAP | IFF_NO_PI; rcVBox = ioctl(maTapFD[slot], TUNSETIFF, &IfReq); if (rcVBox != 0) @@ -8387,13 +8505,13 @@ HRESULT Console::powerDownHostInterfaces() * Process callback handler for VMR3LoadFromFile, VMR3LoadFromStream, VMR3Save * and VMR3Teleport. * - * @param pVM The VM handle. + * @param pUVM The user mode VM handle. * @param uPercent Completion percentage (0-100). * @param pvUser Pointer to an IProgress instance. * @return VINF_SUCCESS. */ /*static*/ -DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, void *pvUser) +DECLCALLBACK(int) Console::stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser) { IProgress *pProgress = static_cast(pvUser); @@ -8401,6 +8519,7 @@ DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, voi if (pProgress) pProgress->SetCurrentOperationProgress(uPercent); + NOREF(pUVM); return VINF_SUCCESS; } @@ -8411,7 +8530,7 @@ DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, voi * object here... */ /*static*/ DECLCALLBACK(void) -Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, +Console::genericVMSetErrorCallback(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszErrorFmt, va_list va) { Utf8Str *pErrorText = (Utf8Str *)pvUser; @@ -8429,14 +8548,17 @@ Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DEC *pErrorText = Utf8StrFmt("%N (%Rrc)", pszErrorFmt, &va2, rc, rc); va_end(va2); + + NOREF(pUVM); } /** * VM runtime error callback function. * See VMSetRuntimeError for the detailed description of parameters. * - * @param pVM The VM handle. - * @param pvUser The user argument. + * @param pUVM The user mode VM handle. Ignored, so passing NULL + * is fine. + * @param pvUser The user argument, pointer to the Console instance. * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. * @param pszErrorId Error ID string. * @param pszFormat Error message format string. @@ -8444,7 +8566,7 @@ Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DEC * @thread EMT. */ /* static */ DECLCALLBACK(void) -Console::setVMRuntimeErrorCallback(PVM pVM, void *pvUser, uint32_t fFlags, +Console::setVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va) { @@ -8457,21 +8579,20 @@ Console::setVMRuntimeErrorCallback(PVM pVM, void *pvUser, uint32_t fFlags, Utf8Str message(pszFormat, va); LogRel(("Console: VM runtime error: fatal=%RTbool, errorID=%s message=\"%s\"\n", - fFatal, pszErrorId, message.c_str())); + fFatal, pszErrorId, message.c_str())); - that->onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(), - Bstr(message).raw()); + that->onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(), Bstr(message).raw()); - LogFlowFuncLeave(); + LogFlowFuncLeave(); NOREF(pUVM); } /** * Captures USB devices that match filters of the VM. * Called at VM startup. * - * @param pVM The VM handle. + * @param pUVM The VM handle. */ -HRESULT Console::captureUSBDevices(PVM pVM) +HRESULT Console::captureUSBDevices(PUVM pUVM) { LogFlowThisFunc(("\n")); @@ -8479,11 +8600,9 @@ HRESULT Console::captureUSBDevices(PVM pVM) AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* If the machine has an USB controller, ask the USB proxy service to + /* If the machine has a USB controller, ask the USB proxy service to * capture devices */ - PPDMIBASE pBase; - int vrc = PDMR3QueryLun(pVM, "usb-ohci", 0, 0, &pBase); - if (RT_SUCCESS(vrc)) + if (mfVMHasUsbController) { /* release the lock before calling Host in VBoxSVC since Host may call * us back from under its lock (e.g. onUSBDeviceAttach()) which would @@ -8493,13 +8612,8 @@ HRESULT Console::captureUSBDevices(PVM pVM) HRESULT hrc = mControl->AutoCaptureUSBDevices(); ComAssertComRCRetRC(hrc); } - else if ( vrc == VERR_PDM_DEVICE_NOT_FOUND - || vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND) - vrc = VINF_SUCCESS; - else - AssertRC(vrc); - return RT_SUCCESS(vrc) ? S_OK : E_FAIL; + return S_OK; } @@ -8702,10 +8816,10 @@ void Console::processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *p */ static void faultToleranceProgressCancelCallback(void *pvUser) { - PVM pVM = (PVM)pvUser; + PUVM pUVM = (PUVM)pvUser; - if (pVM) - FTMR3CancelStandby(pVM); + if (pUVM) + FTMR3CancelStandby(pUVM); } /** @@ -8771,6 +8885,9 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) { HRESULT rc2 = (*it)->WaitForCompletion(-1); AssertComRC(rc2); + + rc = task->mProgress->SetNextOperation(BstrFmt(tr("Disk Image Reset Operation - Immutable Image")).raw(), 1); + AssertComRCReturnRC(rc); } /* @@ -8844,21 +8961,20 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /* * Create the VM - */ - PVM pVM; - /* - * release the lock since EMT will call Console. It's safe because - * mMachineState is either Starting or Restoring state here. + * + * Note! Release the lock since EMT will call Console. It's safe because + * mMachineState is either Starting or Restoring state here. */ alock.release(); + PVM pVM; vrc = VMR3Create(cCpus, pConsole->mpVmm2UserMethods, Console::genericVMSetErrorCallback, &task->mErrorMsg, task->mConfigConstructor, static_cast(pConsole), - &pVM); + &pVM, NULL); alock.acquire(); @@ -8872,14 +8988,14 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /* * Register our load/save state file handlers */ - vrc = SSMR3RegisterExternal(pVM, sSSMConsoleUnit, 0 /*iInstance*/, sSSMConsoleVer, 0 /* cbGuess */, + vrc = SSMR3RegisterExternal(pConsole->mpUVM, sSSMConsoleUnit, 0 /*iInstance*/, sSSMConsoleVer, 0 /* cbGuess */, NULL, NULL, NULL, NULL, saveStateFileExec, NULL, NULL, loadStateFileExec, NULL, static_cast(pConsole)); AssertRCBreak(vrc); - vrc = static_cast(pConsole)->getDisplay()->registerSSM(pVM); + vrc = static_cast(pConsole)->getDisplay()->registerSSM(pConsole->mpUVM); AssertRC(vrc); if (RT_FAILURE(vrc)) break; @@ -8909,10 +9025,11 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) if (FAILED(rc)) { ErrorInfoKeeper eik; - setVMRuntimeErrorCallbackF(pVM, pConsole, 0, "BrokenSharedFolder", - N_("The shared folder '%s' could not be set up: %ls.\n" - "The shared folder setup will not be complete. It is recommended to power down the virtual machine and fix the shared folder settings while the machine is not running"), - it->first.c_str(), eik.getText().raw()); + pConsole->setVMRuntimeErrorCallbackF(0, "BrokenSharedFolder", + N_("The shared folder '%s' could not be set up: %ls.\n" + "The shared folder setup will not be complete. It is recommended to power down the virtual " + "machine and fix the shared folder settings while the machine is not running"), + it->first.c_str(), eik.getText().raw()); } } if (FAILED(rc)) @@ -8928,8 +9045,9 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /* * Capture USB devices. */ - rc = pConsole->captureUSBDevices(pVM); - if (FAILED(rc)) break; + rc = pConsole->captureUSBDevices(pConsole->mpUVM); + if (FAILED(rc)) + break; /* Load saved state? */ if (task->mSavedStateFile.length()) @@ -8937,7 +9055,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) LogFlowFunc(("Restoring saved state from '%s'...\n", task->mSavedStateFile.c_str())); - vrc = VMR3LoadFromFile(pVM, + vrc = VMR3LoadFromFile(pConsole->mpUVM, task->mSavedStateFile.c_str(), Console::stateProgressCallback, static_cast(task->mProgress)); @@ -8954,7 +9072,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM); #endif if (RT_SUCCESS(vrc)) - vrc = VMR3Resume(pVM); + vrc = VMR3Resume(pConsole->mpUVM, VMRESUMEREASON_STATE_RESTORED); AssertLogRelRC(vrc); } } @@ -8962,7 +9080,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /* Power off in case we failed loading or resuming the VM */ if (RT_FAILURE(vrc)) { - int vrc2 = VMR3PowerOff(pVM); AssertLogRelRC(vrc2); + int vrc2 = VMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2); #ifdef VBOX_WITH_EXTPACK pConsole->mptrExtPackManager->callAllVmPowerOffHooks(pConsole, pVM); #endif @@ -8972,12 +9090,12 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) { /* -> ConsoleImplTeleporter.cpp */ bool fPowerOffOnFailure; - rc = pConsole->teleporterTrg(VMR3GetUVM(pVM), pMachine, &task->mErrorMsg, task->mStartPaused, + rc = pConsole->teleporterTrg(pConsole->mpUVM, pMachine, &task->mErrorMsg, task->mStartPaused, task->mProgress, &fPowerOffOnFailure); if (FAILED(rc) && fPowerOffOnFailure) { ErrorInfoKeeper eik; - int vrc2 = VMR3PowerOff(pVM); AssertLogRelRC(vrc2); + int vrc2 = VMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2); #ifdef VBOX_WITH_EXTPACK pConsole->mptrExtPackManager->callAllVmPowerOffHooks(pConsole, pVM); #endif @@ -9001,7 +9119,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) if (SUCCEEDED(rc)) rc = pMachine->COMGETTER(FaultTolerancePassword)(bstrPassword.asOutParam()); } - if (task->mProgress->setCancelCallback(faultToleranceProgressCancelCallback, pVM)) + if (task->mProgress->setCancelCallback(faultToleranceProgressCancelCallback, pConsole->mpUVM)) { if (SUCCEEDED(rc)) { @@ -9015,7 +9133,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM); #endif if (RT_SUCCESS(vrc)) - vrc = FTMR3PowerOn(pVM, + vrc = FTMR3PowerOn(pConsole->mpUVM, task->mEnmFaultToleranceState == FaultToleranceState_Master /* fMaster */, uInterval, pszAddress, @@ -9038,7 +9156,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM); #endif if (RT_SUCCESS(vrc)) - vrc = VMR3PowerOn(pVM); + vrc = VMR3PowerOn(pConsole->mpUVM); AssertLogRelRC(vrc); } @@ -9068,7 +9186,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) * be sticky but our error callback isn't. */ alock.release(); - VMR3AtErrorDeregister(pVM, Console::genericVMSetErrorCallback, &task->mErrorMsg); + VMR3AtErrorDeregister(pConsole->mpUVM, Console::genericVMSetErrorCallback, &task->mErrorMsg); /** @todo register another VMSetError callback? */ alock.acquire(); } @@ -9127,8 +9245,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) ErrorInfoKeeper eik; Assert(pConsole->mpUVM == NULL); - vmstateChangeCallback(NULL, VMSTATE_TERMINATED, VMSTATE_CREATING, - pConsole); + vmstateChangeCallback(NULL, VMSTATE_TERMINATED, VMSTATE_CREATING, pConsole); } /* @@ -9168,8 +9285,8 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /** * Reconfigures a medium attachment (part of taking or deleting an online snapshot). * - * @param pConsole Reference to the console object. - * @param pVM The VM handle. + * @param pThis Reference to the console object. + * @param pUVM The VM handle. * @param lInstance The instance of the controller. * @param pcszDevice The name of the controller type. * @param enmBus The storage bus type of the controller. @@ -9182,8 +9299,8 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) * @return VBox status code. */ /* static */ -DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, - PVM pVM, +DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pThis, + PUVM pUVM, const char *pcszDevice, unsigned uInstance, StorageBus_T enmBus, @@ -9196,13 +9313,11 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, MachineState_T aMachineState, HRESULT *phrc) { - LogFlowFunc(("pVM=%p aMediumAtt=%p phrc=%p\n", pVM, aMediumAtt, phrc)); + LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, aMediumAtt, phrc)); - int rc; HRESULT hrc; Bstr bstr; *phrc = S_OK; -#define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertMsgFailed(("rc=%Rrc\n", rc)); return rc; } } while (0) #define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0) /* Ignore attachments other than hard disks, since at the moment they are @@ -9214,33 +9329,37 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; - pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance); + pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); /* Update the device instance configuration. */ - rc = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - fSetupMerge, - uMergeSource, - uMergeTarget, - aMediumAtt, - aMachineState, - phrc, - true /* fAttachDetach */, - false /* fForceUnmount */, - false /* fHotplug */, - pVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - RC_CHECK(); + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + fBuiltinIOCache, + fSetupMerge, + uMergeSource, + uMergeTarget, + aMediumAtt, + aMachineState, + phrc, + true /* fAttachDetach */, + false /* fForceUnmount */, + false /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + if (RT_FAILURE(rc)) + { + AssertMsgFailed(("rc=%Rrc\n", rc)); + return rc; + } -#undef RC_CHECK #undef H LogFlowFunc(("Returns success\n")); @@ -9253,7 +9372,7 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, static void takesnapshotProgressCancelCallback(void *pvUser) { PUVM pUVM = (PUVM)pvUser; - SSMR3Cancel(VMR3GetVM(pUVM)); + SSMR3Cancel(pUVM); } /** @@ -9308,13 +9427,13 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) fBeganTakingSnapshot = true; - /* - * state file is non-null only when the VM is paused - * (i.e. creating a snapshot online) - */ - bool f = (!pTask->bstrSavedStateFile.isEmpty() && pTask->fTakingSnapshotOnline) - || ( pTask->bstrSavedStateFile.isEmpty() && !pTask->fTakingSnapshotOnline); - if (!f) + /* Check sanity: for offline snapshots there must not be a saved state + * file name. All other combinations are valid (even though online + * snapshots without saved state file seems inconsistent - there are + * some exotic use cases, which need to be explicitly enabled, see the + * code of SessionMachine::BeginTakingSnapshot. */ + if ( !pTask->fTakingSnapshotOnline + && !pTask->bstrSavedStateFile.isEmpty()) throw setErrorStatic(E_FAIL, "Invalid state of saved state file"); /* sync the state with the server */ @@ -9326,31 +9445,38 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) // STEP 3: save the VM state (if online) if (pTask->fTakingSnapshotOnline) { - Utf8Str strSavedStateFile(pTask->bstrSavedStateFile); - + int vrc; SafeVMPtr ptrVM(that); if (!ptrVM.isOk()) throw ptrVM.rc(); pTask->mProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(), pTask->ulMemSize); // operation weight, same as computed when setting up progress object - pTask->mProgress->setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM()); + if (!pTask->bstrSavedStateFile.isEmpty()) + { + Utf8Str strSavedStateFile(pTask->bstrSavedStateFile); - alock.release(); - LogFlowFunc(("VMR3Save...\n")); - int vrc = VMR3Save(ptrVM, + pTask->mProgress->setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM()); + + alock.release(); + LogFlowFunc(("VMR3Save...\n")); + vrc = VMR3Save(ptrVM.rawUVM(), strSavedStateFile.c_str(), true /*fContinueAfterwards*/, Console::stateProgressCallback, static_cast(pTask->mProgress), &fSuspenededBySave); - alock.acquire(); - if (RT_FAILURE(vrc)) - throw setErrorStatic(E_FAIL, - tr("Failed to save the machine state to '%s' (%Rrc)"), - strSavedStateFile.c_str(), vrc); + alock.acquire(); + if (RT_FAILURE(vrc)) + throw setErrorStatic(E_FAIL, + tr("Failed to save the machine state to '%s' (%Rrc)"), + strSavedStateFile.c_str(), vrc); + + pTask->mProgress->setCancelCallback(NULL, NULL); + } + else + LogRel(("Console: skipped saving state as part of online snapshot\n")); - pTask->mProgress->setCancelCallback(NULL, NULL); if (!pTask->mProgress->notifyPointOfNoReturn()) throw setErrorStatic(E_FAIL, tr("Canceled")); that->mptrCancelableProgress.setNull(); @@ -9415,23 +9541,11 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) * don't release the lock since reconfigureMediumAttachment * isn't going to need the Console lock. */ - vrc = VMR3ReqCallWait(ptrVM, - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - that, - ptrVM.raw(), - pcszDevice, - lInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - false /* fSetupMerge */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - atts[i], - that->mMachineState, - &rc); + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + that, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */, + 0 /* uMergeTarget */, atts[i], that->mMachineState, &rc); if (RT_FAILURE(vrc)) throw setErrorStatic(E_FAIL, Console::tr("%Rrc"), vrc); if (FAILED(rc)) @@ -9488,7 +9602,7 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) LogFlowFunc(("VMR3Resume...\n")); SafeVMPtr ptrVM(that); alock.release(); - int vrc = VMR3Resume(ptrVM); + int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED); alock.acquire(); if (RT_FAILURE(vrc)) { @@ -9546,7 +9660,7 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) LogFlowFunc(("VMR3Resume (on failure)...\n")); SafeVMPtr ptrVM(that); alock.release(); - int vrc = VMR3Resume(ptrVM); AssertLogRelRC(vrc); + int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED); AssertLogRelRC(vrc); alock.acquire(); if (RT_FAILURE(vrc)) that->setMachineState(MachineState_Paused); @@ -9606,7 +9720,7 @@ DECLCALLBACK(int) Console::saveStateThread(RTTHREAD Thread, void *pvUser) LogFlowFunc(("Saving the state to '%s'...\n", task->mSavedStateFile.c_str())); bool fSuspenededBySave; - int vrc = VMR3Save(task->mpVM, + int vrc = VMR3Save(task->mpUVM, task->mSavedStateFile.c_str(), false, /*fContinueAfterwards*/ Console::stateProgressCallback, @@ -9758,6 +9872,18 @@ Console::vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM) VirtualBoxBase::uninitializeComForThread(); } +/** + * @interface_method_impl{VMM2USERMETHODS,pfnNotifyResetTurnedIntoPowerOff} + */ +/*static*/ DECLCALLBACK(void) +Console::vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM) +{ + Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole; + NOREF(pUVM); + + pConsole->mfPowerOffCausedByReset = true; +} + @@ -9802,14 +9928,14 @@ typedef struct DRVMAINSTATUS */ DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN) { - PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, ILedConnectors)); - if (iLUN >= pData->iFirstLUN && iLUN <= pData->iLastLUN) + PDRVMAINSTATUS pThis = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, ILedConnectors)); + if (iLUN >= pThis->iFirstLUN && iLUN <= pThis->iLastLUN) { PPDMLED pLed; - int rc = pData->pLedPorts->pfnQueryStatusLed(pData->pLedPorts, iLUN, &pLed); + int rc = pThis->pLedPorts->pfnQueryStatusLed(pThis->pLedPorts, iLUN, &pLed); if (RT_FAILURE(rc)) pLed = NULL; - ASMAtomicWritePtr(&pData->papLeds[iLUN - pData->iFirstLUN], pLed); + ASMAtomicWritePtr(&pThis->papLeds[iLUN - pThis->iFirstLUN], pLed); Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed)); } } @@ -9824,17 +9950,17 @@ DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, */ DECLCALLBACK(int) Console::drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN) { - PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, IMediaNotify)); - PPDMDRVINS pDrvIns = pData->pDrvIns; + PDRVMAINSTATUS pThis = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, IMediaNotify)); + PPDMDRVINS pDrvIns = pThis->pDrvIns; LogFunc(("uLUN=%d\n", uLUN)); - if (pData->pmapMediumAttachments) + if (pThis->pmapMediumAttachments) { - AutoWriteLock alock(pData->pConsole COMMA_LOCKVAL_SRC_POS); + AutoWriteLock alock(pThis->pConsole COMMA_LOCKVAL_SRC_POS); ComPtr pMediumAtt; - Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pData->pszDeviceInstance, uLUN); - Console::MediumAttachmentMap::const_iterator end = pData->pmapMediumAttachments->end(); - Console::MediumAttachmentMap::const_iterator it = pData->pmapMediumAttachments->find(devicePath); + Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pThis->pszDeviceInstance, uLUN); + Console::MediumAttachmentMap::const_iterator end = pThis->pmapMediumAttachments->end(); + Console::MediumAttachmentMap::const_iterator it = pThis->pmapMediumAttachments->find(devicePath); if (it != end) pMediumAtt = it->second; Assert(!pMediumAtt.isNull()); @@ -9853,15 +9979,15 @@ DECLCALLBACK(int) Console::drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, alock.release(); ComPtr pNewMediumAtt; - rc = pData->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam()); + rc = pThis->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam()); if (SUCCEEDED(rc)) - fireMediumChangedEvent(pData->pConsole->mEventSource, pNewMediumAtt); + fireMediumChangedEvent(pThis->pConsole->mEventSource, pNewMediumAtt); alock.acquire(); if (pNewMediumAtt != pMediumAtt) { - pData->pmapMediumAttachments->erase(devicePath); - pData->pmapMediumAttachments->insert(std::make_pair(devicePath, pNewMediumAtt)); + pThis->pmapMediumAttachments->erase(devicePath); + pThis->pmapMediumAttachments->insert(std::make_pair(devicePath, pNewMediumAtt)); } } } @@ -9893,15 +10019,15 @@ DECLCALLBACK(void *) Console::drvStatus_QueryInterface(PPDMIBASE pInterface, co */ DECLCALLBACK(void) Console::drvStatus_Destruct(PPDMDRVINS pDrvIns) { - PDRVMAINSTATUS pData = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS); - LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS); + LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); - if (pData->papLeds) + if (pThis->papLeds) { - unsigned iLed = pData->iLastLUN - pData->iFirstLUN + 1; + unsigned iLed = pThis->iLastLUN - pThis->iFirstLUN + 1; while (iLed-- > 0) - ASMAtomicWriteNullPtr(&pData->papLeds[iLed]); + ASMAtomicWriteNullPtr(&pThis->papLeds[iLed]); } } @@ -9913,9 +10039,9 @@ DECLCALLBACK(void) Console::drvStatus_Destruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { - PDRVMAINSTATUS pData = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS); - LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS); + LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. @@ -9930,36 +10056,36 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf * Data. */ pDrvIns->IBase.pfnQueryInterface = Console::drvStatus_QueryInterface; - pData->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged; - pData->IMediaNotify.pfnEjected = Console::drvStatus_MediumEjected; - pData->pDrvIns = pDrvIns; - pData->pszDeviceInstance = NULL; + pThis->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged; + pThis->IMediaNotify.pfnEjected = Console::drvStatus_MediumEjected; + pThis->pDrvIns = pDrvIns; + pThis->pszDeviceInstance = NULL; /* * Read config. */ - int rc = CFGMR3QueryPtr(pCfg, "papLeds", (void **)&pData->papLeds); + int rc = CFGMR3QueryPtr(pCfg, "papLeds", (void **)&pThis->papLeds); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"papLeds\" value! rc=%Rrc\n", rc)); return rc; } - rc = CFGMR3QueryPtrDef(pCfg, "pmapMediumAttachments", (void **)&pData->pmapMediumAttachments, NULL); + rc = CFGMR3QueryPtrDef(pCfg, "pmapMediumAttachments", (void **)&pThis->pmapMediumAttachments, NULL); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"pmapMediumAttachments\" value! rc=%Rrc\n", rc)); return rc; } - if (pData->pmapMediumAttachments) + if (pThis->pmapMediumAttachments) { - rc = CFGMR3QueryStringAlloc(pCfg, "DeviceInstance", &pData->pszDeviceInstance); + rc = CFGMR3QueryStringAlloc(pCfg, "DeviceInstance", &pThis->pszDeviceInstance); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"DeviceInstance\" value! rc=%Rrc\n", rc)); return rc; } - rc = CFGMR3QueryPtr(pCfg, "pConsole", (void **)&pData->pConsole); + rc = CFGMR3QueryPtr(pCfg, "pConsole", (void **)&pThis->pConsole); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"pConsole\" value! rc=%Rrc\n", rc)); @@ -9967,26 +10093,26 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf } } - rc = CFGMR3QueryU32(pCfg, "First", &pData->iFirstLUN); + rc = CFGMR3QueryU32(pCfg, "First", &pThis->iFirstLUN); if (rc == VERR_CFGM_VALUE_NOT_FOUND) - pData->iFirstLUN = 0; + pThis->iFirstLUN = 0; else if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"First\" value! rc=%Rrc\n", rc)); return rc; } - rc = CFGMR3QueryU32(pCfg, "Last", &pData->iLastLUN); + rc = CFGMR3QueryU32(pCfg, "Last", &pThis->iLastLUN); if (rc == VERR_CFGM_VALUE_NOT_FOUND) - pData->iLastLUN = 0; + pThis->iLastLUN = 0; else if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"Last\" value! rc=%Rrc\n", rc)); return rc; } - if (pData->iFirstLUN > pData->iLastLUN) + if (pThis->iFirstLUN > pThis->iLastLUN) { - AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pData->iFirstLUN, pData->iLastLUN)); + AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pThis->iFirstLUN, pThis->iLastLUN)); return VERR_GENERAL_FAILURE; } @@ -9994,12 +10120,12 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf * Get the ILedPorts interface of the above driver/device and * query the LEDs we want. */ - pData->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); - AssertMsgReturn(pData->pLedPorts, ("Configuration error: No led ports interface above!\n"), + pThis->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); + AssertMsgReturn(pThis->pLedPorts, ("Configuration error: No led ports interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); - for (unsigned i = pData->iFirstLUN; i <= pData->iLastLUN; ++i) - Console::drvStatus_UnitChanged(&pData->ILedConnectors, i); + for (unsigned i = pThis->iFirstLUN; i <= pThis->iLastLUN; ++i) + Console::drvStatus_UnitChanged(&pThis->ILedConnectors, i); return VINF_SUCCESS; } diff --git a/src/VBox/Main/src-client/ConsoleImpl2.cpp b/src/VBox/Main/src-client/ConsoleImpl2.cpp index 515ba2bd..78feac8f 100644 --- a/src/VBox/Main/src-client/ConsoleImpl2.cpp +++ b/src/VBox/Main/src-client/ConsoleImpl2.cpp @@ -9,7 +9,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -46,6 +46,7 @@ #include "AutoCaller.h" #include "Logging.h" +#include #include #include #include @@ -113,15 +114,24 @@ # endif #endif /* VBOX_WITH_NETFLT */ -#include "DHCPServerRunner.h" +#include "NetworkServiceRunner.h" #include "BusAssignmentManager.h" #ifdef VBOX_WITH_EXTPACK # include "ExtPackManagerImpl.h" #endif - #if defined(RT_OS_DARWIN) - # include "IOKit/IOKitLib.h" +#endif + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue); + + + +#if defined(RT_OS_DARWIN) static int DarwinSmcKey(char *pabKey, uint32_t cbKey) { @@ -160,7 +170,7 @@ static int DarwinSmcKey(char *pabKey, uint32_t cbKey) for (int i = 0; i < 2; i++) { - inputStruct.key = (uint32_t)((i == 0) ? 'OSK0' : 'OSK1'); + inputStruct.key = (uint32_t)(i == 0 ? 'OSK0' : 'OSK1'); kr = IOConnectCallStructMethod((mach_port_t)port, (uint32_t)2, (const void *)&inputStruct, @@ -246,20 +256,18 @@ static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str * return VINF_SUCCESS; } -static int getSmcDeviceKey(IMachine *pMachine, BSTR *aKey, bool *pfGetKeyFromRealSMC) +/** + * @throws HRESULT on extra data retrival error. + */ +static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC) { *pfGetKeyFromRealSMC = false; /* * The extra data takes precedence (if non-zero). */ - HRESULT hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/SmcDeviceKey").raw(), - aKey); - if (FAILED(hrc)) - return Global::vboxStatusCodeFromCOM(hrc); - if ( SUCCEEDED(hrc) - && *aKey - && **aKey) + GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey); + if (pStrKey->isNotEmpty()) return VINF_SUCCESS; #ifdef RT_OS_DARWIN @@ -270,7 +278,8 @@ static int getSmcDeviceKey(IMachine *pMachine, BSTR *aKey, bool *pfGetKeyFromRea int rc = DarwinSmcKey(abKeyBuf, sizeof(abKeyBuf)); if (SUCCEEDED(rc)) { - Bstr(abKeyBuf).detachTo(aKey); + *pStrKey = abKeyBuf; + *pfGetKeyFromRealSMC = true; return rc; } LogRel(("Warning: DarwinSmcKey failed with rc=%Rrc!\n", rc)); @@ -296,10 +305,10 @@ static int getSmcDeviceKey(IMachine *pMachine, BSTR *aKey, bool *pfGetKeyFromRea char szProdName[256]; szProdName[0] = '\0'; RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName)); - if ( ( !strncmp(szProdName, "Mac", 3) - || !strncmp(szProdName, "iMac", 4) - || !strncmp(szProdName, "iMac", 4) - || !strncmp(szProdName, "Xserve", 6) + if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac")) + || !strncmp(szProdName, RT_STR_TUPLE("iMac")) + || !strncmp(szProdName, RT_STR_TUPLE("iMac")) + || !strncmp(szProdName, RT_STR_TUPLE("Xserve")) ) && !strchr(szProdName, ' ') /* no spaces */ && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */ @@ -464,10 +473,137 @@ static void RemoveConfigValue(PCFGMNODE pNode, throw ConfigError("CFGMR3RemoveValue", vrc, pcszName); } +/** + * Gets an extra data value, consulting both machine and global extra data. + * + * @throws HRESULT on failure + * @returns pStrValue for the callers convenience. + * @param pVirtualBox Pointer to the IVirtualBox interface. + * @param pMachine Pointer to the IMachine interface. + * @param pszName The value to get. + * @param pStrValue Where to return it's value (empty string if not + * found). + */ +static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue) +{ + pStrValue->setNull(); + + Bstr bstrName(pszName); + Bstr bstrValue; + HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam()); + if (FAILED(hrc)) + throw hrc; + if (bstrValue.isEmpty()) + { + hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam()); + if (FAILED(hrc)) + throw hrc; + } + + if (bstrValue.isNotEmpty()) + *pStrValue = bstrValue; + return pStrValue; +} + + +/** Helper that finds out the next HBA port used + */ +static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size) +{ + LONG lNextPortUsed = 30; + for (size_t j = 0; j < u32Size; ++j) + { + if ( aPortUsed[j] > lBaseVal + && aPortUsed[j] <= lNextPortUsed) + lNextPortUsed = aPortUsed[j]; + } + return lNextPortUsed; +} + +#define MAX_BIOS_LUN_COUNT 4 + +static int SetBiosDiskInfo(ComPtr pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg, + Bstr controllerName, const char * const s_apszBiosConfig[4]) +{ + HRESULT hrc; +#define MAX_DEVICES 30 +#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE) + + LONG lPortLUN[MAX_BIOS_LUN_COUNT]; + LONG lPortUsed[MAX_DEVICES]; + uint32_t u32HDCount = 0; + + /* init to max value */ + lPortLUN[0] = MAX_DEVICES; + + com::SafeIfaceArray atts; + hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(), + ComSafeArrayAsOutParam(atts)); H(); + size_t uNumAttachments = atts.size(); + if (uNumAttachments > MAX_DEVICES) + { + LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments)); + uNumAttachments = MAX_DEVICES; + } + + /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */ + for (size_t j = 0; j < uNumAttachments; ++j) + { + IMediumAttachment *pMediumAtt = atts[j]; + LONG lPortNum = 0; + hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H(); + if (SUCCEEDED(hrc)) + { + DeviceType_T lType; + hrc = pMediumAtt->COMGETTER(Type)(&lType); H(); + if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk) + { + /* find min port number used for HD */ + if (lPortNum < lPortLUN[0]) + lPortLUN[0] = lPortNum; + lPortUsed[u32HDCount++] = lPortNum; + LogFlowFunc(("HD port Count=%d\n", u32HDCount)); + } + + /* Configure the hotpluggable flag for the port. */ + BOOL fHotPluggable = FALSE; + hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H(); + if (SUCCEEDED(hrc)) + { + PCFGMNODE pPortCfg; + char szName[24]; + RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum); + + InsertConfigNode(pCfg, szName, &pPortCfg); + InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0); + } + } + } + + + /* Pick only the top 4 used HD Ports as CMOS doesn't have space + * to save details for all 30 ports + */ + uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT; + if (u32HDCount < MAX_BIOS_LUN_COUNT) + u32MaxPortCount = u32HDCount; + for (size_t j = 1; j < u32MaxPortCount; j++) + lPortLUN[j] = GetNextUsedPort(lPortUsed, + lPortLUN[j-1], + u32HDCount); + if (pBiosCfg) + { + for (size_t j = 0; j < u32MaxPortCount; j++) + { + InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]); + LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j])); + } + } + return VINF_SUCCESS; +} + #ifdef VBOX_WITH_PCI_PASSTHROUGH -HRESULT Console::attachRawPCIDevices(PVM pVM, - BusAssignmentManager *BusMgr, - PCFGMNODE pDevices) +HRESULT Console::attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices) { HRESULT hrc = S_OK; PCFGMNODE pInst, pCfg, pLunL0, pLunL1; @@ -491,14 +627,12 @@ HRESULT Console::attachRawPCIDevices(PVM pVM, # ifdef VBOX_WITH_EXTPACK static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack"; if (!mptrExtPackManager->isExtPackUsable(s_pszPCIRawExtPackName)) - { /* Always fatal! */ - return VMSetError(pVM, VERR_NOT_FOUND, RT_SRC_POS, + return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS, N_("Implementation of the PCI passthrough framework not found!\n" "The VM cannot be started. To fix this problem, either " "install the '%s' or disable PCI passthrough via VBoxManage"), s_pszPCIRawExtPackName); - } # endif PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge"); @@ -520,7 +654,7 @@ HRESULT Console::attachRawPCIDevices(PVM pVM, int iBridgesMissed = 0; int iBase = GuestPCIAddress.miBus - 1; - while (!BusMgr->hasPCIDevice("ich9pcibridge", iBase) && iBase > 0) + while (!pBusMgr->hasPCIDevice("ich9pcibridge", iBase) && iBase > 0) { iBridgesMissed++; iBase--; } @@ -530,7 +664,7 @@ HRESULT Console::attachRawPCIDevices(PVM pVM, { InsertConfigNode(pBridges, Utf8StrFmt("%d", iBase + iBridge).c_str(), &pInst); InsertConfigInteger(pInst, "Trusted", 1); - hrc = BusMgr->assignPCIDevice("ich9pcibridge", pInst); + hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); } } } @@ -583,7 +717,7 @@ HRESULT Console::attachRawPCIDevices(PVM pVM, GuestPCIAddress.fromLong(guest); Assert(GuestPCIAddress.valid()); - hrc = BusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true); + hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true); if (hrc != S_OK) return hrc; @@ -638,13 +772,14 @@ void Console::attachStatusDriver(PCFGMNODE pCtlInst, PPDMLED *papLeds, * in the emulation thread (EMT). Any per thread COM/XPCOM initialization * is done here. * - * @param pVM VM handle. + * @param pUVM The user mode VM handle. + * @param pVM The cross context VM handle. * @param pvConsole Pointer to the VMPowerUpTask object. * @return VBox status code. * * @note Locks the Console object for writing. */ -DECLCALLBACK(int) Console::configConstructor(PVM pVM, void *pvConsole) +DECLCALLBACK(int) Console::configConstructor(PUVM pUVM, PVM pVM, void *pvConsole) { LogFlowFuncEnter(); @@ -661,12 +796,12 @@ DECLCALLBACK(int) Console::configConstructor(PVM pVM, void *pvConsole) * Set the VM handle and do the rest of the job in an worker method so we * can easily reset the VM handle on failure. */ - PUVM pUVM = pConsole->mpUVM = VMR3GetUVM(pVM); + pConsole->mpUVM = pUVM; VMR3RetainUVM(pUVM); int vrc; try { - vrc = pConsole->configConstructorInner(pVM, &alock); + vrc = pConsole->configConstructorInner(pUVM, pVM, &alock); } catch (...) { @@ -686,20 +821,20 @@ DECLCALLBACK(int) Console::configConstructor(PVM pVM, void *pvConsole) * Worker for configConstructor. * * @return VBox status code. - * @param pVM The VM handle. + * @param pUVM The user mode VM handle. + * @param pVM The cross context VM handle. * @param pAlock The automatic lock instance. This is for when we have * to leave it in order to avoid deadlocks (ext packs and * more). */ -int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) +int Console::configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock) { - VMMDev *pVMMDev = m_pVMMDev; - Assert(pVMMDev); - + VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev); ComPtr pMachine = machine(); int rc; HRESULT hrc; + Utf8Str strTmp; Bstr bstr; #define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE) @@ -746,7 +881,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) uMcfgBase = _4G - cbRamHole; } - BusAssignmentManager* BusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType); + BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType); ULONG cCpus = 1; hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H(); @@ -756,6 +891,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) Bstr osTypeId; hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H(); + LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str())); BOOL fIOAPIC; hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H(); @@ -773,7 +909,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) * Get root node first. * This is the only node in the tree. */ - PCFGMNODE pRoot = CFGMR3GetRoot(pVM); + PCFGMNODE pRoot = CFGMR3GetRootU(pUVM); Assert(pRoot); // InsertConfigString throws @@ -798,6 +934,15 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pRoot, "PATMEnabled", 1); /* boolean */ InsertConfigInteger(pRoot, "CSAMEnabled", 1); /* boolean */ #endif + +#ifdef VBOX_WITH_RAW_RING1 + if (osTypeId == "QNX") + { + /* QNX needs special treatment in raw mode due to its use of ring-1. */ + InsertConfigInteger(pRoot, "RawR1Enabled", 1); /* boolean */ + } +#endif + /* Not necessary, but to make sure these two settings end up in the release log. */ BOOL fPageFusion = FALSE; hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H(); @@ -844,6 +989,14 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pCPUM, "NT4LeafLimit", true); } + /* Expose CMPXCHG16B. Currently a hack. */ + if ( osTypeId == "Windows81_64" + || osTypeId == "Windows2012_64") + { + LogRel(("Enabling CMPXCHG16B for Windows 8.1 / 2k12 guests\n")); + InsertConfigInteger(pCPUM, "CMPXCHG16B", true); + } + /* Expose extended MWAIT features to Mac OS X guests. */ if (fOsXGuest) { @@ -851,128 +1004,188 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pCPUM, "MWaitExtensions", true); } + if (fOsXGuest) + { + InsertConfigInteger(pCPUM, "EnableHVP", 1); + + /* Fake the CPU family/model so the guest works. This is partly + because older mac releases really doesn't work on newer cpus, + and partly because mac os x expects more from systems with newer + cpus (MSRs, power features, whatever). */ + uint32_t uMaxIntelFamilyModelStep = UINT32_MAX; + if ( osTypeId == "MacOS" + || osTypeId == "MacOS_64") + uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 7); /* Penryn / X5482. */ + else if ( osTypeId == "MacOS106" + || osTypeId == "MacOS106_64") + uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 7); /* Penryn / X5482 */ + else if ( osTypeId == "MacOS107" + || osTypeId == "MacOS107_64") + uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 7); /* Penryn / X5482 */ /** @todo figure out what is required here. */ + else if ( osTypeId == "MacOS108" + || osTypeId == "MacOS108_64") + uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 7); /* Penryn / X5482 */ /** @todo figure out what is required here. */ + else if ( osTypeId == "MacOS109" + || osTypeId == "MacOS109_64") + uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 7); /* Penryn / X5482 */ /** @todo figure out what is required here. */ + if (uMaxIntelFamilyModelStep != UINT32_MAX) + InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep); + } + + + /* Synthetic CPU */ + BOOL fSyntheticCpu = false; + hrc = pMachine->GetCPUProperty(CPUPropertyType_Synthetic, &fSyntheticCpu); H(); + InsertConfigInteger(pCPUM, "SyntheticCpu", fSyntheticCpu); + + /* Physical Address Extension (PAE) */ + BOOL fEnablePAE = false; + hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H(); + InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE); + + /* * Hardware virtualization extensions. */ - BOOL fHWVirtExEnabled; - BOOL fHwVirtExtForced = false; + BOOL fSupportsHwVirtEx; + hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx); H(); + + BOOL fIsGuest64Bit; + hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H(); + if (fIsGuest64Bit) + { + BOOL fSupportsLongMode; + hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H(); + if (!fSupportsLongMode) + { + LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n")); + fIsGuest64Bit = FALSE; + } + if (!fSupportsHwVirtEx) + { + LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n")); + fIsGuest64Bit = FALSE; + } + } + + BOOL fHMEnabled; + hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H(); + if (cCpus > 1 && !fHMEnabled) + { + LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n")); + fHMEnabled = TRUE; + } + + BOOL fHMForced; #ifdef VBOX_WITH_RAW_MODE - hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHWVirtExEnabled); H(); - if (cCpus > 1) /** @todo SMP: This isn't nice, but things won't work on mac otherwise. */ - fHWVirtExEnabled = TRUE; -# ifdef RT_OS_DARWIN - fHwVirtExtForced = fHWVirtExEnabled; -# else /* - With more than 4GB PGM will use different RAMRANGE sizes for raw mode and hv mode to optimize lookup times. - - With more than one virtual CPU, raw-mode isn't a fallback option. */ - fHwVirtExtForced = fHWVirtExEnabled - && ( cbRam + cbRamHole > _4G - || cCpus > 1); + - With more than one virtual CPU, raw-mode isn't a fallback option. + - With a 64-bit guest, raw-mode isn't a fallback option either. */ + fHMForced = fHMEnabled + && ( cbRam + cbRamHole > _4G + || cCpus > 1 + || fIsGuest64Bit); +# ifdef RT_OS_DARWIN + fHMForced = fHMEnabled; # endif + if (fHMForced) + { + if (cbRam + cbRamHole > _4G) + LogRel(("fHMForced=true - Lots of RAM\n")); + if (cCpus > 1) + LogRel(("fHMForced=true - SMP\n")); + if (fIsGuest64Bit) + LogRel(("fHMForced=true - 64-bit guest\n")); +# ifdef RT_OS_DARWIN + LogRel(("fHMForced=true - Darwin host\n")); +# endif + } #else /* !VBOX_WITH_RAW_MODE */ - fHWVirtExEnabled = fHwVirtExtForced = true; + fHMEnabled = fHMForced = TRUE; + LogRel(("fHMForced=true - No raw-mode support in this build!\n")); #endif /* !VBOX_WITH_RAW_MODE */ - /* only honor the property value if there was no other reason to enable it */ - if (!fHwVirtExtForced) + if (!fHMForced) /* No need to query if already forced above. */ { - hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHwVirtExtForced); H(); + hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H(); + if (fHMForced) + LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n")); } - InsertConfigInteger(pRoot, "HwVirtExtForced", fHwVirtExtForced); - - - /* - * MM values. - */ - PCFGMNODE pMM; - InsertConfigNode(pRoot, "MM", &pMM); - InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9); - - /* - * Hardware virtualization settings. - */ - BOOL fIsGuest64Bit = false; - PCFGMNODE pHWVirtExt; - InsertConfigNode(pRoot, "HWVirtExt", &pHWVirtExt); - if (fHWVirtExEnabled) + InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled); + + /* /EM/xzy */ + PCFGMNODE pEM; + InsertConfigNode(pRoot, "EM", &pEM); + + /* Triple fault behavior. */ + BOOL fTripleFaultReset = false; + hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H(); + InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset); + + /* /HM/xzy */ + PCFGMNODE pHM; + InsertConfigNode(pRoot, "HM", &pHM); + InsertConfigInteger(pHM, "HMForced", fHMForced); + if (fHMEnabled) { - InsertConfigInteger(pHWVirtExt, "Enabled", 1); - /* Indicate whether 64-bit guests are supported or not. */ - /** @todo This is currently only forced off on 32-bit hosts only because it - * makes a lof of difference there (REM and Solaris performance). - */ - BOOL fSupportsLongMode = false; - hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, - &fSupportsLongMode); H(); - hrc = guestOSType->COMGETTER(Is64Bit)(&fIsGuest64Bit); H(); - - if (fSupportsLongMode && fIsGuest64Bit) - { - InsertConfigInteger(pHWVirtExt, "64bitEnabled", 1); + InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit); #if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */ - PCFGMNODE pREM; - InsertConfigNode(pRoot, "REM", &pREM); - InsertConfigInteger(pREM, "64bitEnabled", 1); -#endif - } -#if ARCH_BITS == 32 /* 32-bit guests only. */ - else - { - InsertConfigInteger(pHWVirtExt, "64bitEnabled", 0); - } + PCFGMNODE pREM; + InsertConfigNode(pRoot, "REM", &pREM); + InsertConfigInteger(pREM, "64bitEnabled", 1); #endif /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better, but that requires quite a bit of API change in Main. */ - if ( !fIsGuest64Bit - && fIOAPIC + if ( fIOAPIC && ( osTypeId == "WindowsNT4" - || osTypeId == "Windows2000" - || osTypeId == "WindowsXP" - || osTypeId == "Windows2003")) + || osTypeId == "Windows2000" + || osTypeId == "WindowsXP" + || osTypeId == "Windows2003")) { /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode) * We may want to consider adding more guest OSes (Solaris) later on. */ - InsertConfigInteger(pHWVirtExt, "TPRPatchingEnabled", 1); + InsertConfigInteger(pHM, "TPRPatchingEnabled", 1); } } /* HWVirtEx exclusive mode */ - BOOL fHWVirtExExclusive = true; - hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Exclusive, &fHWVirtExExclusive); H(); - InsertConfigInteger(pHWVirtExt, "Exclusive", fHWVirtExExclusive); + BOOL fHMExclusive = true; + hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H(); + InsertConfigInteger(pHM, "Exclusive", fHMExclusive); /* Nested paging (VT-x/AMD-V) */ BOOL fEnableNestedPaging = false; hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H(); - InsertConfigInteger(pHWVirtExt, "EnableNestedPaging", fEnableNestedPaging); + InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging); /* Large pages; requires nested paging */ BOOL fEnableLargePages = false; hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H(); - InsertConfigInteger(pHWVirtExt, "EnableLargePages", fEnableLargePages); + InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages); /* VPID (VT-x) */ BOOL fEnableVPID = false; hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H(); - InsertConfigInteger(pHWVirtExt, "EnableVPID", fEnableVPID); + InsertConfigInteger(pHM, "EnableVPID", fEnableVPID); - /* Physical Address Extension (PAE) */ - BOOL fEnablePAE = false; - hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H(); - InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE); + /* Unrestricted execution aka UX (VT-x) */ + BOOL fEnableUX = false; + hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H(); + InsertConfigInteger(pHM, "EnableUX", fEnableUX); - /* Synthetic CPU */ - BOOL fSyntheticCpu = false; - hrc = pMachine->GetCPUProperty(CPUPropertyType_Synthetic, &fSyntheticCpu); H(); - InsertConfigInteger(pCPUM, "SyntheticCpu", fSyntheticCpu); + /* Reset overwrite. */ + if (isResetTurnedIntoPowerOff()) + InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1); - if (fOsXGuest) - InsertConfigInteger(pCPUM, "EnableHVP", 1); - BOOL fPXEDebug; - hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H(); + /* + * MM values. + */ + PCFGMNODE pMM; + InsertConfigNode(pRoot, "MM", &pMM); + InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9); /* * PDM config. @@ -1039,7 +1252,11 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H(); hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H(); - hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H(); + hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H(); + + if (strName.isEmpty()) + return VMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, + N_("No bandwidth group name specified")); if (enmType == BandwidthGroupType_Disk) { @@ -1072,6 +1289,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) PCFGMNODE pLunL2 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config/ */ PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */ PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */ + bool fHaveBiosScsiConfig = false; InsertConfigNode(pRoot, "Devices", &pDevices); @@ -1133,15 +1351,15 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pDevices, "ich9pcibridge", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("ich9pcibridge", pInst); H(); + hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H(); InsertConfigNode(pDev, "1", &pInst); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("ich9pcibridge", pInst); H(); + hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H(); #ifdef VBOX_WITH_PCI_PASSTHROUGH /* Add PCI passthrough devices */ - hrc = attachRawPCIDevices(pVM, BusMgr, pDevices); H(); + hrc = attachRawPCIDevices(pUVM, pBusMgr, pDevices); H(); #endif } @@ -1181,11 +1399,11 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pInst, "Config", &pCfg); bool fGetKeyFromRealSMC; - Bstr bstrKey; - rc = getSmcDeviceKey(pMachine, bstrKey.asOutParam(), &fGetKeyFromRealSMC); + Utf8Str strKey; + rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC); AssertRCReturn(rc, rc); - InsertConfigString(pCfg, "DeviceKey", bstrKey); + InsertConfigString(pCfg, "DeviceKey", strKey); InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC); } @@ -1199,7 +1417,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) { InsertConfigNode(pDevices, "lpc", &pDev); InsertConfigNode(pDev, "0", &pInst); - hrc = BusMgr->assignPCIDevice("lpc", pInst); H(); + hrc = pBusMgr->assignPCIDevice("lpc", pInst); H(); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ } @@ -1225,6 +1443,9 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) Keyboard *pKeyboard = mKeyboard; InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard); + Mouse *pMouse = mMouse; + PointingHIDType_T aPointingHID; + hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H(); InsertConfigNode(pInst, "LUN#1", &pLunL0); InsertConfigString(pLunL0, "Driver", "MouseQueue"); InsertConfigNode(pLunL0, "Config", &pCfg); @@ -1233,7 +1454,6 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); InsertConfigString(pLunL1, "Driver", "MainMouse"); InsertConfigNode(pLunL1, "Config", &pCfg); - Mouse *pMouse = mMouse; InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse); /* @@ -1291,87 +1511,26 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) /* * VGA. */ - InsertConfigNode(pDevices, "vga", &pDev); - InsertConfigNode(pDev, "0", &pInst); - InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - - hrc = BusMgr->assignPCIDevice("vga", pInst); H(); - InsertConfigNode(pInst, "Config", &pCfg); - ULONG cVRamMBs; - hrc = pMachine->COMGETTER(VRAMSize)(&cVRamMBs); H(); - InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M); - ULONG cMonitorCount; - hrc = pMachine->COMGETTER(MonitorCount)(&cMonitorCount); H(); - InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount); -#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE - InsertConfigInteger(pCfg, "R0Enabled", fHWVirtExEnabled); -#endif - - /* - * BIOS logo - */ - BOOL fFadeIn; - hrc = biosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H(); - InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0); - BOOL fFadeOut; - hrc = biosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H(); - InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0); - ULONG logoDisplayTime; - hrc = biosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H(); - InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime); - Bstr logoImagePath; - hrc = biosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H(); - InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") ); - - /* - * Boot menu - */ - BIOSBootMenuMode_T eBootMenuMode; - int iShowBootMenu; - biosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); - switch (eBootMenuMode) - { - case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break; - case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break; - default: iShowBootMenu = 2; break; - } - InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu); - - /* Custom VESA mode list */ - unsigned cModes = 0; - for (unsigned iMode = 1; iMode <= 16; ++iMode) + GraphicsControllerType_T graphicsController; + hrc = pMachine->COMGETTER(GraphicsControllerType)(&graphicsController); H(); + switch (graphicsController) { - char szExtraDataKey[sizeof("CustomVideoModeXX")]; - RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode); - hrc = pMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H(); - if (bstr.isEmpty()) + case GraphicsControllerType_Null: break; - InsertConfigString(pCfg, szExtraDataKey, bstr); - ++cModes; - } - InsertConfigInteger(pCfg, "CustomVideoModes", cModes); - - /* VESA height reduction */ - ULONG ulHeightReduction; - IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer(); - if (pFramebuffer) - { - hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H(); - } - else - { - /* If framebuffer is not available, there is no height reduction. */ - ulHeightReduction = 0; + case GraphicsControllerType_VBoxVGA: +#ifdef VBOX_WITH_VMSVGA + case GraphicsControllerType_VMSVGA: +#endif + rc = configGraphicsController(pDevices, graphicsController, pBusMgr, pMachine, biosSettings, + RT_BOOL(fHMEnabled)); + if (FAILED(rc)) + return rc; + break; + default: + AssertMsgFailed(("Invalid graphicsController=%d\n", graphicsController)); + return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, + N_("Invalid graphics controller type '%d'"), graphicsController); } - InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction); - - /* Attach the display. */ - InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigString(pLunL0, "Driver", "MainDisplay"); - InsertConfigNode(pLunL0, "Config", &pCfg); - Display *pDisplay = mDisplay; - InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay); - /* * Firmware. @@ -1399,6 +1558,8 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide"); InsertConfigString(pBiosCfg, "FloppyDevice", "i82078"); InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC); + BOOL fPXEDebug; + hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H(); InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug); InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid)); InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg); @@ -1406,12 +1567,8 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength); DeviceType_T bootDevice; - if (SchemaDefs::MaxBootPosition > 9) - { - AssertMsgFailed(("Too many boot devices %d\n", - SchemaDefs::MaxBootPosition)); - return VERR_INVALID_PARAMETER; - } + AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition), + VERR_INVALID_PARAMETER); for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos) { @@ -1440,11 +1597,16 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) break; default: AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice)); - return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, - N_("Invalid boot device '%d'"), bootDevice); + return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, + N_("Invalid boot device '%d'"), bootDevice); } InsertConfigString(pBiosCfg, szParamName, pszBootDevice); } + + /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now, + * this is required for Windows 2012 guests. */ + if (osTypeId == "Windows2012_64") + InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */ } else { @@ -1462,29 +1624,29 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) AssertRCReturn(rc, rc); /* Get boot args */ - Bstr bootArgs; - hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiBootArgs").raw(), bootArgs.asOutParam()); H(); + Utf8Str bootArgs; + GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs); /* Get device props */ - Bstr deviceProps; - hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiDeviceProps").raw(), deviceProps.asOutParam()); H(); + Utf8Str deviceProps; + GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps); /* Get GOP mode settings */ uint32_t u32GopMode = UINT32_MAX; - hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiGopMode").raw(), bstr.asOutParam()); H(); - if (!bstr.isEmpty()) - u32GopMode = Utf8Str(bstr).toUInt32(); + GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp); + if (!strTmp.isEmpty()) + u32GopMode = strTmp.toUInt32(); /* UGA mode settings */ uint32_t u32UgaHorisontal = 0; - hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiUgaHorizontalResolution").raw(), bstr.asOutParam()); H(); - if (!bstr.isEmpty()) - u32UgaHorisontal = Utf8Str(bstr).toUInt32(); + GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp); + if (!strTmp.isEmpty()) + u32UgaHorisontal = strTmp.toUInt32(); uint32_t u32UgaVertical = 0; - hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiUgaVerticalResolution").raw(), bstr.asOutParam()); H(); - if (!bstr.isEmpty()) - u32UgaVertical = Utf8Str(bstr).toUInt32(); + GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp); + if (!strTmp.isEmpty()) + u32UgaVertical = strTmp.toUInt32(); /* * EFI subtree. @@ -1512,11 +1674,10 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pCfg, "DmiUseHostInfo", 1); InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1); } - PCFGMNODE pDrv; InsertConfigNode(pInst, "LUN#0", &pLunL0); InsertConfigString(pLunL0, "Driver", "NvramStorage"); InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigInteger(pCfg, "Object", (uint64_t)mNvram); + InsertConfigInteger(pCfg, "Object", (uintptr_t)mNvram); #ifdef DEBUG_vvl InsertConfigInteger(pCfg, "PermanentSave", 1); #endif @@ -1570,14 +1731,32 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pCtlInst, "Trusted", 1); InsertConfigNode(pCtlInst, "Config", &pCfg); + static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] = + { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" }; + + static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] = + { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" }; + switch (enmCtrlType) { case StorageControllerType_LsiLogic: { - hrc = BusMgr->assignPCIDevice("lsilogic", pCtlInst); H(); + hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H(); InsertConfigInteger(pCfg, "Bootable", fBootable); + /* BIOS configuration values, first controller only. */ + if (!pBusMgr->hasPCIDevice("lsilogicscsi", 1) && pBiosCfg) + { + if (!fHaveBiosScsiConfig) + { + fHaveBiosScsiConfig = true; + InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi"); + + hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H(); + } + } + /* Attach the status driver */ Assert(cLedScsi >= 16); attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15, @@ -1588,10 +1767,22 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) case StorageControllerType_BusLogic: { - hrc = BusMgr->assignPCIDevice("buslogic", pCtlInst); H(); + hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H(); InsertConfigInteger(pCfg, "Bootable", fBootable); + /* BIOS configuration values, first controller only. */ + if (!pBusMgr->hasPCIDevice("buslogic", 1) && pBiosCfg) + { + if (!fHaveBiosScsiConfig) + { + fHaveBiosScsiConfig = true; + InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic"); + + hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H(); + } + } + /* Attach the status driver */ Assert(cLedScsi >= 16); attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15, @@ -1602,7 +1793,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) case StorageControllerType_IntelAhci: { - hrc = BusMgr->assignPCIDevice("ahci", pCtlInst); H(); + hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H(); ULONG cPorts = 0; hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H(); @@ -1610,12 +1801,14 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigInteger(pCfg, "Bootable", fBootable); /* Needed configuration values for the bios, only first controller. */ - if (!BusMgr->hasPCIDevice("ahci", 1)) + if (!pBusMgr->hasPCIDevice("ahci", 1)) { if (pBiosCfg) { InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci"); } + + hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H(); } /* Attach the status driver */ @@ -1633,7 +1826,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) /* * IDE (update this when the main interface changes) */ - hrc = BusMgr->assignPCIDevice("piix3ide", pCtlInst); H(); + hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H(); InsertConfigString(pCfg, "Type", controllerString(enmCtrlType)); /* Attach the status driver */ Assert(cLedIde >= 4); @@ -1669,11 +1862,27 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) case StorageControllerType_LsiLogicSas: { - hrc = BusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H(); + hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H(); InsertConfigString(pCfg, "ControllerType", "SAS1068"); InsertConfigInteger(pCfg, "Bootable", fBootable); + /* BIOS configuration values, first controller only. */ + if (!pBusMgr->hasPCIDevice("lsilogicsas", 1) && pBiosCfg) + { + if (!fHaveBiosScsiConfig) + { + fHaveBiosScsiConfig = true; + InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas"); + + hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H(); + } + } + + ULONG cPorts = 0; + hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H(); + InsertConfigInteger(pCfg, "NumPorts", cPorts); + /* Attach the status driver */ Assert(cLedSas >= 8); attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7, @@ -1714,8 +1923,9 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) false /* fAttachDetach */, false /* fForceUnmount */, false /* fHotplug */, - pVM, - paLedDevType); + pUVM, + paLedDevType, + NULL /* ppLunL0 */); if (RT_FAILURE(rc)) return rc; } @@ -1778,9 +1988,9 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) default: AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, ulInstance)); - return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, - N_("Invalid network adapter type '%d' for slot '%d'"), - adapterType, ulInstance); + return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, + N_("Invalid network adapter type '%d' for slot '%d'"), + adapterType, ulInstance); } InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst); @@ -1807,7 +2017,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) #ifdef VMWARE_NET_IN_SLOT_11 /* * Dirty hack for PCI slot compatibility with VMWare, - * it assigns slot 11 to the first network controller. + * it assigns slot 0x11 to the first network controller. */ if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM) { @@ -1818,7 +2028,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) iPCIDeviceNo = 3; #endif PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0); - hrc = BusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H(); + hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H(); InsertConfigNode(pInst, "Config", &pCfg); #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */ @@ -1872,7 +2082,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) char *macStr = (char*)macAddrUtf8.c_str(); Assert(strlen(macStr) == 12); RTMAC Mac; - memset(&Mac, 0, sizeof(Mac)); + RT_ZERO(Mac); char *pMac = (char*)&Mac; for (uint32_t i = 0; i < 6; ++i) { @@ -2051,7 +2261,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pDev, "0", &pInst); InsertConfigNode(pInst, "Config", &pCfg); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("VMMDev", pInst); H(); + hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H(); Bstr hwVersion; hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H(); @@ -2108,7 +2318,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pDevices, "ichac97", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("ichac97", pInst); H(); + hrc = pBusMgr->assignPCIDevice("ichac97", pInst); H(); InsertConfigNode(pInst, "Config", &pCfg); break; } @@ -2132,7 +2342,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pDevices, "hda", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("hda", pInst); H(); + hrc = pBusMgr->assignPCIDevice("hda", pInst); H(); InsertConfigNode(pInst, "Config", &pCfg); } } @@ -2217,34 +2427,55 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) } /* - * The USB Controller. + * The USB Controllers. */ - ComPtr USBCtlPtr; - hrc = pMachine->COMGETTER(USBController)(USBCtlPtr.asOutParam()); - if (USBCtlPtr) + com::SafeIfaceArray usbCtrls; + hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls)); H(); + bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is presnet. */ + + for (size_t i = 0; i < usbCtrls.size(); ++i) { - BOOL fOhciEnabled; - hrc = USBCtlPtr->COMGETTER(Enabled)(&fOhciEnabled); H(); - if (fOhciEnabled) + USBControllerType_T enmCtrlType; + rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H(); + if (enmCtrlType == USBControllerType_OHCI) { - InsertConfigNode(pDevices, "usb-ohci", &pDev); - InsertConfigNode(pDev, "0", &pInst); - InsertConfigNode(pInst, "Config", &pCfg); - InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("usb-ohci", pInst); H(); - InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigString(pLunL0, "Driver", "VUSBRootHub"); - InsertConfigNode(pLunL0, "Config", &pCfg); + fOhciPresent = true; + break; + } + } - /* - * Attach the status driver. - */ - attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0); + /* + * Currently EHCI is only enabled when a OHCI controller is present too. + * This might change when XHCI is supported. + */ + if (fOhciPresent) + mfVMHasUsbController = true; + if (mfVMHasUsbController) + { + for (size_t i = 0; i < usbCtrls.size(); ++i) + { + USBControllerType_T enmCtrlType; + rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H(); + + if (enmCtrlType == USBControllerType_OHCI) + { + InsertConfigNode(pDevices, "usb-ohci", &pDev); + InsertConfigNode(pDev, "0", &pInst); + InsertConfigNode(pInst, "Config", &pCfg); + InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ + hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H(); + InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigString(pLunL0, "Driver", "VUSBRootHub"); + InsertConfigNode(pLunL0, "Config", &pCfg); + + /* + * Attach the status driver. + */ + attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0); + } #ifdef VBOX_WITH_EHCI - BOOL fEHCIEnabled; - hrc = USBCtlPtr->COMGETTER(EnabledEHCI)(&fEHCIEnabled); H(); - if (fEHCIEnabled) + else if (enmCtrlType == USBControllerType_EHCI) { /* * USB 2.0 is only available if the proper ExtPack is installed. @@ -2263,7 +2494,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) InsertConfigNode(pDev, "0", &pInst); InsertConfigNode(pInst, "Config", &pCfg); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ - hrc = BusMgr->assignPCIDevice("usb-ehci", pInst); H(); + hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H(); InsertConfigNode(pInst, "LUN#0", &pLunL0); InsertConfigString(pLunL0, "Driver", "VUSBRootHub"); @@ -2279,7 +2510,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) { /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway * but this induced problems when the user saved + restored the VM! */ - return VMSetError(pVM, VERR_NOT_FOUND, RT_SRC_POS, + return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS, N_("Implementation of the USB 2.0 controller not found!\n" "Because the USB 2.0 controller state is part of the saved " "VM state, the VM cannot be started. To fix " @@ -2290,142 +2521,134 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) # endif } #endif + } /* for every USB controller. */ - /* - * Virtual USB Devices. - */ - PCFGMNODE pUsbDevices = NULL; - InsertConfigNode(pRoot, "USB", &pUsbDevices); + + /* + * Virtual USB Devices. + */ + PCFGMNODE pUsbDevices = NULL; + InsertConfigNode(pRoot, "USB", &pUsbDevices); #ifdef VBOX_WITH_USB - { - /* - * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing - * on a per device level now. - */ - InsertConfigNode(pUsbDevices, "USBProxy", &pCfg); - InsertConfigNode(pCfg, "GlobalConfig", &pCfg); - // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet. - //InsertConfigInteger(pCfg, "Force11Device", true); - // The following breaks stuff, but it makes MSDs work in vista. (I include it here so - // that it's documented somewhere.) Users needing it can use: - // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1 - //InsertConfigInteger(pCfg, "Force11PacketSize", true); - } + { + /* + * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing + * on a per device level now. + */ + InsertConfigNode(pUsbDevices, "USBProxy", &pCfg); + InsertConfigNode(pCfg, "GlobalConfig", &pCfg); + // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet. + //InsertConfigInteger(pCfg, "Force11Device", true); + // The following breaks stuff, but it makes MSDs work in vista. (I include it here so + // that it's documented somewhere.) Users needing it can use: + // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1 + //InsertConfigInteger(pCfg, "Force11PacketSize", true); + } #endif -#ifdef VBOX_WITH_USB_VIDEO - - InsertConfigNode(pUsbDevices, "Webcam", &pDev); +#ifdef VBOX_WITH_USB_CARDREADER + BOOL aEmulatedUSBCardReaderEnabled = FALSE; + hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H(); + if (aEmulatedUSBCardReaderEnabled) + { + InsertConfigNode(pUsbDevices, "CardReader", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigNode(pInst, "Config", &pCfg); -# if 0 /* Experiments with attaching */ - InsertConfigInteger(pCfg, "USBVER", RT_BIT(2)); -# endif - InsertConfigNode(pInst, "LUN#0", &pLunL0); -# ifdef VBOX_WITH_USB_VIDEO_TEST - InsertConfigString(pLunL0, "Driver", "WebcamFileFeeder"); - InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigString(pCfg, "DirToFeed", "out"); -# else - InsertConfigString(pLunL0, "Driver", "UsbWebcamInterface"); - InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigInteger(pCfg, "Object", mUsbWebcamInterface); -# endif -#endif -#ifdef VBOX_WITH_USB_CARDREADER - BOOL aEmulatedUSBCardReaderEnabled = FALSE; - hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H(); - if (aEmulatedUSBCardReaderEnabled) - { - InsertConfigNode(pUsbDevices, "CardReader", &pDev); - InsertConfigNode(pDev, "0", &pInst); - InsertConfigNode(pInst, "Config", &pCfg); - InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigNode(pInst, "LUN#0", &pLunL0); # ifdef VBOX_WITH_USB_CARDREADER_TEST - InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader"); - InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader"); + InsertConfigNode(pLunL0, "Config", &pCfg); # else - InsertConfigString(pLunL0, "Driver", "UsbCardReader"); - InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader); + InsertConfigString(pLunL0, "Driver", "UsbCardReader"); + InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader); # endif - } + } #endif # if 0 /* Virtual MSD*/ + InsertConfigNode(pUsbDevices, "Msd", &pDev); + InsertConfigNode(pDev, "0", &pInst); + InsertConfigNode(pInst, "Config", &pCfg); + InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigNode(pUsbDevices, "Msd", &pDev); + InsertConfigString(pLunL0, "Driver", "SCSI"); + InsertConfigNode(pLunL0, "Config", &pCfg); + + InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); + InsertConfigString(pLunL1, "Driver", "Block"); + InsertConfigNode(pLunL1, "Config", &pCfg); + InsertConfigString(pCfg, "Type", "HardDisk"); + InsertConfigInteger(pCfg, "Mountable", 0); + + InsertConfigNode(pLunL1, "AttachedDriver", &pLunL2); + InsertConfigString(pLunL2, "Driver", "VD"); + InsertConfigNode(pLunL2, "Config", &pCfg); + InsertConfigString(pCfg, "Path", "/Volumes/DataHFS/bird/VDIs/linux.vdi"); + InsertConfigString(pCfg, "Format", "VDI"); +# endif + + /* Virtual USB Mouse/Tablet */ + if ( aPointingHID == PointingHIDType_USBMouse + || aPointingHID == PointingHIDType_USBTablet + || aPointingHID == PointingHIDType_USBMultiTouch) + { + InsertConfigNode(pUsbDevices, "HidMouse", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigNode(pInst, "Config", &pCfg); - InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigString(pLunL0, "Driver", "SCSI"); + if (aPointingHID == PointingHIDType_USBMouse) + InsertConfigString(pCfg, "Mode", "relative"); + else + InsertConfigString(pCfg, "Mode", "absolute"); + InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigString(pLunL0, "Driver", "MouseQueue"); InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigInteger(pCfg, "QueueSize", 128); InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); - InsertConfigString(pLunL1, "Driver", "Block"); + InsertConfigString(pLunL1, "Driver", "MainMouse"); InsertConfigNode(pLunL1, "Config", &pCfg); - InsertConfigString(pCfg, "Type", "HardDisk"); - InsertConfigInteger(pCfg, "Mountable", 0); - - InsertConfigNode(pLunL1, "AttachedDriver", &pLunL2); - InsertConfigString(pLunL2, "Driver", "VD"); - InsertConfigNode(pLunL2, "Config", &pCfg); - InsertConfigString(pCfg, "Path", "/Volumes/DataHFS/bird/VDIs/linux.vdi"); - InsertConfigString(pCfg, "Format", "VDI"); -# endif - - /* Virtual USB Mouse/Tablet */ - PointingHIDType_T aPointingHID; - hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H(); - if (aPointingHID == PointingHIDType_USBMouse || aPointingHID == PointingHIDType_USBTablet) - { - InsertConfigNode(pUsbDevices, "HidMouse", &pDev); - InsertConfigNode(pDev, "0", &pInst); - InsertConfigNode(pInst, "Config", &pCfg); + InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse); + } + if (aPointingHID == PointingHIDType_USBMultiTouch) + { + InsertConfigNode(pDev, "1", &pInst); + InsertConfigNode(pInst, "Config", &pCfg); - if (aPointingHID == PointingHIDType_USBTablet) - { - InsertConfigInteger(pCfg, "Absolute", 1); - } - else - { - InsertConfigInteger(pCfg, "Absolute", 0); - } - InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigString(pLunL0, "Driver", "MouseQueue"); - InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigInteger(pCfg, "QueueSize", 128); + InsertConfigString(pCfg, "Mode", "multitouch"); + InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigString(pLunL0, "Driver", "MouseQueue"); + InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigInteger(pCfg, "QueueSize", 128); - InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); - InsertConfigString(pLunL1, "Driver", "MainMouse"); - InsertConfigNode(pLunL1, "Config", &pCfg); - pMouse = mMouse; - InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse); - } + InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); + InsertConfigString(pLunL1, "Driver", "MainMouse"); + InsertConfigNode(pLunL1, "Config", &pCfg); + InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse); + } - /* Virtual USB Keyboard */ - KeyboardHIDType_T aKbdHID; - hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H(); - if (aKbdHID == KeyboardHIDType_USBKeyboard) - { - InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev); - InsertConfigNode(pDev, "0", &pInst); - InsertConfigNode(pInst, "Config", &pCfg); + /* Virtual USB Keyboard */ + KeyboardHIDType_T aKbdHID; + hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H(); + if (aKbdHID == KeyboardHIDType_USBKeyboard) + { + InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev); + InsertConfigNode(pDev, "0", &pInst); + InsertConfigNode(pInst, "Config", &pCfg); - InsertConfigNode(pInst, "LUN#0", &pLunL0); - InsertConfigString(pLunL0, "Driver", "KeyboardQueue"); - InsertConfigNode(pLunL0, "Config", &pCfg); - InsertConfigInteger(pCfg, "QueueSize", 64); + InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigString(pLunL0, "Driver", "KeyboardQueue"); + InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigInteger(pCfg, "QueueSize", 64); - InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); - InsertConfigString(pLunL1, "Driver", "MainKeyboard"); - InsertConfigNode(pLunL1, "Config", &pCfg); - pKeyboard = mKeyboard; - InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard); - } + InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1); + InsertConfigString(pLunL1, "Driver", "MainKeyboard"); + InsertConfigNode(pLunL1, "Config", &pCfg); + pKeyboard = mKeyboard; + InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard); } } @@ -2530,7 +2753,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) { BOOL fSupports3D = VBoxOglIs3DAccelerationSupported(); if (!fSupports3D) - return VMSetError(pVM, VERR_NOT_AVAILABLE, RT_SRC_POS, + return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS, N_("This VM was configured to use 3D acceleration. However, the " "3D support of the host is not working properly and the " "VM cannot be started. To fix this problem, either " @@ -2576,7 +2799,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) * Guest property service */ - rc = configGuestProperties(this, pVM); + rc = configGuestProperties(this, pUVM); #endif /* VBOX_WITH_GUEST_PROPS defined */ #ifdef VBOX_WITH_GUEST_CONTROL @@ -2594,22 +2817,22 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H(); if (fACPI) { - BOOL fCpuHotPlug = false; - BOOL fShowCpu = fOsXGuest; /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled. * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the * intelppm driver refuses to register an idle state handler. - */ - if ((cCpus > 1) || fIOAPIC) + * Always show CPU leafs for OS X guests. */ + BOOL fShowCpu = fOsXGuest; + if (cCpus > 1 || fIOAPIC) fShowCpu = true; + BOOL fCpuHotPlug; hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H(); InsertConfigNode(pDevices, "acpi", &pDev); InsertConfigNode(pDev, "0", &pInst); InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ InsertConfigNode(pInst, "Config", &pCfg); - hrc = BusMgr->assignPCIDevice("acpi", pInst); H(); + hrc = pBusMgr->assignPCIDevice("acpi", pInst); H(); InsertConfigInteger(pCfg, "RamSize", cbRam); InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole); @@ -2629,7 +2852,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) if (fOsXGuest && fAudioEnabled) { PCIBusAddress Address; - if (BusMgr->findPCIAddress("hda", 0, Address)) + if (pBusMgr->findPCIAddress("hda", 0, Address)) { uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn; InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr); @@ -2720,6 +2943,10 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) // InsertConfig threw something: return x.m_vrc; } + catch (HRESULT hrcXcpt) + { + AssertMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_GENERAL_FAILURE); + } #ifdef VBOX_WITH_EXTPACK /* @@ -2737,7 +2964,13 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) * Apply the CFGM overlay. */ if (RT_SUCCESS(rc)) - rc = configCfgmOverlay(pVM, virtualBox, pMachine); + rc = configCfgmOverlay(pRoot, virtualBox, pMachine); + + /* + * Dump all extradata API settings tweaks, both global and per VM. + */ + if (RT_SUCCESS(rc)) + rc = configDumpAPISettingsTweaks(virtualBox, pMachine); #undef H @@ -2746,7 +2979,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) /* * Register VM state change handler. */ - int rc2 = VMR3AtStateRegister(pVM, Console::vmstateChangeCallback, this); + int rc2 = VMR3AtStateRegister(pUVM, Console::vmstateChangeCallback, this); AssertRC(rc2); if (RT_SUCCESS(rc)) rc = rc2; @@ -2754,7 +2987,7 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) /* * Register VM runtime error handler. */ - rc2 = VMR3AtRuntimeErrorRegister(pVM, Console::setVMRuntimeErrorCallback, this); + rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::setVMRuntimeErrorCallback, this); AssertRC(rc2); if (RT_SUCCESS(rc)) rc = rc2; @@ -2768,16 +3001,16 @@ int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock) } /** - * Applies the CFGM overlay as specified by /VBoxInternal/XXX extra data + * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data * values. * * @returns VBox status code. - * @param pVM The VM handle. + * @param pRoot The root of the configuration tree. * @param pVirtualBox Pointer to the IVirtualBox interface. * @param pMachine Pointer to the IMachine interface. */ /* static */ -int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMachine) +int Console::configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine) { /* * CFGM overlay handling. @@ -2792,8 +3025,7 @@ int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMac * We first perform a run on global extra data, then on the machine * extra data to support global settings with local overrides. */ - PCFGMNODE pRoot = CFGMR3GetRoot(pVM); - int rc = VINF_SUCCESS; + int rc = VINF_SUCCESS; try { /** @todo add support for removing nodes and byte blobs. */ @@ -2809,7 +3041,7 @@ int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMac size_t cGlobalValues = aGlobalExtraDataKeys.size(); hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys)); - AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc)); + AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc)); // build a combined list from global keys... std::list llExtraDataKeys; @@ -2845,7 +3077,7 @@ int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMac hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam()); if (FAILED(hrc)) - LogRel(("Warning: Cannot get extra data key %s, rc = %Rrc\n", strKey.c_str(), hrc)); + LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc)); /* * The key will be in the format "Node1/Node2/Value" or simply "Value". @@ -2897,16 +3129,36 @@ int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMac uint64_t u64Value; /* check for type prefix first. */ - if (!strncmp(strCFGMValueUtf8.c_str(), "string:", sizeof("string:") - 1)) + if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:"))) InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1); - else if (!strncmp(strCFGMValueUtf8.c_str(), "integer:", sizeof("integer:") - 1)) + else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:"))) { rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value); if (RT_SUCCESS(rc)) rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value); } - else if (!strncmp(strCFGMValueUtf8.c_str(), "bytes:", sizeof("bytes:") - 1)) - rc = VERR_NOT_IMPLEMENTED; + else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:"))) + { + char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1; + ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL); + if (cbValue > 0) + { + void *pvBytes = RTMemTmpAlloc(cbValue); + if (pvBytes) + { + rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL); + if (RT_SUCCESS(rc)) + rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue); + RTMemTmpFree(pvBytes); + } + else + rc = VERR_NO_TMP_MEMORY; + } + else if (cbValue == 0) + rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0); + else + rc = VERR_INVALID_BASE64_ENCODING; + } /* auto detect type. */ else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value))) rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value); @@ -2924,15 +3176,206 @@ int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMac return rc; } +/** + * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data + * values. + * + * @returns VBox status code. + * @param pVirtualBox Pointer to the IVirtualBox interface. + * @param pMachine Pointer to the IMachine interface. + */ +/* static */ +int Console::configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine) +{ + { + SafeArray aGlobalExtraDataKeys; + HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys)); + AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc)); + bool hasKey = false; + for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++) + { + Utf8Str strKey(aGlobalExtraDataKeys[i]); + if (!strKey.startsWith("VBoxInternal2/")) + continue; + + Bstr bstrValue; + hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), + bstrValue.asOutParam()); + if (FAILED(hrc)) + continue; + if (!hasKey) + LogRel(("Global extradata API settings:\n")); + LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw())); + hasKey = true; + } + } + + { + SafeArray aMachineExtraDataKeys; + HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys)); + AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc)); + bool hasKey = false; + for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++) + { + Utf8Str strKey(aMachineExtraDataKeys[i]); + if (!strKey.startsWith("VBoxInternal2/")) + continue; + + Bstr bstrValue; + hrc = pMachine->GetExtraData(Bstr(strKey).raw(), + bstrValue.asOutParam()); + if (FAILED(hrc)) + continue; + if (!hasKey) + LogRel(("Per-VM extradata API settings:\n")); + LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw())); + hasKey = true; + } + } + + return VINF_SUCCESS; +} + +int Console::configGraphicsController(PCFGMNODE pDevices, + const GraphicsControllerType_T graphicsController, + BusAssignmentManager *pBusMgr, + const ComPtr &pMachine, + const ComPtr &biosSettings, + bool fHMEnabled) +{ + // InsertConfig* throws + try + { + PCFGMNODE pDev, pInst, pCfg, pLunL0; + HRESULT hrc; + Bstr bstr; + const char *pcszDevice = "vga"; + +#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE) + InsertConfigNode(pDevices, pcszDevice, &pDev); + InsertConfigNode(pDev, "0", &pInst); + InsertConfigInteger(pInst, "Trusted", 1); /* boolean */ + + hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H(); + InsertConfigNode(pInst, "Config", &pCfg); + ULONG cVRamMBs; + hrc = pMachine->COMGETTER(VRAMSize)(&cVRamMBs); H(); + InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M); + ULONG cMonitorCount; + hrc = pMachine->COMGETTER(MonitorCount)(&cMonitorCount); H(); + InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount); +#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE + InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled); +#else + NOREF(fHMEnabled); +#endif + +#ifdef VBOX_WITH_VMSVGA + if (graphicsController == GraphicsControllerType_VMSVGA) + { + InsertConfigInteger(pCfg, "VMSVGAEnabled", true); +#ifdef VBOX_WITH_VMSVGA3D + IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer(); + if (pFramebuffer) + { + LONG64 winId = 0; + /* @todo deal with multimonitor setup */ + Assert(cMonitorCount == 1); + hrc = pFramebuffer->COMGETTER(WinId)(&winId); + InsertConfigInteger(pCfg, "HostWindowId", winId); + } + BOOL f3DEnabled; + pMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); + InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled); +#endif + } +#endif + + /* Custom VESA mode list */ + unsigned cModes = 0; + for (unsigned iMode = 1; iMode <= 16; ++iMode) + { + char szExtraDataKey[sizeof("CustomVideoModeXX")]; + RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode); + hrc = pMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H(); + if (bstr.isEmpty()) + break; + InsertConfigString(pCfg, szExtraDataKey, bstr); + ++cModes; + } + InsertConfigInteger(pCfg, "CustomVideoModes", cModes); + + /* VESA height reduction */ + ULONG ulHeightReduction; + IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer(); + if (pFramebuffer) + { + hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H(); + } + else + { + /* If framebuffer is not available, there is no height reduction. */ + ulHeightReduction = 0; + } + InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction); + + /* + * BIOS logo + */ + BOOL fFadeIn; + hrc = biosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H(); + InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0); + BOOL fFadeOut; + hrc = biosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H(); + InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0); + ULONG logoDisplayTime; + hrc = biosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H(); + InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime); + Bstr logoImagePath; + hrc = biosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H(); + InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") ); + + /* + * Boot menu + */ + BIOSBootMenuMode_T eBootMenuMode; + int iShowBootMenu; + biosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); + switch (eBootMenuMode) + { + case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break; + case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break; + default: iShowBootMenu = 2; break; + } + InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu); + + /* Attach the display. */ + InsertConfigNode(pInst, "LUN#0", &pLunL0); + InsertConfigString(pLunL0, "Driver", "MainDisplay"); + InsertConfigNode(pLunL0, "Config", &pCfg); + Display *pDisplay = mDisplay; + InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay); + } + catch (ConfigError &x) + { + // InsertConfig threw something: + return x.m_vrc; + } + +#undef H + + return VINF_SUCCESS; +} + + /** * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback. */ -/*static*/ -void Console::setVMRuntimeErrorCallbackF(PVM pVM, void *pvConsole, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...) +void Console::setVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); - setVMRuntimeErrorCallback(pVM, pvConsole, fFlags, pszErrorId, pszFormat, va); + setVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va); va_end(va); } @@ -2971,8 +3414,9 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, bool fAttachDetach, bool fForceUnmount, bool fHotplug, - PVM pVM, - DeviceType_T *paLedDevType) + PUVM pUVM, + DeviceType_T *paLedDevType, + PCFGMNODE *ppLunL0) { // InsertConfig* throws try @@ -3009,7 +3453,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, { /* Unmount existing media only for floppy and DVD drives. */ PPDMIBASE pBase; - rc = PDMR3QueryLun(pVM, pcszDevice, uInstance, uLUN, &pBase); + rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase); if (RT_FAILURE(rc)) { if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN) @@ -3031,7 +3475,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, } } - rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG); + rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG); if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN) rc = VINF_SUCCESS; AssertRCReturn(rc, rc); @@ -3043,6 +3487,8 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, } InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0); + if (ppLunL0) + *ppLunL0 = pLunL0; PCFGMNODE pCfg = CFGMR3GetChild(pCtlInst, "Config"); if (pCfg) @@ -3101,8 +3547,13 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, */ ComPtr pMediumFormat; hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H(); - ULONG uCaps; - hrc = pMediumFormat->COMGETTER(Capabilities)(&uCaps); H(); + ULONG uCaps = 0; + com::SafeArray mediumFormatCap; + hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H(); + + for (ULONG j = 0; j < mediumFormatCap.size(); j++) + uCaps |= mediumFormatCap[j]; + if (uCaps & MediumFormatCapabilities_File) { Bstr strFile; @@ -3135,8 +3586,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, { const char *pszUnit; uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit); - setVMRuntimeErrorCallbackF(pVM, this, 0, - "FatPartitionDetected", + setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", N_("The medium '%ls' has a logical size of %RU64%s " "but the file system the medium is located on seems " "to be FAT(32) which cannot handle files bigger than 4GB.\n" @@ -3167,8 +3617,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, const char *pszUnitMax; uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz); uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax); - setVMRuntimeErrorCallbackF(pVM, this, 0, - "FatPartitionDetected", /* <= not exact but ... */ + setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */ N_("The medium '%ls' has a logical size of %RU64%s " "but the file system the medium is located on can " "only handle files up to %RU64%s in theory.\n" @@ -3191,8 +3640,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, { const char *pszUnit; uint64_t u64Print = formatDiskSize(i64Size, &pszUnit); - setVMRuntimeErrorCallbackF(pVM, this, 0, - "FatPartitionDetected", + setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", #ifdef RT_OS_WINDOWS N_("The snapshot folder of this VM '%ls' seems to be located on " "a FAT(32) file system. The logical size of the medium '%ls' " @@ -3233,8 +3681,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, if ( enmFsTypeFile == RTFSTYPE_EXT4 || enmFsTypeFile == RTFSTYPE_XFS) { - setVMRuntimeErrorCallbackF(pVM, this, 0, - "Ext4PartitionDetected", + setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected", N_("The host I/O cache for at least one controller is disabled " "and the medium '%ls' for this VM " "is located on an %s partition. There is a known Linux " @@ -3251,8 +3698,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, || enmFsTypeSnap == RTFSTYPE_XFS) && !mfSnapshotFolderExt4WarningShown) { - setVMRuntimeErrorCallbackF(pVM, this, 0, - "Ext4PartitionDetected", + setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected", N_("The host I/O cache for at least one controller is disabled " "and the snapshot folder for this VM " "is located on an %s partition. There is a known Linux " @@ -3271,19 +3717,17 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, } } - if ( pMedium - && ( lType == DeviceType_DVD - || lType == DeviceType_Floppy)) + if (pMedium) { - /* - * Informative logging. - */ - ComPtr pMediumFormat; - hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H(); - ULONG uCaps; - hrc = pMediumFormat->COMGETTER(Capabilities)(&uCaps); H(); - if (uCaps & MediumFormatCapabilities_File) + BOOL fHostDrive; + hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H(); + if ( ( lType == DeviceType_DVD + || lType == DeviceType_Floppy) + && !fHostDrive) { + /* + * Informative logging. + */ Bstr strFile; hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H(); Utf8Str utfFile = Utf8Str(strFile); @@ -3326,8 +3770,8 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, if (fAttachDetach) { /* Attach the new driver. */ - rc = PDMR3DeviceAttach(pVM, pcszDevice, uInstance, uLUN, - fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/); + rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN, + fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/); AssertRCReturn(rc, rc); /* There is no need to handle removable medium mounting, as we @@ -3346,7 +3790,7 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, #undef H - return VINF_SUCCESS;; + return VINF_SUCCESS; } int Console::configMedium(PCFGMNODE pLunL0, @@ -3443,10 +3887,7 @@ int Console::configMedium(PCFGMNODE pLunL0, { Bstr loc; hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H(); - setVMRuntimeErrorCallbackF(VMR3GetVM(mpUVM), - this, - 0, - "DvdOrFloppyImageInaccessible", + setVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible", "The image file '%ls' is inaccessible and is being ignored. Please select a different image file for the virtual %s drive.", loc.raw(), enmType == DeviceType_DVD ? "DVD" : "floppy"); @@ -3700,8 +4141,6 @@ int Console::configNetwork(const char *pszDevice, */ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - PVM pVM = VMR3GetVM(mpUVM); /* We're on an EMT, so this is safe. */ - ComPtr pMachine = machine(); ComPtr virtualBox; @@ -3726,7 +4165,7 @@ int Console::configNetwork(const char *pszDevice, if (fAttachDetach) { - rc = PDMR3DeviceDetach(pVM, pszDevice, uInstance, uLun, 0 /*fFlags*/); + rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/); if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN) rc = VINF_SUCCESS; AssertLogRelRCReturn(rc, rc); @@ -3903,6 +4342,10 @@ int Console::configNetwork(const char *pszDevice, if (!fValid) continue; + if (strName.isEmpty()) + VMSetError(VMR3GetVM(mpUVM), VERR_CFGM_NO_NODE, RT_SRC_POS, + N_("NAT redirection rule without a name")); + InsertConfigNode(pCfg, strName.c_str(), &pPF); InsertConfigString(pPF, "Protocol", strProto); @@ -3932,7 +4375,7 @@ int Console::configNetwork(const char *pszDevice, switch (hrc) { case VERR_ACCESS_DENIED: - return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( + return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( "Failed to open '/dev/net/tun' for read/write access. Please check the " "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or " "change the group of that node and make yourself a member of that group. Make " @@ -3940,7 +4383,7 @@ int Console::configNetwork(const char *pszDevice, "using udev")); default: AssertMsgFailed(("Could not attach to host interface! Bad!\n")); - return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( + return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( "Failed to initialize Host Interface Networking")); } } @@ -3961,7 +4404,7 @@ int Console::configNetwork(const char *pszDevice, hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam()); if (FAILED(hrc)) { - LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)", hrc)); + LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc)); H(); } @@ -3983,7 +4426,7 @@ int Console::configNetwork(const char *pszDevice, // * See @bugref{4750}. // * hrc = aNetworkAdapter->Detach(); H(); // */ -// return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS, +// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, // N_("Malformed host interface networking name '%ls'"), // BridgedIfName.raw()); // } @@ -4019,7 +4462,7 @@ int Console::configNetwork(const char *pszDevice, if (!SUCCEEDED(hrc)) { AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc)); - return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS, + return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, N_("Nonexistent host networking interface, name '%ls'"), BridgedIfName.raw()); } @@ -4028,13 +4471,13 @@ int Console::configNetwork(const char *pszDevice, hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType); if (FAILED(hrc)) { - LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)", hrc)); + LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc)); H(); } if (eIfType != HostNetworkInterfaceType_Bridged) { - return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS, + return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, N_("Interface ('%ls') is not a Bridged Adapter interface"), BridgedIfName.raw()); } @@ -4042,7 +4485,7 @@ int Console::configNetwork(const char *pszDevice, hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam()); if (FAILED(hrc)) { - LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)", hrc)); + LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc)); H(); } Guid hostIFGuid(bstr); @@ -4064,7 +4507,7 @@ int Console::configNetwork(const char *pszDevice, if (hrc != S_OK) { VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/); - LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)", hrc)); + LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc)); H(); } #define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\" @@ -4124,14 +4567,14 @@ int Console::configNetwork(const char *pszDevice, * This works and performs better than bridging a physical * interface via the current FreeBSD vboxnetflt implementation. */ - if (!strncmp(pszBridgedIfName, "tap", sizeof "tap" - 1)) { + if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) { hrc = attachToTapInterface(aNetworkAdapter); if (FAILED(hrc)) { switch (hrc) { case VERR_ACCESS_DENIED: - return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( + return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( "Failed to open '/dev/%s' for read/write access. Please check the " "permissions of that node, and that the net.link.tap.user_open " "sysctl is set. Either run 'chmod 0666 /dev/%s' or " @@ -4139,7 +4582,7 @@ int Console::configNetwork(const char *pszDevice, "a member of that group. Make sure that these changes are permanent."), pszBridgedIfName, pszBridgedIfName); default: AssertMsgFailed(("Could not attach to tap interface! Bad!\n")); - return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( + return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_( "Failed to initialize Host Interface Networking")); } } @@ -4164,12 +4607,12 @@ int Console::configNetwork(const char *pszDevice, { struct ifreq Req; RT_ZERO(Req); - strncpy(Req.ifr_name, pszBridgedIfName, sizeof(Req.ifr_name) - 1); + RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName); if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0) if ((Req.ifr_flags & IFF_UP) == 0) - setVMRuntimeErrorCallbackF(pVM, this, 0, "BridgedInterfaceDown", - "Bridged interface %s is down. Guest will not be able to use this interface", - pszBridgedIfName); + setVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown", + N_("Bridged interface %s is down. Guest will not be able to use this interface"), + pszBridgedIfName); close(iSock); } @@ -4213,7 +4656,7 @@ int Console::configNetwork(const char *pszDevice, { struct iwreq WRq; - memset(&WRq, 0, sizeof(WRq)); + RT_ZERO(WRq); strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ); bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0; close(iSock); @@ -4234,7 +4677,7 @@ int Console::configNetwork(const char *pszDevice, struct ieee80211req WReq; uint8_t abData[32]; - memset(&WReq, 0, sizeof(WReq)); + RT_ZERO(WReq); strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name)); WReq.i_type = IEEE80211_IOC_SSID; WReq.i_val = -1; @@ -4390,7 +4833,7 @@ int Console::configNetwork(const char *pszDevice, if (!SUCCEEDED(rc)) { LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc)); - return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS, + return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, N_("Nonexistent host networking interface, name '%ls'"), HostOnlyName.raw()); } @@ -4415,7 +4858,7 @@ int Console::configNetwork(const char *pszDevice, } if (eIfType != HostNetworkInterfaceType_HostOnly) - return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS, + return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, N_("Interface ('%ls') is not a Host-Only Adapter interface"), HostOnlyName.raw()); @@ -4591,6 +5034,23 @@ int Console::configNetwork(const char *pszDevice, break; } + case NetworkAttachmentType_NATNetwork: + { + hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H(); + if (!bstr.isEmpty()) + { + /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */ + InsertConfigString(pLunL0, "Driver", "IntNet"); + InsertConfigNode(pLunL0, "Config", &pCfg); + InsertConfigString(pCfg, "Network", bstr); + InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone); + InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy); + networkName = bstr; + trunkType = Bstr(TRUNKTYPE_WHATEVER); + } + break; + } + default: AssertMsgFailed(("should not get here!\n")); break; @@ -4609,12 +5069,13 @@ int Console::configNetwork(const char *pszDevice, case NetworkAttachmentType_HostOnly: case NetworkAttachmentType_NAT: case NetworkAttachmentType_Generic: + case NetworkAttachmentType_NATNetwork: { if (SUCCEEDED(hrc) && SUCCEEDED(rc)) { if (fAttachDetach) { - rc = PDMR3DriverAttach(pVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */); + rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */); //AssertRC(rc); } @@ -4627,7 +5088,11 @@ int Console::configNetwork(const char *pszDevice, /* Stop the hostonly DHCP Server */ } - if (!networkName.isEmpty()) + /* + * NAT networks start their DHCP server theirself, see NATNetwork::Start() + */ + if ( !networkName.isEmpty() + && eAttachmentType != NetworkAttachmentType_NATNetwork) { /* * Until we implement service reference counters DHCP Server will be stopped @@ -4643,7 +5108,7 @@ int Console::configNetwork(const char *pszDevice, hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp); if (FAILED(hrc)) { - LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)", hrc)); + LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc)); H(); } @@ -4724,13 +5189,13 @@ static void configSetProperty(VMMDev * const pVMMDev, AssertPtrReturnVoid(pszFlags); parms[0].type = VBOX_HGCM_SVC_PARM_PTR; parms[0].u.pointer.addr = (void *)pszName; - parms[0].u.pointer.size = strlen(pszName) + 1; + parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1; parms[1].type = VBOX_HGCM_SVC_PARM_PTR; parms[1].u.pointer.addr = (void *)pszValue; - parms[1].u.pointer.size = strlen(pszValue) + 1; + parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1; parms[2].type = VBOX_HGCM_SVC_PARM_PTR; parms[2].u.pointer.addr = (void *)pszFlags; - parms[2].u.pointer.size = strlen(pszFlags) + 1; + parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1; pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3, &parms[0]); } @@ -4766,7 +5231,7 @@ int configSetGlobalPropertyFlags(VMMDev * const pVMMDev, * Set up the Guest Property service, populate it with properties read from * the machine XML and set a couple of initial properties. */ -/* static */ int Console::configGuestProperties(void *pvConsole, PVM pVM) +/* static */ int Console::configGuestProperties(void *pvConsole, PUVM pUVM) { #ifdef VBOX_WITH_GUEST_PROPS AssertReturn(pvConsole, VERR_GENERAL_FAILURE); @@ -4798,7 +5263,7 @@ int configSetGlobalPropertyFlags(VMMDev * const pVMMDev, { PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr; void *pService = (void*)Params[1].u.pointer.addr; - DBGFR3InfoRegisterExternal(pVM, "guestprops", "Display the guest properties", pfnHandler, pService); + DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService); } } @@ -4822,7 +5287,7 @@ int configSetGlobalPropertyFlags(VMMDev * const pVMMDev, ComSafeArrayAsOutParam(valuesOut), ComSafeArrayAsOutParam(timestampsOut), ComSafeArrayAsOutParam(flagsOut)); - AssertMsgReturn(SUCCEEDED(hrc), ("hrc=%Rrc\n", hrc), VERR_GENERAL_FAILURE); + AssertMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE); size_t cProps = namesOut.size(); size_t cAlloc = cProps + 1; if ( valuesOut.size() != cProps diff --git a/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp b/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp index 7e765352..e5666f3f 100644 --- a/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp +++ b/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -239,7 +239,7 @@ Console::teleporterSrcReadACK(TeleporterStateSrc *pState, const char *pszWhich, if (!strcmp(szMsg, "ACK")) return S_OK; - if (!strncmp(szMsg, "NACK=", sizeof("NACK=") - 1)) + if (!strncmp(szMsg, RT_STR_TUPLE("NACK="))) { char *pszMsgText = strchr(szMsg, ';'); if (pszMsgText) @@ -573,7 +573,7 @@ static SSMSTRMOPS const g_teleporterTcpOps = static void teleporterProgressCancelCallback(void *pvUser) { TeleporterState *pState = (TeleporterState *)pvUser; - SSMR3Cancel(VMR3GetVM(pState->mpUVM)); + SSMR3Cancel(pState->mpUVM); if (!pState->mfIsSource) { TeleporterStateTrg *pStateTrg = (TeleporterStateTrg *)pState; @@ -584,7 +584,7 @@ static void teleporterProgressCancelCallback(void *pvUser) /** * @copydoc PFNVMPROGRESS */ -static DECLCALLBACK(int) teleporterProgressCallback(PVM pVM, unsigned uPercent, void *pvUser) +static DECLCALLBACK(int) teleporterProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser) { TeleporterState *pState = (TeleporterState *)pvUser; if (pState->mptrProgress) @@ -597,12 +597,13 @@ static DECLCALLBACK(int) teleporterProgressCallback(PVM pVM, unsigned uPercent, hrc = pState->mptrProgress->COMGETTER(Canceled)(&fCanceled); if (SUCCEEDED(hrc) && fCanceled) { - SSMR3Cancel(VMR3GetVM(pState->mpUVM)); + SSMR3Cancel(pState->mpUVM); return VERR_SSM_CANCELLED; } } } + NOREF(pUVM); return VINF_SUCCESS; } @@ -685,7 +686,7 @@ Console::teleporterSrc(TeleporterStateSrc *pState) RTSocketRetain(pState->mhSocket); void *pvUser = static_cast(static_cast(pState)); - vrc = VMR3Teleport(VMR3GetVM(pState->mpUVM), + vrc = VMR3Teleport(pState->mpUVM, pState->mcMsMaxDowntime, &g_teleporterTcpOps, pvUser, teleporterProgressCallback, pvUser, @@ -810,7 +811,11 @@ Console::teleporterSrcThreadWrapper(RTTHREAD hThread, void *pvUser) ptrVM.release(); pState->mptrConsole->mVMIsAlreadyPoweringOff = true; /* (Make sure we stick in the TeleportingPausedVM state.) */ + autoLock.release(); + hrc = pState->mptrConsole->powerDown(); + + autoLock.acquire(); pState->mptrConsole->mVMIsAlreadyPoweringOff = false; pState->mptrProgress->notifyComplete(hrc); @@ -886,7 +891,7 @@ Console::teleporterSrcThreadWrapper(RTTHREAD hThread, void *pvUser) if (pState->mfSuspendedByUs) { autoLock.release(); - int rc = VMR3Resume(VMR3GetVM(pState->mpUVM)); + int rc = VMR3Resume(pState->mpUVM, VMRESUMEREASON_TELEPORT_FAILED); AssertLogRelMsgRC(rc, ("VMR3Resume -> %Rrc\n", rc)); autoLock.acquire(); } @@ -932,7 +937,7 @@ Console::Teleport(IN_BSTR aHostname, ULONG aPort, IN_BSTR aPassword, ULONG aMaxD */ CheckComArgOutPointerValid(aProgress); CheckComArgStrNotEmptyOrNull(aHostname); - CheckComArgStrNotEmptyOrNull(aPassword); + CheckComArgNotNull(aPassword); CheckComArgExprMsg(aPort, aPort > 0 && aPort <= 65535, ("is %u", aPort)); CheckComArgExprMsg(aMaxDowntime, aMaxDowntime > 0, ("is %u", aMaxDowntime)); @@ -1337,18 +1342,18 @@ Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser) if (RT_FAILURE(vrc)) break; - int vrc2 = VMR3AtErrorRegisterU(pState->mpUVM, - Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); + int vrc2 = VMR3AtErrorRegister(pState->mpUVM, + Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); RTSocketRetain(pState->mhSocket); /* For concurrent access by I/O thread and EMT. */ pState->moffStream = 0; void *pvUser2 = static_cast(static_cast(pState)); - vrc = VMR3LoadFromStream(VMR3GetVM(pState->mpUVM), + vrc = VMR3LoadFromStream(pState->mpUVM, &g_teleporterTcpOps, pvUser2, teleporterProgressCallback, pvUser2); RTSocketRelease(pState->mhSocket); - vrc2 = VMR3AtErrorDeregister(VMR3GetVM(pState->mpUVM), Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); + vrc2 = VMR3AtErrorDeregister(pState->mpUVM, Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); if (RT_FAILURE(vrc)) { @@ -1411,7 +1416,7 @@ Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser) if (RT_SUCCESS(vrc)) { if (!strcmp(szCmd, "hand-over-resume")) - vrc = VMR3Resume(VMR3GetVM(pState->mpUVM)); + vrc = VMR3Resume(pState->mpUVM, VMRESUMEREASON_TELEPORTED); else pState->mptrConsole->setMachineState(MachineState_Paused); fDone = true; diff --git a/src/VBox/Main/src-client/ConsoleVRDPServer.cpp b/src/VBox/Main/src-client/ConsoleVRDPServer.cpp index f907b189..4247f2fb 100644 --- a/src/VBox/Main/src-client/ConsoleVRDPServer.cpp +++ b/src/VBox/Main/src-client/ConsoleVRDPServer.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -28,6 +28,7 @@ #ifdef VBOX_WITH_USB_CARDREADER # include "UsbCardReader.h" #endif +#include "UsbWebcamInterface.h" #include "Global.h" #include "AutoCaller.h" @@ -666,7 +667,6 @@ DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback *pcbOut = (uint32_t)cbPortRange; } break; -#ifdef VBOX_WITH_VRDP_VIDEO_CHANNEL case VRDE_QP_VIDEO_CHANNEL: { com::Bstr bstr; @@ -750,7 +750,6 @@ DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback *pcbOut = sizeof(uint32_t); } break; -#endif /* VBOX_WITH_VRDP_VIDEO_CHANNEL */ case VRDE_QP_FEATURE: { @@ -924,6 +923,16 @@ DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect(void *pvCallback ConsoleVRDPServer *server = static_cast(pvCallback); server->mConsole->VRDPClientConnect(u32ClientId); + + /* Should the server report usage of an interface for each client? + * Similar to Intercept. + */ + int c = ASMAtomicIncS32(&server->mcClients); + if (c == 1) + { + /* Features which should be enabled only if there is a client. */ + server->remote3DRedirect(true); + } } DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted) @@ -947,6 +956,13 @@ DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect(void *pvCallb AssertFailed(); } } + + int c = ASMAtomicDecS32(&server->mcClients); + if (c == 0) + { + /* Features which should be enabled only if there is a client. */ + server->remote3DRedirect(false); + } } DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept) @@ -1332,6 +1348,8 @@ ConsoleVRDPServer::ConsoleVRDPServer(Console *console) mhServer = 0; mServerInterfaceVersion = 0; + mcInResize = 0; + m_fGuestWantsAbsolute = false; m_mousex = 0; m_mousey = 0; @@ -1347,7 +1365,7 @@ ConsoleVRDPServer::ConsoleVRDPServer(Console *console) m_InputSynch.fClientCapsLock = false; m_InputSynch.fClientScrollLock = false; - memset(maFramebuffers, 0, sizeof(maFramebuffers)); + RT_ZERO(maFramebuffers); { ComPtr es; @@ -1368,18 +1386,29 @@ ConsoleVRDPServer::ConsoleVRDPServer(Console *console) mAuthLibrary = 0; mu32AudioInputClientId = 0; + mcClients = 0; /* * Optional interfaces. */ m_fInterfaceImage = false; - memset(&m_interfaceImage, 0, sizeof (m_interfaceImage)); - memset(&m_interfaceCallbacksImage, 0, sizeof (m_interfaceCallbacksImage)); + RT_ZERO(m_interfaceImage); + RT_ZERO(m_interfaceCallbacksImage); RT_ZERO(m_interfaceMousePtr); RT_ZERO(m_interfaceSCard); RT_ZERO(m_interfaceCallbacksSCard); RT_ZERO(m_interfaceTSMF); RT_ZERO(m_interfaceCallbacksTSMF); + RT_ZERO(m_interfaceVideoIn); + RT_ZERO(m_interfaceCallbacksVideoIn); + RT_ZERO(m_interfaceInput); + RT_ZERO(m_interfaceCallbacksInput); + + rc = RTCritSectInit(&mTSMFLock); + AssertRC(rc); + + mEmWebcam = new EmWebcam(this); + AssertPtr(mEmWebcam); } ConsoleVRDPServer::~ConsoleVRDPServer() @@ -1404,10 +1433,22 @@ ConsoleVRDPServer::~ConsoleVRDPServer() } } + if (mEmWebcam) + { + delete mEmWebcam; + mEmWebcam = NULL; + } + if (RTCritSectIsInitialized(&mCritSect)) { RTCritSectDelete(&mCritSect); - memset(&mCritSect, 0, sizeof(mCritSect)); + RT_ZERO(mCritSect); + } + + if (RTCritSectIsInitialized(&mTSMFLock)) + { + RTCritSectDelete(&mTSMFLock); + RT_ZERO(mTSMFLock); } } @@ -1654,6 +1695,54 @@ int ConsoleVRDPServer::Launch(void) RT_ZERO(m_interfaceTSMF); } + /* VideoIn interface. */ + m_interfaceVideoIn.header.u64Version = 1; + m_interfaceVideoIn.header.u64Size = sizeof(m_interfaceVideoIn); + + m_interfaceCallbacksVideoIn.header.u64Version = 1; + m_interfaceCallbacksVideoIn.header.u64Size = sizeof(m_interfaceCallbacksVideoIn); + m_interfaceCallbacksVideoIn.VRDECallbackVideoInNotify = VRDECallbackVideoInNotify; + m_interfaceCallbacksVideoIn.VRDECallbackVideoInDeviceDesc = VRDECallbackVideoInDeviceDesc; + m_interfaceCallbacksVideoIn.VRDECallbackVideoInControl = VRDECallbackVideoInControl; + m_interfaceCallbacksVideoIn.VRDECallbackVideoInFrame = VRDECallbackVideoInFrame; + + vrc = mpEntryPoints->VRDEGetInterface(mhServer, + VRDE_VIDEOIN_INTERFACE_NAME, + &m_interfaceVideoIn.header, + &m_interfaceCallbacksVideoIn.header, + this); + if (RT_SUCCESS(vrc)) + { + LogRel(("VRDE: [%s]\n", VRDE_VIDEOIN_INTERFACE_NAME)); + } + else + { + RT_ZERO(m_interfaceVideoIn); + } + + /* Input interface. */ + m_interfaceInput.header.u64Version = 1; + m_interfaceInput.header.u64Size = sizeof(m_interfaceInput); + + m_interfaceCallbacksInput.header.u64Version = 1; + m_interfaceCallbacksInput.header.u64Size = sizeof(m_interfaceCallbacksInput); + m_interfaceCallbacksInput.VRDECallbackInputSetup = VRDECallbackInputSetup; + m_interfaceCallbacksInput.VRDECallbackInputEvent = VRDECallbackInputEvent; + + vrc = mpEntryPoints->VRDEGetInterface(mhServer, + VRDE_INPUT_INTERFACE_NAME, + &m_interfaceInput.header, + &m_interfaceCallbacksInput.header, + this); + if (RT_SUCCESS(vrc)) + { + LogRel(("VRDE: [%s]\n", VRDE_INPUT_INTERFACE_NAME)); + } + else + { + RT_ZERO(m_interfaceInput); + } + /* Since these interfaces are optional, it is always a success here. */ vrc = VINF_SUCCESS; } @@ -1683,14 +1772,17 @@ typedef struct H3DORInstance uint32_t w; uint32_t h; bool fCreated; + bool fFallback; } H3DORInstance; +#define H3DORLOG Log + /* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORBegin(const void *pvContext, void **ppvInstance, const char *pszFormat) { - LogFlowFunc(("ctx %p\n", pvContext)); + H3DORLOG(("H3DORBegin: ctx %p [%s]\n", pvContext, pszFormat)); - H3DORInstance *p = (H3DORInstance *)RTMemAlloc(sizeof (H3DORInstance)); + H3DORInstance *p = (H3DORInstance *)RTMemAlloc(sizeof(H3DORInstance)); if (p) { @@ -1701,6 +1793,7 @@ typedef struct H3DORInstance p->w = 0; p->h = 0; p->fCreated = false; + p->fFallback = false; /* Host 3D service passes the actual format of data in this redirect instance. * That is what will be in the H3DORFrame's parameters pvData and cbData. @@ -1716,14 +1809,16 @@ typedef struct H3DORInstance } } - /* Caller check this for NULL. */ + H3DORLOG(("H3DORBegin: ins %p\n", p)); + + /* Caller checks this for NULL. */ *ppvInstance = p; } /* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORGeometry(void *pvInstance, int32_t x, int32_t y, uint32_t w, uint32_t h) { - LogFlowFunc(("ins %p %d,%d %dx%d\n", pvInstance, x, y, w, h)); + H3DORLOG(("H3DORGeometry: ins %p %d,%d %dx%d\n", pvInstance, x, y, w, h)); H3DORInstance *p = (H3DORInstance *)pvInstance; Assert(p); @@ -1752,12 +1847,14 @@ typedef struct H3DORInstance && p->w == w && p->h == h) { - LogFlowFunc(("geometry not changed\n")); + H3DORLOG(("H3DORGeometry: geometry not changed\n")); /* Do nothing. Continue using the existing handle. */ } else { - int rc = p->pThis->m_interfaceImage.VRDEImageGeometrySet(p->hImageBitmap, &rect); + int rc = p->fFallback? + VERR_NOT_SUPPORTED: /* Try to go out of fallback mode. */ + p->pThis->m_interfaceImage.VRDEImageGeometrySet(p->hImageBitmap, &rect); if (RT_SUCCESS(rc)) { p->x = x; @@ -1786,6 +1883,7 @@ typedef struct H3DORInstance * the clipping must be done here in ConsoleVRDPServer */ uint32_t fu32CompletionFlags = 0; + p->fFallback = false; int rc = p->pThis->m_interfaceImage.VRDEImageHandleCreate(p->pThis->mhServer, &p->hImageBitmap, p, @@ -1800,7 +1898,9 @@ typedef struct H3DORInstance if (RT_FAILURE(rc)) { /* No support for a 3D + WINDOW. Try bitmap updates. */ + H3DORLOG(("H3DORGeometry: Fallback to bitmaps\n")); fu32CompletionFlags = 0; + p->fFallback = true; rc = p->pThis->m_interfaceImage.VRDEImageHandleCreate(p->pThis->mhServer, &p->hImageBitmap, p, @@ -1813,6 +1913,8 @@ typedef struct H3DORInstance &fu32CompletionFlags); } + H3DORLOG(("H3DORGeometry: Image handle create %Rrc, flags 0x%RX32\n", rc, fu32CompletionFlags)); + if (RT_SUCCESS(rc)) { p->x = x; @@ -1832,12 +1934,14 @@ typedef struct H3DORInstance p->h = 0; } } + + H3DORLOG(("H3DORGeometry: ins %p completed\n", pvInstance)); } /* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORVisibleRegion(void *pvInstance, - uint32_t cRects, RTRECT *paRects) + uint32_t cRects, const RTRECT *paRects) { - LogFlowFunc(("ins %p %d\n", pvInstance, cRects)); + H3DORLOG(("H3DORVisibleRegion: ins %p %d\n", pvInstance, cRects)); H3DORInstance *p = (H3DORInstance *)pvInstance; Assert(p); @@ -1861,12 +1965,14 @@ typedef struct H3DORInstance cRects, paRects); } + + H3DORLOG(("H3DORVisibleRegion: ins %p completed\n", pvInstance)); } /* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORFrame(void *pvInstance, void *pvData, uint32_t cbData) { - LogFlowFunc(("ins %p %p %d\n", pvInstance, pvData, cbData)); + H3DORLOG(("H3DORFrame: ins %p %p %d\n", pvInstance, pvData, cbData)); H3DORInstance *p = (H3DORInstance *)pvInstance; Assert(p); @@ -1889,11 +1995,13 @@ typedef struct H3DORInstance p->h, &image, sizeof(VRDEIMAGEBITMAP)); + + H3DORLOG(("H3DORFrame: ins %p completed\n", pvInstance)); } /* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DOREnd(void *pvInstance) { - LogFlowFunc(("ins %p\n", pvInstance)); + H3DORLOG(("H3DOREnd: ins %p\n", pvInstance)); H3DORInstance *p = (H3DORInstance *)pvInstance; Assert(p); @@ -1902,6 +2010,8 @@ typedef struct H3DORInstance p->pThis->m_interfaceImage.VRDEImageHandleClose(p->hImageBitmap); RTMemFree(p); + + H3DORLOG(("H3DOREnd: ins %p completed\n", pvInstance)); } /* static */ DECLCALLBACK(int) ConsoleVRDPServer::H3DORContextProperty(const void *pvContext, uint32_t index, @@ -1909,6 +2019,8 @@ typedef struct H3DORInstance { int rc = VINF_SUCCESS; + H3DORLOG(("H3DORContextProperty: index %d\n", index)); + if (index == H3DOR_PROP_FORMATS) { /* Return a comma separated list of supported formats. */ @@ -1929,10 +2041,11 @@ typedef struct H3DORInstance rc = VERR_NOT_SUPPORTED; } + H3DORLOG(("H3DORContextProperty: %Rrc\n", rc)); return rc; } -void ConsoleVRDPServer::remote3DRedirect(void) +void ConsoleVRDPServer::remote3DRedirect(bool fEnable) { if (!m_fInterfaceImage) { @@ -1940,21 +2053,17 @@ void ConsoleVRDPServer::remote3DRedirect(void) return; } - /* Check if 3D redirection has been enabled. */ + /* Check if 3D redirection has been enabled. It is enabled by default. */ com::Bstr bstr; HRESULT hrc = mConsole->getVRDEServer()->GetVRDEProperty(Bstr("H3DRedirect/Enabled").raw(), bstr.asOutParam()); - if (hrc != S_OK) - { - bstr = ""; - } - - com::Utf8Str value = bstr; + com::Utf8Str value = hrc == S_OK? bstr: ""; - bool fEnabled = RTStrICmp(value.c_str(), "true") == 0 - || RTStrICmp(value.c_str(), "1") == 0; + bool fAllowed = RTStrICmp(value.c_str(), "true") == 0 + || RTStrICmp(value.c_str(), "1") == 0 + || value.c_str()[0] == 0; - if (!fEnabled) + if (!fAllowed && fEnable) { return; } @@ -1971,6 +2080,12 @@ void ConsoleVRDPServer::remote3DRedirect(void) H3DORContextProperty }; + if (!fEnable) + { + /* This will tell the service to disable rediection. */ + RT_ZERO(outputRedirect); + } + VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; @@ -1992,11 +2107,11 @@ void ConsoleVRDPServer::remote3DRedirect(void) if (!RT_SUCCESS(rc)) { - AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc)); + Log(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc)); return; } - LogRel(("VRDE: Enabled 3D redirect.\n")); + LogRel(("VRDE: %s 3D redirect.\n", fEnable? "Enabled": "Disabled")); return; } @@ -2008,8 +2123,8 @@ void ConsoleVRDPServer::remote3DRedirect(void) void *pvData, uint32_t cbData) { - LogFlowFunc(("pvContext %p, pvUser %p, hVideo %p, u32Id %u, pvData %p, cbData %d\n", - pvContext, pvUser, hVideo, u32Id, pvData, cbData)); + H3DORLOG(("H3DOR: VRDEImageCbNotify: pvContext %p, pvUser %p, hVideo %p, u32Id %u, pvData %p, cbData %d\n", + pvContext, pvUser, hVideo, u32Id, pvData, cbData)); ConsoleVRDPServer *pServer = static_cast(pvContext); H3DORInstance *p = (H3DORInstance *)pvUser; @@ -2026,8 +2141,8 @@ void ConsoleVRDPServer::remote3DRedirect(void) } uint32_t u32StreamId = *(uint32_t *)pvData; - LogFlowFunc(("VRDE_IMAGE_NOTIFY_HANDLE_CREATE u32StreamId %d\n", - u32StreamId)); + H3DORLOG(("H3DOR: VRDE_IMAGE_NOTIFY_HANDLE_CREATE u32StreamId %d\n", + u32StreamId)); if (u32StreamId != 0) { @@ -2042,6 +2157,8 @@ void ConsoleVRDPServer::remote3DRedirect(void) return VINF_SUCCESS; } +#undef H3DORLOG + /* static */ DECLCALLBACK(int) ConsoleVRDPServer::VRDESCardCbNotify(void *pvContext, uint32_t u32Id, void *pvData, @@ -2098,19 +2215,64 @@ int ConsoleVRDPServer::SCardRequest(void *pvUser, uint32_t u32Function, const vo return rc; } -typedef struct TSMFHOSTCHANNELCTX + +struct TSMFHOSTCHCTX; +struct TSMFVRDPCTX; + +typedef struct TSMFHOSTCHCTX +{ + ConsoleVRDPServer *pThis; + + struct TSMFVRDPCTX *pVRDPCtx; /* NULL if no corresponding host channel context. */ + + void *pvDataReceived; + uint32_t cbDataReceived; + uint32_t cbDataAllocated; +} TSMFHOSTCHCTX; + +typedef struct TSMFVRDPCTX { ConsoleVRDPServer *pThis; VBOXHOSTCHANNELCALLBACKS *pCallbacks; void *pvCallbacks; + TSMFHOSTCHCTX *pHostChCtx; /* NULL if no corresponding host channel context. */ + uint32_t u32ChannelHandle; +} TSMFVRDPCTX; - void *pvDataReceived; - uint32_t cbDataReceived; - uint32_t cbDataAllocated; -} TSMFHOSTCHANNELCTX; +static int tsmfContextsAlloc(TSMFHOSTCHCTX **ppHostChCtx, TSMFVRDPCTX **ppVRDPCtx) +{ + TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)RTMemAllocZ(sizeof(TSMFHOSTCHCTX)); + if (!pHostChCtx) + { + return VERR_NO_MEMORY; + } + + TSMFVRDPCTX *pVRDPCtx = (TSMFVRDPCTX *)RTMemAllocZ(sizeof(TSMFVRDPCTX)); + if (!pVRDPCtx) + { + RTMemFree(pHostChCtx); + return VERR_NO_MEMORY; + } + + *ppHostChCtx = pHostChCtx; + *ppVRDPCtx = pVRDPCtx; + return VINF_SUCCESS; +} + +int ConsoleVRDPServer::tsmfLock(void) +{ + int rc = RTCritSectEnter(&mTSMFLock); + AssertRC(rc); + return rc; +} + +void ConsoleVRDPServer::tsmfUnlock(void) +{ + RTCritSectLeave(&mTSMFLock); +} /* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelAttach(void *pvProvider, void **ppvChannel, @@ -2122,26 +2284,35 @@ typedef struct TSMFHOSTCHANNELCTX ConsoleVRDPServer *pThis = static_cast(pvProvider); - TSMFHOSTCHANNELCTX *pCtx = (TSMFHOSTCHANNELCTX *)RTMemAllocZ(sizeof(TSMFHOSTCHANNELCTX)); - if (!pCtx) + /* Create 2 context structures: for the VRDP server and for the host service. */ + TSMFHOSTCHCTX *pHostChCtx = NULL; + TSMFVRDPCTX *pVRDPCtx = NULL; + + int rc = tsmfContextsAlloc(&pHostChCtx, &pVRDPCtx); + if (RT_FAILURE(rc)) { - return VERR_NO_MEMORY; + return rc; } - pCtx->pThis = pThis; - pCtx->pCallbacks = pCallbacks; - pCtx->pvCallbacks = pvCallbacks; + pHostChCtx->pThis = pThis; + pHostChCtx->pVRDPCtx = pVRDPCtx; - int rc = pThis->m_interfaceTSMF.VRDETSMFChannelCreate(pThis->mhServer, pCtx, u32Flags); + pVRDPCtx->pThis = pThis; + pVRDPCtx->pCallbacks = pCallbacks; + pVRDPCtx->pvCallbacks = pvCallbacks; + pVRDPCtx->pHostChCtx = pHostChCtx; + + rc = pThis->m_interfaceTSMF.VRDETSMFChannelCreate(pThis->mhServer, pVRDPCtx, u32Flags); if (RT_SUCCESS(rc)) { /* @todo contexts should be in a list for accounting. */ - *ppvChannel = pCtx; + *ppvChannel = pHostChCtx; } else { - RTMemFree(pCtx); + RTMemFree(pHostChCtx); + RTMemFree(pVRDPCtx); } return rc; @@ -2151,21 +2322,69 @@ typedef struct TSMFHOSTCHANNELCTX { LogFlowFunc(("\n")); - TSMFHOSTCHANNELCTX *pCtx = (TSMFHOSTCHANNELCTX *)pvChannel; + TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel; + ConsoleVRDPServer *pThis = pHostChCtx->pThis; + + int rc = pThis->tsmfLock(); + if (RT_SUCCESS(rc)) + { + bool fClose = false; + uint32_t u32ChannelHandle = 0; + + if (pHostChCtx->pVRDPCtx) + { + /* There is still a VRDP context for this channel. */ + pHostChCtx->pVRDPCtx->pHostChCtx = NULL; + u32ChannelHandle = pHostChCtx->pVRDPCtx->u32ChannelHandle; + fClose = true; + } + + pThis->tsmfUnlock(); - pCtx->pThis->m_interfaceTSMF.VRDETSMFChannelClose(pCtx->pThis->mhServer, pCtx->u32ChannelHandle); - /* @todo */ + RTMemFree(pHostChCtx); + + if (fClose) + { + LogFlowFunc(("Closing VRDE channel %d.\n", u32ChannelHandle)); + pThis->m_interfaceTSMF.VRDETSMFChannelClose(pThis->mhServer, u32ChannelHandle); + } + else + { + LogFlowFunc(("No VRDE channel.\n")); + } + } } /* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelSend(void *pvChannel, const void *pvData, uint32_t cbData) { - LogFlowFunc(("\n")); - TSMFHOSTCHANNELCTX *pCtx = (TSMFHOSTCHANNELCTX *)pvChannel; + LogFlowFunc(("cbData %d\n", cbData)); + + TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel; + ConsoleVRDPServer *pThis = pHostChCtx->pThis; + + int rc = pThis->tsmfLock(); + if (RT_SUCCESS(rc)) + { + bool fSend = false; + uint32_t u32ChannelHandle = 0; + + if (pHostChCtx->pVRDPCtx) + { + u32ChannelHandle = pHostChCtx->pVRDPCtx->u32ChannelHandle; + fSend = true; + } - int rc = pCtx->pThis->m_interfaceTSMF.VRDETSMFChannelSend(pCtx->pThis->mhServer, pCtx->u32ChannelHandle, - pvData, cbData); + pThis->tsmfUnlock(); + + if (fSend) + { + LogFlowFunc(("Send to VRDE channel %d.\n", u32ChannelHandle)); + rc = pThis->m_interfaceTSMF.VRDETSMFChannelSend(pThis->mhServer, u32ChannelHandle, + pvData, cbData); + } + } return rc; } @@ -2176,32 +2395,38 @@ typedef struct TSMFHOSTCHANNELCTX uint32_t *pcbReceived, uint32_t *pcbRemaining) { - LogFlowFunc(("\n")); - - TSMFHOSTCHANNELCTX *pCtx = (TSMFHOSTCHANNELCTX *)pvChannel; - int rc = VINF_SUCCESS; + LogFlowFunc(("cbData %d\n", cbData)); - uint32_t cbToCopy = RT_MIN(cbData, pCtx->cbDataReceived); - uint32_t cbRemaining = pCtx->cbDataReceived - cbToCopy; + TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel; + ConsoleVRDPServer *pThis = pHostChCtx->pThis; - LogFlowFunc(("cbToCopy %d, cbRemaining %d\n", cbToCopy, cbRemaining)); - - if (cbToCopy != 0) + int rc = pThis->tsmfLock(); + if (RT_SUCCESS(rc)) { - memcpy(pvData, pCtx->pvDataReceived, cbToCopy); + uint32_t cbToCopy = RT_MIN(cbData, pHostChCtx->cbDataReceived); + uint32_t cbRemaining = pHostChCtx->cbDataReceived - cbToCopy; + + LogFlowFunc(("cbToCopy %d, cbRemaining %d\n", cbToCopy, cbRemaining)); - if (cbRemaining != 0) + if (cbToCopy != 0) { - memmove(pCtx->pvDataReceived, (uint8_t *)pCtx->pvDataReceived + cbToCopy, cbRemaining); + memcpy(pvData, pHostChCtx->pvDataReceived, cbToCopy); + + if (cbRemaining != 0) + { + memmove(pHostChCtx->pvDataReceived, (uint8_t *)pHostChCtx->pvDataReceived + cbToCopy, cbRemaining); + } + + pHostChCtx->cbDataReceived = cbRemaining; } - pCtx->cbDataReceived = cbRemaining; - } + pThis->tsmfUnlock(); - *pcbRemaining = cbRemaining; - *pcbReceived = cbToCopy; + *pcbRemaining = cbRemaining; + *pcbReceived = cbToCopy; + } - return VINF_SUCCESS; + return rc; } /* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelControl(void *pvChannel, @@ -2212,7 +2437,8 @@ typedef struct TSMFHOSTCHANNELCTX uint32_t cbData, uint32_t *pcbDataReturned) { - LogFlowFunc(("\n")); + LogFlowFunc(("u32Code %u\n", u32Code)); + if (!pvChannel) { /* Special case, the provider must answer rather than a channel instance. */ @@ -2295,33 +2521,44 @@ void ConsoleVRDPServer::setupTSMF(void) const void *pvParm, uint32_t cbParm) { + int rc = VINF_SUCCESS; + ConsoleVRDPServer *pThis = static_cast(pvContext); - TSMFHOSTCHANNELCTX *pCtx = (TSMFHOSTCHANNELCTX *)pvChannel; + TSMFVRDPCTX *pVRDPCtx = (TSMFVRDPCTX *)pvChannel; - Assert(pCtx->pThis == pThis); + Assert(pVRDPCtx->pThis == pThis); - switch(u32Notification) + if (pVRDPCtx->pCallbacks == NULL) + { + LogFlowFunc(("tsmfHostChannel: Channel disconnected. Skipping.\n")); + return; + } + + switch (u32Notification) { case VRDE_TSMF_N_CREATE_ACCEPTED: { VRDETSMFNOTIFYCREATEACCEPTED *p = (VRDETSMFNOTIFYCREATEACCEPTED *)pvParm; Assert(cbParm == sizeof(VRDETSMFNOTIFYCREATEACCEPTED)); - LogFlowFunc(("VRDE_TSMF_N_CREATE_ACCEPTED: p->u32ChannelHandle %d\n", p->u32ChannelHandle)); + LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_CREATE_ACCEPTED(%p): p->u32ChannelHandle %d\n", + pVRDPCtx, p->u32ChannelHandle)); - pCtx->u32ChannelHandle = p->u32ChannelHandle; + pVRDPCtx->u32ChannelHandle = p->u32ChannelHandle; - pCtx->pCallbacks->HostChannelCallbackEvent(pCtx->pvCallbacks, pCtx, - VBOX_TSMF_HCH_CREATE_ACCEPTED, - NULL, 0); + pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx, + VBOX_TSMF_HCH_CREATE_ACCEPTED, + NULL, 0); } break; case VRDE_TSMF_N_CREATE_DECLINED: { - pCtx->pCallbacks->HostChannelCallbackEvent(pCtx->pvCallbacks, pCtx, - VBOX_TSMF_HCH_CREATE_DECLINED, - NULL, 0); + LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_CREATE_DECLINED(%p)\n", pVRDPCtx)); + + pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx, + VBOX_TSMF_HCH_CREATE_DECLINED, + NULL, 0); } break; case VRDE_TSMF_N_DATA: @@ -2330,39 +2567,79 @@ void ConsoleVRDPServer::setupTSMF(void) VRDETSMFNOTIFYDATA *p = (VRDETSMFNOTIFYDATA *)pvParm; Assert(cbParm == sizeof(VRDETSMFNOTIFYDATA)); - LogFlowFunc(("VRDE_TSMF_N_DATA: p->cbData %d\n", p->cbData)); + LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DATA(%p): p->cbData %d\n", pVRDPCtx, p->cbData)); - if (pCtx->pvDataReceived) - { - uint32_t cbAlloc = p->cbData + pCtx->cbDataReceived; - pCtx->pvDataReceived = RTMemRealloc(pCtx->pvDataReceived, cbAlloc); - memcpy((uint8_t *)pCtx->pvDataReceived + pCtx->cbDataReceived, p->pvData, p->cbData); + VBOXHOSTCHANNELEVENTRECV ev; + ev.u32SizeAvailable = 0; - pCtx->cbDataReceived += p->cbData; - pCtx->cbDataAllocated = cbAlloc; - } - else + rc = pThis->tsmfLock(); + + if (RT_SUCCESS(rc)) { - pCtx->pvDataReceived = RTMemAlloc(p->cbData); - memcpy(pCtx->pvDataReceived, p->pvData, p->cbData); + TSMFHOSTCHCTX *pHostChCtx = pVRDPCtx->pHostChCtx; - pCtx->cbDataReceived = p->cbData; - pCtx->cbDataAllocated = p->cbData; - } + if (pHostChCtx) + { + if (pHostChCtx->pvDataReceived) + { + uint32_t cbAlloc = p->cbData + pHostChCtx->cbDataReceived; + pHostChCtx->pvDataReceived = RTMemRealloc(pHostChCtx->pvDataReceived, cbAlloc); + memcpy((uint8_t *)pHostChCtx->pvDataReceived + pHostChCtx->cbDataReceived, p->pvData, p->cbData); - VBOXHOSTCHANNELEVENTRECV ev; - ev.u32SizeAvailable = p->cbData; + pHostChCtx->cbDataReceived += p->cbData; + pHostChCtx->cbDataAllocated = cbAlloc; + } + else + { + pHostChCtx->pvDataReceived = RTMemAlloc(p->cbData); + memcpy(pHostChCtx->pvDataReceived, p->pvData, p->cbData); - pCtx->pCallbacks->HostChannelCallbackEvent(pCtx->pvCallbacks, pCtx, - VBOX_HOST_CHANNEL_EVENT_RECV, - &ev, sizeof(ev)); + pHostChCtx->cbDataReceived = p->cbData; + pHostChCtx->cbDataAllocated = p->cbData; + } + + ev.u32SizeAvailable = p->cbData; + } + else + { + LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DATA: no host channel. Skipping\n")); + } + + pThis->tsmfUnlock(); + } + + pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx, + VBOX_HOST_CHANNEL_EVENT_RECV, + &ev, sizeof(ev)); } break; case VRDE_TSMF_N_DISCONNECTED: { - pCtx->pCallbacks->HostChannelCallbackEvent(pCtx->pvCallbacks, pCtx, - VBOX_TSMF_HCH_DISCONNECTED, - NULL, 0); + LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DISCONNECTED(%p)\n", pVRDPCtx)); + + pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx, + VBOX_TSMF_HCH_DISCONNECTED, + NULL, 0); + + /* The callback context will not be used anymore. */ + pVRDPCtx->pCallbacks->HostChannelCallbackDeleted(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx); + pVRDPCtx->pCallbacks = NULL; + pVRDPCtx->pvCallbacks = NULL; + + rc = pThis->tsmfLock(); + if (RT_SUCCESS(rc)) + { + if (pVRDPCtx->pHostChCtx) + { + /* There is still a host channel context for this channel. */ + pVRDPCtx->pHostChCtx->pVRDPCtx = NULL; + } + + pThis->tsmfUnlock(); + + RT_ZERO(*pVRDPCtx); + RTMemFree(pVRDPCtx); + } } break; default: @@ -2372,15 +2649,222 @@ void ConsoleVRDPServer::setupTSMF(void) } } +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInNotify(void *pvCallback, + uint32_t u32Id, + const void *pvData, + uint32_t cbData) +{ + ConsoleVRDPServer *pThis = static_cast(pvCallback); + if (pThis->mEmWebcam) + { + pThis->mEmWebcam->EmWebcamCbNotify(u32Id, pvData, cbData); + } +} + +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInDeviceDesc(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, + uint32_t cbDevice) +{ + ConsoleVRDPServer *pThis = static_cast(pvCallback); + if (pThis->mEmWebcam) + { + pThis->mEmWebcam->EmWebcamCbDeviceDesc(rcRequest, pDeviceCtx, pvUser, pDeviceDesc, cbDevice); + } +} + +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInControl(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, + uint32_t cbControl) +{ + ConsoleVRDPServer *pThis = static_cast(pvCallback); + if (pThis->mEmWebcam) + { + pThis->mEmWebcam->EmWebcamCbControl(rcRequest, pDeviceCtx, pvUser, pControl, cbControl); + } +} + +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInFrame(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, + uint32_t cbFrame) +{ + ConsoleVRDPServer *pThis = static_cast(pvCallback); + if (pThis->mEmWebcam) + { + pThis->mEmWebcam->EmWebcamCbFrame(rcRequest, pDeviceCtx, pFrame, cbFrame); + } +} + +int ConsoleVRDPServer::VideoInDeviceAttach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, void *pvDeviceCtx) +{ + int rc; + + if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInDeviceAttach) + { + rc = m_interfaceVideoIn.VRDEVideoInDeviceAttach(mhServer, pDeviceHandle, pvDeviceCtx); + } + else + { + rc = VERR_NOT_SUPPORTED; + } + + return rc; +} + +int ConsoleVRDPServer::VideoInDeviceDetach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle) +{ + int rc; + + if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInDeviceDetach) + { + rc = m_interfaceVideoIn.VRDEVideoInDeviceDetach(mhServer, pDeviceHandle); + } + else + { + rc = VERR_NOT_SUPPORTED; + } + + return rc; +} + +int ConsoleVRDPServer::VideoInGetDeviceDesc(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle) +{ + int rc; + + if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInGetDeviceDesc) + { + rc = m_interfaceVideoIn.VRDEVideoInGetDeviceDesc(mhServer, pvUser, pDeviceHandle); + } + else + { + rc = VERR_NOT_SUPPORTED; + } + + return rc; +} + +int ConsoleVRDPServer::VideoInControl(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + const VRDEVIDEOINCTRLHDR *pReq, uint32_t cbReq) +{ + int rc; + + if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInControl) + { + rc = m_interfaceVideoIn.VRDEVideoInControl(mhServer, pvUser, pDeviceHandle, pReq, cbReq); + } + else + { + rc = VERR_NOT_SUPPORTED; + } + + return rc; +} + + +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackInputSetup(void *pvCallback, + int rcRequest, + uint32_t u32Method, + const void *pvResult, + uint32_t cbResult) +{ + NOREF(pvCallback); + NOREF(rcRequest); + NOREF(u32Method); + NOREF(pvResult); + NOREF(cbResult); +} + +/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackInputEvent(void *pvCallback, + uint32_t u32Method, + const void *pvEvent, + uint32_t cbEvent) +{ + ConsoleVRDPServer *pThis = static_cast(pvCallback); + + if (u32Method == VRDE_INPUT_METHOD_TOUCH) + { + if (cbEvent >= sizeof(VRDEINPUTHEADER)) + { + VRDEINPUTHEADER *pHeader = (VRDEINPUTHEADER *)pvEvent; + + if (pHeader->u16EventId == VRDEINPUT_EVENTID_TOUCH) + { + IMouse *pMouse = pThis->mConsole->getMouse(); + + VRDEINPUT_TOUCH_EVENT_PDU *p = (VRDEINPUT_TOUCH_EVENT_PDU *)pHeader; + + uint16_t iFrame; + for (iFrame = 0; iFrame < p->u16FrameCount; iFrame++) + { + VRDEINPUT_TOUCH_FRAME *pFrame = &p->aFrames[iFrame]; + + com::SafeArray aContacts(pFrame->u16ContactCount); + + uint16_t iContact; + for (iContact = 0; iContact < pFrame->u16ContactCount; iContact++) + { + VRDEINPUT_CONTACT_DATA *pContact = &pFrame->aContacts[iContact]; + + int16_t x = (int16_t)(pContact->i32X + 1); + int16_t y = (int16_t)(pContact->i32Y + 1); + uint8_t contactId = pContact->u8ContactId; + uint8_t contactState = TouchContactState_None; + + if (pContact->u32ContactFlags & VRDEINPUT_CONTACT_FLAG_INRANGE) + { + contactState |= TouchContactState_InRange; + } + if (pContact->u32ContactFlags & VRDEINPUT_CONTACT_FLAG_INCONTACT) + { + contactState |= TouchContactState_InContact; + } + + aContacts[iContact] = RT_MAKE_U64_FROM_U16((uint16_t)x, + (uint16_t)y, + RT_MAKE_U16(contactId, contactState), + 0); + } + + if (pFrame->u64FrameOffset == 0) + { + pThis->mu64TouchInputTimestampMCS = 0; + } + else + { + pThis->mu64TouchInputTimestampMCS += pFrame->u64FrameOffset; + } + + pMouse->PutEventMultiTouch(pFrame->u16ContactCount, + ComSafeArrayAsInParam(aContacts), + (ULONG)(pThis->mu64TouchInputTimestampMCS / 1000)); /* Micro->milliseconds. */ + } + } + else if (pHeader->u16EventId == VRDEINPUT_EVENTID_DISMISS_HOVERING_CONTACT) + { + /* @todo */ + } + else + { + AssertMsgFailed(("EventId %d\n", pHeader->u16EventId)); + } + } + } +} + + void ConsoleVRDPServer::EnableConnections(void) { if (mpEntryPoints && mhServer) { mpEntryPoints->VRDEEnableConnections(mhServer, true); - /* Redirect 3D output if it is enabled. */ - remote3DRedirect(); - /* Setup the generic TSMF channel. */ setupTSMF(); } @@ -2471,6 +2955,11 @@ void ConsoleVRDPServer::Stop(void) { Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on * linux. Just remove this when it's 100% sure that problem has been fixed. */ + +#ifdef VBOX_WITH_USB + remoteUSBThreadStop(); +#endif /* VBOX_WITH_USB */ + if (mhServer) { HVRDESERVER hServer = mhServer; @@ -2478,16 +2967,29 @@ void ConsoleVRDPServer::Stop(void) /* Reset the handle to avoid further calls to the server. */ mhServer = 0; + /* Workaround for VM process hangs on termination. + * + * Make sure that the server is not currently processing a resize. + * mhServer 0 will not allow to enter the server again. + * Wait until any current resize returns from the server. + */ + if (mcInResize) + { + LogRel(("VRDP: waiting for resize %d\n", mcInResize)); + + int i = 0; + while (mcInResize && ++i < 100) + { + RTThreadSleep(10); + } + } + if (mpEntryPoints && hServer) { mpEntryPoints->VRDEDestroy(hServer); } } -#ifdef VBOX_WITH_USB - remoteUSBThreadStop(); -#endif /* VBOX_WITH_USB */ - mpfnAuthEntry = NULL; mpfnAuthEntry2 = NULL; mpfnAuthEntry3 = NULL; @@ -2615,6 +3117,77 @@ void ConsoleVRDPServer::remoteUSBThreadStop(void) } #endif /* VBOX_WITH_USB */ +typedef struct AuthCtx +{ + AuthResult result; + + PAUTHENTRY3 pfnAuthEntry3; + PAUTHENTRY2 pfnAuthEntry2; + PAUTHENTRY pfnAuthEntry; + + const char *pszCaller; + PAUTHUUID pUuid; + AuthGuestJudgement guestJudgement; + const char *pszUser; + const char *pszPassword; + const char *pszDomain; + int fLogon; + unsigned clientId; +} AuthCtx; + +static DECLCALLBACK(int) authThread(RTTHREAD self, void *pvUser) +{ + AuthCtx *pCtx = (AuthCtx *)pvUser; + + if (pCtx->pfnAuthEntry3) + { + pCtx->result = pCtx->pfnAuthEntry3(pCtx->pszCaller, pCtx->pUuid, pCtx->guestJudgement, + pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain, + pCtx->fLogon, pCtx->clientId); + } + else if (pCtx->pfnAuthEntry2) + { + pCtx->result = pCtx->pfnAuthEntry2(pCtx->pUuid, pCtx->guestJudgement, + pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain, + pCtx->fLogon, pCtx->clientId); + } + else if (pCtx->pfnAuthEntry) + { + pCtx->result = pCtx->pfnAuthEntry(pCtx->pUuid, pCtx->guestJudgement, + pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain); + } + return VINF_SUCCESS; +} + +static AuthResult authCall(AuthCtx *pCtx) +{ + AuthResult result = AuthResultAccessDenied; + + /* Use a separate thread because external modules might need a lot of stack space. */ + RTTHREAD thread = NIL_RTTHREAD; + int rc = RTThreadCreate(&thread, authThread, pCtx, 512*_1K, + RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VRDEAuth"); + LogFlow(("authCall: RTThreadCreate %Rrc\n", rc)); + + if (RT_SUCCESS(rc)) + { + rc = RTThreadWait(thread, RT_INDEFINITE_WAIT, NULL); + LogFlow(("authCall: RTThreadWait %Rrc\n", rc)); + } + + if (RT_SUCCESS(rc)) + { + /* Only update the result if the thread finished without errors. */ + result = pCtx->result; + } + else + { + LogRel(("AUTH: unable to execute the auth thread %Rrc\n", rc)); + } + + return result; +} + AuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, AuthGuestJudgement guestJudgement, const char *pszUser, const char *pszPassword, const char *pszDomain, uint32_t u32ClientId) @@ -2638,7 +3211,7 @@ AuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, AuthGuestJudgement Utf8Str filename = authLibrary; - LogRel(("AUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw())); + LogRel(("AUTH: loading external authentication library '%ls'\n", authLibrary.raw())); int rc; if (RTPathHavePath(filename.c_str())) @@ -2726,19 +3299,21 @@ AuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, AuthGuestJudgement Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3)); - AuthResult result = AuthResultAccessDenied; - if (mpfnAuthEntry3) - { - result = mpfnAuthEntry3("vrde", &rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId); - } - else if (mpfnAuthEntry2) - { - result = mpfnAuthEntry2(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId); - } - else if (mpfnAuthEntry) - { - result = mpfnAuthEntry(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain); - } + AuthCtx ctx; + ctx.result = AuthResultAccessDenied; /* Denied by default. */ + ctx.pfnAuthEntry3 = mpfnAuthEntry3; + ctx.pfnAuthEntry2 = mpfnAuthEntry2; + ctx.pfnAuthEntry = mpfnAuthEntry; + ctx.pszCaller = "vrde"; + ctx.pUuid = &rawuuid; + ctx.guestJudgement = guestJudgement; + ctx.pszUser = pszUser; + ctx.pszPassword = pszPassword; + ctx.pszDomain = pszDomain; + ctx.fLogon = true; + ctx.clientId = u32ClientId; + + AuthResult result = authCall(&ctx); switch (result) { @@ -2772,10 +3347,21 @@ void ConsoleVRDPServer::AuthDisconnect(const Guid &uuid, uint32_t u32ClientId) Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3)); - if (mpfnAuthEntry3) - mpfnAuthEntry3("vrde", &rawuuid, AuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId); - else if (mpfnAuthEntry2) - mpfnAuthEntry2(&rawuuid, AuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId); + AuthCtx ctx; + ctx.result = AuthResultAccessDenied; /* Not used. */ + ctx.pfnAuthEntry3 = mpfnAuthEntry3; + ctx.pfnAuthEntry2 = mpfnAuthEntry2; + ctx.pfnAuthEntry = NULL; /* Does not use disconnect notification. */ + ctx.pszCaller = "vrde"; + ctx.pUuid = &rawuuid; + ctx.guestJudgement = AuthGuestNotAsked; + ctx.pszUser = NULL; + ctx.pszPassword = NULL; + ctx.pszDomain = NULL; + ctx.fLogon = false; + ctx.clientId = u32ClientId; + + authCall(&ctx); } int ConsoleVRDPServer::lockConsoleVRDPServer(void) @@ -3210,11 +3796,13 @@ void ConsoleVRDPServer::SendUpdate(unsigned uScreenId, void *pvUpdate, uint32_t } } -void ConsoleVRDPServer::SendResize(void) const +void ConsoleVRDPServer::SendResize(void) { if (mpEntryPoints && mhServer) { + ++mcInResize; mpEntryPoints->VRDEResize(mhServer); + --mcInResize; } } @@ -3297,24 +3885,6 @@ void ConsoleVRDPServer::SendAudioInputEnd(void *pvUserCtx) } } -#ifdef VBOX_WITH_USB_VIDEO -int ConsoleVRDPServer::GetVideoFrameDimensions(uint16_t *pu16Heigh, uint16_t *pu16Width) -{ - *pu16Heigh = 640; - *pu16Width = 480; - return VINF_SUCCESS; -} - -int ConsoleVRDPServer::SendVideoSreamOn(bool fFetch) -{ - /* Here we inform server that guest is starting/stopping - * the stream - */ - return VINF_SUCCESS; -} -#endif - - void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const { diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp index fc261019..3477a07c 100644 --- a/src/VBox/Main/src-client/DisplayImpl.cpp +++ b/src/VBox/Main/src-client/DisplayImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,10 +30,11 @@ #include #include #include +#include #include #include -#ifdef DEBUG /* for VM_ASSERT_EMT(). */ +#if defined(DEBUG) || defined(VBOX_STRICT) /* for VM_ASSERT_EMT(). */ # include #endif @@ -48,9 +49,18 @@ #include #ifdef VBOX_WITH_VPX +# include # include "VideoRec.h" #endif +#ifdef VBOX_WITH_CROGL +typedef enum +{ + CRVREC_STATE_IDLE, + CRVREC_STATE_SUBMITTED +} CRVREC_STATE; +#endif + /** * Display driver instance data. * @@ -76,8 +86,8 @@ typedef struct DRVMAINDISPLAY #define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector) #ifdef DEBUG_sunlover -static STAMPROFILE StatDisplayRefresh; -static int stam = 0; +static STAMPROFILE g_StatDisplayRefresh; +static int g_stam = 0; #endif /* DEBUG_sunlover */ // constructor / destructor @@ -105,6 +115,9 @@ HRESULT Display::FinalConstruct() mfPendingVideoAccelEnable = false; mfMachineRunning = false; +#ifdef VBOX_WITH_CROGL + mfCrOglDataHidden = false; +#endif mpu8VbvaPartial = NULL; mcbVbvaPartial = 0; @@ -121,11 +134,34 @@ HRESULT Display::FinalConstruct() int rc = RTCritSectInit(&mVBVALock); AssertRC(rc); + + rc = RTCritSectInit(&mSaveSeamlessRectLock); + AssertRC(rc); + mfu32PendingVideoAccelDisable = false; #ifdef VBOX_WITH_HGSMI mu32UpdateVBVAFlags = 0; #endif +#ifdef VBOX_WITH_VPX + mpVideoRecCtx = NULL; + for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++) + maVideoRecEnabled[i] = true; +#endif + +#ifdef VBOX_WITH_CRHGSMI + mhCrOglSvc = NULL; +#endif +#ifdef VBOX_WITH_CROGL + RT_ZERO(mCrOglCallbacks); + RT_ZERO(mCrOglScreenshotData); + mfCrOglVideoRecState = CRVREC_STATE_IDLE; + mCrOglScreenshotData.u32Screen = CRSCREEN_ALL; + mCrOglScreenshotData.pvContext = this; + mCrOglScreenshotData.pfnScreenshotBegin = displayCrVRecScreenshotBegin; + mCrOglScreenshotData.pfnScreenshotPerform = displayCrVRecScreenshotPerform; + mCrOglScreenshotData.pfnScreenshotEnd = displayCrVRecScreenshotEnd; +#endif return BaseFinalConstruct(); } @@ -137,7 +173,13 @@ void Display::FinalRelease() if (RTCritSectIsInitialized (&mVBVALock)) { RTCritSectDelete (&mVBVALock); - memset (&mVBVALock, 0, sizeof (mVBVALock)); + RT_ZERO(mVBVALock); + } + + if (RTCritSectIsInitialized(&mSaveSeamlessRectLock)) + { + RTCritSectDelete(&mSaveSeamlessRectLock); + RT_ZERO(mSaveSeamlessRectLock); } BaseFinalRelease(); } @@ -205,6 +247,47 @@ static int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy, return rc; } +#ifdef VBOX_WITH_CROGL +typedef struct +{ + CRVBOXHGCMTAKESCREENSHOT Base; + + /* 32bpp small RGB image. */ + uint8_t *pu8Thumbnail; + uint32_t cbThumbnail; + uint32_t cxThumbnail; + uint32_t cyThumbnail; + + /* PNG screenshot. */ + uint8_t *pu8PNG; + uint32_t cbPNG; + uint32_t cxPNG; + uint32_t cyPNG; +} VBOX_DISPLAY_SAVESCREENSHOT_DATA; + +static DECLCALLBACK(void) displaySaveScreenshotReport(void *pvCtx, uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uBitsPerPixel, + uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + VBOX_DISPLAY_SAVESCREENSHOT_DATA *pData = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)pvCtx; + displayMakeThumbnail(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8Thumbnail, &pData->cbThumbnail, &pData->cxThumbnail, &pData->cyThumbnail); + int rc = DisplayMakePNG(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8PNG, &pData->cbPNG, &pData->cxPNG, &pData->cyPNG, 1); + if (RT_FAILURE(rc)) + { + AssertMsgFailed(("DisplayMakePNG failed %d\n", rc)); + if (pData->pu8PNG) + { + RTMemFree(pData->pu8PNG); + pData->pu8PNG = NULL; + } + pData->cbPNG = 0; + pData->cxPNG = 0; + pData->cyPNG = 0; + } +} +#endif + DECLCALLBACK(void) Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) { @@ -222,8 +305,8 @@ Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) uint32_t cxPNG = 0; uint32_t cyPNG = 0; - Console::SafeVMPtr pVM (that->mParent); - if (SUCCEEDED(pVM.rc())) + Console::SafeVMPtr ptrVM(that->mParent); + if (ptrVM.isOk()) { /* Query RGB bitmap. */ uint8_t *pu8Data = NULL; @@ -231,39 +314,101 @@ Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) uint32_t cx = 0; uint32_t cy = 0; - /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */ - int rc = Display::displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy); +#ifdef VBOX_WITH_CROGL + BOOL f3DSnapshot = FALSE; + BOOL is3denabled; + that->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled && that->mCrOglCallbacks.pfnHasData()) + { + VMMDev *pVMMDev = that->mParent->getVMMDev(); + if (pVMMDev) + { + VBOX_DISPLAY_SAVESCREENSHOT_DATA *pScreenshot = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)RTMemAllocZ(sizeof (*pScreenshot)); + if (pScreenshot) + { + /* screen id or CRSCREEN_ALL to specify all enabled */ + pScreenshot->Base.u32Screen = 0; + pScreenshot->Base.u32Width = 0; + pScreenshot->Base.u32Height = 0; + pScreenshot->Base.u32Pitch = 0; + pScreenshot->Base.pvBuffer = NULL; + pScreenshot->Base.pvContext = pScreenshot; + pScreenshot->Base.pfnScreenshotBegin = NULL; + pScreenshot->Base.pfnScreenshotPerform = displaySaveScreenshotReport; + pScreenshot->Base.pfnScreenshotEnd = NULL; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = &pScreenshot->Base; + parm.u.pointer.size = sizeof (pScreenshot->Base); + + int rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_TAKE_SCREENSHOT, 1, &parm); + if (RT_SUCCESS(rc)) + { + if (pScreenshot->pu8PNG) + { + pu8Thumbnail = pScreenshot->pu8Thumbnail; + cbThumbnail = pScreenshot->cbThumbnail; + cxThumbnail = pScreenshot->cxThumbnail; + cyThumbnail = pScreenshot->cyThumbnail; + + /* PNG screenshot. */ + pu8PNG = pScreenshot->pu8PNG; + cbPNG = pScreenshot->cbPNG; + cxPNG = pScreenshot->cxPNG; + cyPNG = pScreenshot->cyPNG; + f3DSnapshot = TRUE; + } + else + AssertMsgFailed(("no png\n")); + } + else + AssertMsgFailed(("SHCRGL_HOST_FN_TAKE_SCREENSHOT failed %d\n", rc)); + - /* - * It is possible that success is returned but everything is 0 or NULL. - * (no display attached if a VM is running with VBoxHeadless on OSE for example) - */ - if (RT_SUCCESS(rc) && pu8Data) + RTMemFree(pScreenshot); + } + } + } + + if (!f3DSnapshot) +#endif { - Assert(cx && cy); + /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */ + int rc = Display::displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy); - /* Prepare a small thumbnail and a PNG screenshot. */ - displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail); - rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1); - if (RT_FAILURE(rc)) + /* + * It is possible that success is returned but everything is 0 or NULL. + * (no display attached if a VM is running with VBoxHeadless on OSE for example) + */ + if (RT_SUCCESS(rc) && pu8Data) { - if (pu8PNG) + Assert(cx && cy); + + /* Prepare a small thumbnail and a PNG screenshot. */ + displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail); + rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1); + if (RT_FAILURE(rc)) { - RTMemFree(pu8PNG); - pu8PNG = NULL; + if (pu8PNG) + { + RTMemFree(pu8PNG); + pu8PNG = NULL; + } + cbPNG = 0; + cxPNG = 0; + cyPNG = 0; } - cbPNG = 0; - cxPNG = 0; - cyPNG = 0; - } - /* This can be called from any thread. */ - that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data); + /* This can be called from any thread. */ + that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data); + } } } else { - LogFunc(("Failed to get VM pointer 0x%x\n", pVM.rc())); + LogFunc(("Failed to get VM pointer 0x%x\n", ptrVM.rc())); } /* Regardless of rc, save what is available: @@ -436,40 +581,8 @@ HRESULT Display::init(Console *aParent) unconst(mParent) = aParent; - // by default, we have an internal framebuffer which is - // NULL, i.e. a black hole for no display output - mFramebufferOpened = false; - ULONG ul; mParent->machine()->COMGETTER(MonitorCount)(&ul); - -#ifdef VBOX_WITH_VPX - if (VideoRecContextCreate(&mpVideoRecContext)) - { - LogFlow(("Failed to create Video Recording Context\n")); - return E_FAIL; - } - - BOOL fEnabled = false; - mParent->machine()->COMGETTER(VideoCaptureEnabled)(&fEnabled); - if (fEnabled) - { - ULONG ulVideoCaptureHorzRes; - mParent->machine()->COMGETTER(VideoCaptureWidth)(&ulVideoCaptureHorzRes); - ULONG ulVideoCaptureVertRes; - mParent->machine()->COMGETTER(VideoCaptureHeight)(&ulVideoCaptureVertRes); - BSTR strVideoCaptureFile; - mParent->machine()->COMGETTER(VideoCaptureFile)(&strVideoCaptureFile); - LogFlow(("VidoeRecording VPX enabled\n")); - if (VideoRecContextInit(mpVideoRecContext, strVideoCaptureFile, - ulVideoCaptureHorzRes, ulVideoCaptureVertRes)) - { - LogFlow(("Failed to initialize video recording context\n")); - return E_FAIL; - } - } -#endif - mcMonitors = ul; for (ul = 0; ul < mcMonitors; ul++) @@ -500,14 +613,20 @@ HRESULT Display::init(Console *aParent) maFramebuffers[ul].fDefaultFormat = false; - memset (&maFramebuffers[ul].dirtyRect, 0 , sizeof (maFramebuffers[ul].dirtyRect)); - memset (&maFramebuffers[ul].pendingResize, 0 , sizeof (maFramebuffers[ul].pendingResize)); + maFramebuffers[ul].mcSavedVisibleRegion = 0; + maFramebuffers[ul].mpSavedVisibleRegion = NULL; + + RT_ZERO(maFramebuffers[ul].dirtyRect); + RT_ZERO(maFramebuffers[ul].pendingResize); #ifdef VBOX_WITH_HGSMI maFramebuffers[ul].fVBVAEnabled = false; maFramebuffers[ul].cVBVASkipUpdate = 0; - memset (&maFramebuffers[ul].vbvaSkippedRect, 0, sizeof (maFramebuffers[ul].vbvaSkippedRect)); + RT_ZERO(maFramebuffers[ul].vbvaSkippedRect); maFramebuffers[ul].pVBVAHostFlags = NULL; #endif /* VBOX_WITH_HGSMI */ +#ifdef VBOX_WITH_CROGL + RT_ZERO(maFramebuffers[ul].pendingViewportInfo); +#endif } { @@ -557,23 +676,18 @@ void Display::uninit() mpDrv = NULL; mpVMMDev = NULL; mfVMMDevInited = true; - -#ifdef VBOX_WITH_VPX - if (mpVideoRecContext) - VideoRecContextClose(mpVideoRecContext); -#endif } /** * Register the SSM methods. Called by the power up thread to be able to * pass pVM */ -int Display::registerSSM(PVM pVM) +int Display::registerSSM(PUVM pUVM) { /* Version 2 adds width and height of the framebuffer; version 3 adds * the framebuffer offset in the virtual desktop and the framebuffer flags. */ - int rc = SSMR3RegisterExternal(pVM, "DisplayData", 0, sSSMDisplayVer3, + int rc = SSMR3RegisterExternal(pUVM, "DisplayData", 0, sSSMDisplayVer3, mcMonitors * sizeof(uint32_t) * 8 + sizeof(uint32_t), NULL, NULL, NULL, NULL, displaySSMSave, NULL, @@ -584,20 +698,20 @@ int Display::registerSSM(PVM pVM) * Register loaders for old saved states where iInstance was * 3 * sizeof(uint32_t *) due to a code mistake. */ - rc = SSMR3RegisterExternal(pVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, NULL, NULL, NULL, displaySSMLoad, NULL, this); AssertRCReturn(rc, rc); - rc = SSMR3RegisterExternal(pVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, NULL, NULL, NULL, displaySSMLoad, NULL, this); AssertRCReturn(rc, rc); /* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */ - rc = SSMR3RegisterExternal(pVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, displaySSMSaveScreenshot, NULL, NULL, displaySSMLoadScreenshot, NULL, this); @@ -607,6 +721,46 @@ int Display::registerSSM(PVM pVM) return VINF_SUCCESS; } +#ifdef VBOX_WITH_CROGL +int Display::crOglWindowsShow(bool fShow) +{ + if (!mfCrOglDataHidden == !!fShow) + return VINF_SUCCESS; + + if (!mhCrOglSvc) + { + /* no 3D */ +#ifdef DEBUG + BOOL is3denabled; + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + Assert(!is3denabled); +#endif + return VERR_INVALID_STATE; + } + + VMMDev *pVMMDev = mParent->getVMMDev(); + if (!pVMMDev) + { + AssertMsgFailed(("no vmmdev\n")); + return VERR_INVALID_STATE; + } + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_32BIT; + parm.u.uint32 = (uint32_t)fShow; + + int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_WINDOWS_SHOW, &parm, NULL, NULL); + if (RT_SUCCESS(rc)) + mfCrOglDataHidden = !fShow; + else + AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc)); + + return rc; +} +#endif + + // IEventListener method STDMETHODIMP Display::HandleEvent(IEvent * aEvent) { @@ -629,9 +783,20 @@ STDMETHODIMP Display::HandleEvent(IEvent * aEvent) LogRelFlowFunc(("Machine is running.\n")); mfMachineRunning = true; + +#ifdef VBOX_WITH_CROGL + crOglWindowsShow(true); +#endif } else + { mfMachineRunning = false; + +#ifdef VBOX_WITH_CROGL + if (machineState == MachineState_Paused) + crOglWindowsShow(false); +#endif + } break; } default: @@ -650,7 +815,7 @@ STDMETHODIMP Display::HandleEvent(IEvent * aEvent) static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId, ULONG pixelFormat, void *pvVRAM, uint32_t bpp, uint32_t cbLine, - int w, int h) + uint32_t w, uint32_t h) { Assert (pFramebuffer); @@ -662,13 +827,53 @@ static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId if (!finished) { - LogRelFlowFunc (("External framebuffer wants us to wait!\n")); + LogRelFlowFunc(("External framebuffer wants us to wait!\n")); return VINF_VGA_RESIZE_IN_PROGRESS; } return VINF_SUCCESS; } +int Display::notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM) +{ +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + BOOL is3denabled; + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + + if (is3denabled) + { + int rc = VERR_INVALID_STATE; + if (mhCrOglSvc) + { + VMMDev *pVMMDev = mParent->getVMMDev(); + if (pVMMDev) + { + CRVBOXHGCMDEVRESIZE *pData = (CRVBOXHGCMDEVRESIZE*)RTMemAlloc(sizeof (*pData)); + if (pData) + { + pData->Screen = *pScreen; + pData->pvVRAM = pvVRAM; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pData; + parm.u.pointer.size = sizeof (*pData); + + rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_DEV_RESIZE, &parm, displayCrAsyncCmdCompletion, this); + AssertRC(rc); + } + else + rc = VERR_NO_MEMORY; + } + } + + return rc; + } +#endif /* #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */ + return VINF_SUCCESS; +} + /** * Handles display resize event. * Disables access to VGA device; @@ -682,11 +887,11 @@ static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId * @thread EMT */ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM, - uint32_t cbLine, int w, int h, uint16_t flags) + uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags) { - LogRel (("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p " - "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n", - uScreenId, pvVRAM, w, h, bpp, cbLine, flags)); + LogRel(("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p " + "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n", + uScreenId, pvVRAM, w, h, bpp, cbLine, flags)); /* If there is no framebuffer, this call is not interesting. */ if ( uScreenId >= mcMonitors @@ -695,12 +900,15 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM return VINF_SUCCESS; } - mLastAddress = pvVRAM; - mLastBytesPerLine = cbLine; - mLastBitsPerPixel = bpp, - mLastWidth = w; - mLastHeight = h; - mLastFlags = flags; + if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + { + mLastAddress = pvVRAM; + mLastBytesPerLine = cbLine; + mLastBitsPerPixel = bpp; + mLastWidth = w; + mLastHeight = h; + mLastFlags = flags; + } ULONG pixelFormat; @@ -732,7 +940,7 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM * * Note: the resize information is only accessed on EMT so no serialization is required. */ - LogRel (("Display::handleDisplayResize(): Warning: resize postponed.\n")); + LogRel(("Display::handleDisplayResize(): Warning: resize postponed.\n")); maFramebuffers[uScreenId].pendingResize.fPending = true; maFramebuffers[uScreenId].pendingResize.pixelFormat = pixelFormat; @@ -746,6 +954,10 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM return VINF_VGA_RESIZE_IN_PROGRESS; } + /* Framebuffer will be invalid during resize, make sure that it is not accessed. */ + if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, false); + int rc = callFramebufferResize (maFramebuffers[uScreenId].pFramebuffer, uScreenId, pixelFormat, pvVRAM, bpp, cbLine, w, h); if (rc == VINF_VGA_RESIZE_IN_PROGRESS) @@ -810,11 +1022,17 @@ void Display::handleResizeCompletedEMT (void) continue; } + /* Inform VRDP server about the change of display parameters. + * Must be done before calling NotifyUpdate below. + */ + LogRelFlowFunc(("Calling VRDP\n")); + mParent->consoleVRDPServer()->SendResize(); + /* @todo Merge these two 'if's within one 'if (!pFBInfo->pFramebuffer.isNull())' */ if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull()) { /* Primary framebuffer has completed the resize. Update the connector data for VGA device. */ - updateDisplayData(); + int rc2 = updateDisplayData(); /* Check the framebuffer pixel format to setup the rendering in VGA device. */ BOOL usesGuestVRAM = FALSE; @@ -825,7 +1043,7 @@ void Display::handleResizeCompletedEMT (void) /* If the primary framebuffer is disabled, tell the VGA device to not to copy * pixels from VRAM to the framebuffer. */ - if (pFBInfo->fDisabled) + if (pFBInfo->fDisabled || RT_FAILURE(rc2)) mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, false); else mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, @@ -854,22 +1072,33 @@ void Display::handleResizeCompletedEMT (void) } LogRelFlow(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat)); -#ifdef DEBUG_sunlover - if (!stam) + /* Handle the case if there are some saved visible region that needs to be + * applied after the resize of the framebuffer is completed + */ + SaveSeamlessRectLock(); + PRTRECT pSavedVisibleRegion = pFBInfo->mpSavedVisibleRegion; + uint32_t cSavedVisibleRegion = pFBInfo->mcSavedVisibleRegion; + pFBInfo->mpSavedVisibleRegion = NULL; + pFBInfo->mcSavedVisibleRegion = 0; + SaveSeamlessRectUnLock(); + + if (pSavedVisibleRegion) { - /* protect mpVM */ - Console::SafeVMPtr pVM (mParent); - AssertComRC (pVM.rc()); + handleSetVisibleRegion(cSavedVisibleRegion, pSavedVisibleRegion); + RTMemFree(pSavedVisibleRegion); + } - STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates."); - stam = 1; +#ifdef DEBUG_sunlover + if (!g_stam) + { + Console::SafeVMPtr ptrVM(mParent); + AssertComRC(ptrVM.rc()); + STAMR3RegisterU(ptrVM.rawUVM(), &g_StatDisplayRefresh, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, + "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates."); + g_stam = 1; } #endif /* DEBUG_sunlover */ - /* Inform VRDP server about the change of display parameters. */ - LogRelFlowFunc (("Calling VRDP\n")); - mParent->consoleVRDPServer()->SendResize(); - #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) { BOOL is3denabled; @@ -884,7 +1113,16 @@ void Display::handleResizeCompletedEMT (void) VMMDev *pVMMDev = mParent->getVMMDev(); if (pVMMDev) + { +#if 0 + if (mhCrOglSvc) + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SCREEN_CHANGED, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); +#else pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); +#endif + } } } #endif /* VBOX_WITH_CROGL */ @@ -928,17 +1166,17 @@ unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int { DISPLAYFBINFO *pInfo = pInfos; unsigned uScreenId; - LogSunlover (("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph)); + LogSunlover(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph)); for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++) { - LogSunlover ((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h)); + LogSunlover((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h)); if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w) && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h)) { /* The rectangle belongs to the screen. Correct coordinates. */ *px -= pInfo->xOrigin; *py -= pInfo->yOrigin; - LogSunlover ((" -> %d,%d", *px, *py)); + LogSunlover((" -> %d,%d", *px, *py)); break; } } @@ -947,7 +1185,7 @@ unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int /* Map to primary screen. */ uScreenId = 0; } - LogSunlover ((" scr %d\n", uScreenId)); + LogSunlover((" scr %d\n", uScreenId)); return uScreenId; } @@ -967,7 +1205,7 @@ void Display::handleDisplayUpdateLegacy (int x, int y, int w, int h) unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h); #ifdef DEBUG_sunlover - LogFlowFunc (("%d,%d %dx%d (checked)\n", x, y, w, h)); + LogFlowFunc(("%d,%d %dx%d (checked)\n", x, y, w, h)); #endif /* DEBUG_sunlover */ handleDisplayUpdate (uScreenId, x, y, w, h); @@ -981,8 +1219,8 @@ void Display::handleDisplayUpdate (unsigned uScreenId, int x, int y, int w, int */ #ifdef DEBUG_sunlover - LogFlowFunc (("[%d] %d,%d %dx%d (%d,%d)\n", - uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy)); + LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n", + uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy)); #endif /* DEBUG_sunlover */ IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer; @@ -1041,7 +1279,7 @@ void Display::getFramebufferDimensions(int32_t *px1, int32_t *py1, return; /* If VBVA is not in use then this flag will not be set and this * will still work as it should. */ - if (!(maFramebuffers[0].fDisabled)) + if (!maFramebuffers[0].fDisabled) { x1 = (int32_t)maFramebuffers[0].xOrigin; y1 = (int32_t)maFramebuffers[0].yOrigin; @@ -1050,7 +1288,7 @@ void Display::getFramebufferDimensions(int32_t *px1, int32_t *py1, } for (unsigned i = 1; i < mcMonitors; ++i) { - if (!(maFramebuffers[i].fDisabled)) + if (!maFramebuffers[i].fDisabled) { x1 = RT_MIN(x1, maFramebuffers[i].xOrigin); y1 = RT_MIN(y1, maFramebuffers[i].yOrigin); @@ -1115,6 +1353,38 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) if (!pFBInfo->pFramebuffer.isNull()) { + if (pFBInfo->u32ResizeStatus != ResizeStatus_Void) + { + /* handle the case where new rectangles are received from the GA + * when framebuffer resizing is in progress. + * Just save the rectangles to be applied for later time when FB resizing is complete + * (from handleResizeCompletedEMT). + * This is done to prevent a race condition where a new rectangles are received + * from the GA after a resize event and framebuffer resizing is still in progress + * As a result the coordinates of the framebuffer are still + * not updated and hence there is no intersection with the new rectangles passed + * for the new region (THis is checked in the above if condition ). With 0 intersection, + * cRectVisibleRegions = 0 is returned to the GUI and if GUI has invalidated its + * earlier region then it draws nothihing and seamless mode doesn't display the + * guest desktop. + */ + SaveSeamlessRectLock(); + RTMemFree(pFBInfo->mpSavedVisibleRegion); + + pFBInfo->mpSavedVisibleRegion = (RTRECT *)RTMemAlloc( RT_MAX(cRect, 1) + * sizeof (RTRECT)); + if (pFBInfo->mpSavedVisibleRegion) + { + memcpy(pFBInfo->mpSavedVisibleRegion, pRect, cRect * sizeof(RTRECT)); + pFBInfo->mcSavedVisibleRegion = cRect; + } + else + { + pFBInfo->mcSavedVisibleRegion = 0; + } + SaveSeamlessRectUnLock(); + continue; + } /* Prepare a new array of rectangles which intersect with the framebuffer. */ RTRECT rectFramebuffer; @@ -1156,13 +1426,11 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) cRectVisibleRegion++; } } - pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion); } } -#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) - // @todo fix for multimonitor +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) BOOL is3denabled = FALSE; mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); @@ -1170,15 +1438,27 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) VMMDev *vmmDev = mParent->getVMMDev(); if (is3denabled && vmmDev) { - VBOXHGCMSVCPARM parms[2]; + if (mhCrOglSvc) + { + RTRECT *pRectsCopy = (RTRECT *)RTMemAlloc( RT_MAX(cRect, 1) + * sizeof (RTRECT)); + if (pRectsCopy) + { + memcpy(pRectsCopy, pRect, cRect * sizeof (RTRECT)); - parms[0].type = VBOX_HGCM_SVC_PARM_PTR; - parms[0].u.pointer.addr = pRect; - parms[0].u.pointer.size = 0; /* We don't actually care. */ - parms[1].type = VBOX_HGCM_SVC_PARM_32BIT; - parms[1].u.uint32 = cRect; + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pRectsCopy; + parm.u.pointer.size = cRect * sizeof (RTRECT); - vmmDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_VISIBLE_REGION, 2, &parms[0]); + vmmDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SET_VISIBLE_REGION, &parm, displayCrAsyncCmdCompletion, this); + } + else + AssertMsgFailed(("failed to allocate rects memory\n")); + } + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); } #endif @@ -1215,14 +1495,14 @@ static void vbvaRgnInit (VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, u { DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId]; - memset (&pFBInfo->dirtyRect, 0, sizeof (pFBInfo->dirtyRect)); + RT_ZERO(pFBInfo->dirtyRect); } } static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr) { - LogSunlover (("x = %d, y = %d, w = %d, h = %d\n", - phdr->x, phdr->y, phdr->w, phdr->h)); + LogSunlover(("x = %d, y = %d, w = %d, h = %d\n", + phdr->x, phdr->y, phdr->w, phdr->h)); /* * Here update rectangles are accumulated to form an update area. @@ -1396,6 +1676,17 @@ void Display::vbvaUnlock(void) RTCritSectLeave(&mVBVALock); } +int Display::SaveSeamlessRectLock(void) +{ + return RTCritSectEnter(&mSaveSeamlessRectLock); +} + +void Display::SaveSeamlessRectUnLock(void) +{ + RTCritSectLeave(&mSaveSeamlessRectLock); +} + + /** * @thread EMT */ @@ -1422,7 +1713,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) * Guest enabled acceleration at will. And it has to enable * acceleration after a mode change. */ - LogRelFlowFunc (("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", + LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", mfVideoAccelEnabled, fEnable, pVbvaMemory)); /* Strictly check parameters. Callers must not pass anything in the case. */ @@ -1439,7 +1730,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) { Assert (!mfVideoAccelEnabled); - LogRelFlowFunc (("Machine is not yet running.\n")); + LogRelFlowFunc(("Machine is not yet running.\n")); if (fEnable) { @@ -1507,7 +1798,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) LogRel(("VBVA: Disabled.\n")); } - LogRelFlowFunc (("VideoAccelEnable: rc = %Rrc.\n", rc)); + LogRelFlowFunc(("VideoAccelEnable: rc = %Rrc.\n", rc)); return rc; } @@ -1582,7 +1873,7 @@ static void vbvaFetchBytes (VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t c { if (cbDst >= VBVA_RING_BUFFER_SIZE) { - AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X", cbDst, VBVA_RING_BUFFER_SIZE)); + AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE)); return; } @@ -1662,8 +1953,8 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree; #ifdef DEBUG_sunlover - LogFlowFunc (("first = %d, free = %d\n", - indexRecordFirst, indexRecordFree)); + LogFlowFunc(("first = %d, free = %d\n", + indexRecordFirst, indexRecordFree)); #endif /* DEBUG_sunlover */ if (!vbvaVerifyRingBuffer (mpVbvaMemory)) @@ -1680,7 +1971,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst]; #ifdef DEBUG_sunlover - LogFlowFunc (("cbRecord = 0x%08X\n", pRecord->cbRecord)); + LogFlowFunc(("cbRecord = 0x%08X\n", pRecord->cbRecord)); #endif /* DEBUG_sunlover */ uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL; @@ -1691,7 +1982,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) Assert (mpu8VbvaPartial); - LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", + LogFlowFunc(("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree)); if (cbRecord > mcbVbvaPartial) @@ -1716,7 +2007,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover - LogFlowFunc (("partial done ok, data = %d, free = %d\n", + LogFlowFunc(("partial done ok, data = %d, free = %d\n", mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ } @@ -1736,7 +2027,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) return false; } - LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", + LogFlowFunc(("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree)); } @@ -1771,7 +2062,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) if (!dst) { - LogRelFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord)); + LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord)); mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; return false; } @@ -1781,7 +2072,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) *ppHdr = (VBVACMDHDR *)dst; #ifdef DEBUG_sunlover - LogFlowFunc (("Allocated from heap %p\n", dst)); + LogFlowFunc(("Allocated from heap %p\n", dst)); #endif /* DEBUG_sunlover */ } } @@ -1792,8 +2083,8 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover - LogFlowFunc (("done ok, data = %d, free = %d\n", - mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); + LogFlowFunc(("done ok, data = %d, free = %d\n", + mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ return true; @@ -1818,7 +2109,7 @@ void Display::vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd) /* The pointer is outside. It is then an allocated copy. */ #ifdef DEBUG_sunlover - LogFlowFunc (("Free heap %p\n", pHdr)); + LogFlowFunc(("Free heap %p\n", pHdr)); #endif /* DEBUG_sunlover */ if ((uint8_t *)pHdr == mpu8VbvaPartial) @@ -1855,7 +2146,7 @@ void Display::VideoAccelFlush (void) void Display::videoAccelFlush (void) { #ifdef DEBUG_sunlover_2 - LogFlowFunc (("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled)); + LogFlowFunc(("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled)); #endif /* DEBUG_sunlover_2 */ if (!mfVideoAccelEnabled) @@ -1868,7 +2159,7 @@ void Display::videoAccelFlush (void) Assert(mpVbvaMemory); #ifdef DEBUG_sunlover_2 - LogFlowFunc (("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n", + LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n", mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover_2 */ @@ -1911,8 +2202,8 @@ void Display::videoAccelFlush (void) if (cbCmd != 0) { #ifdef DEBUG_sunlover - LogFlowFunc (("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", - cbCmd, phdr->x, phdr->y, phdr->w, phdr->h)); + LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", + cbCmd, phdr->x, phdr->y, phdr->w, phdr->h)); #endif /* DEBUG_sunlover */ VBVACMDHDR hdrSaved = *phdr; @@ -2024,9 +2315,10 @@ int Display::videoAccelRefreshProcess(void) // IDisplay methods ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, - ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel) + ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel, + LONG *aXOrigin, LONG *aYOrigin) { - LogRelFlowFunc (("aScreenId = %d\n", aScreenId)); + LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2036,10 +2328,12 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, uint32_t u32Width = 0; uint32_t u32Height = 0; uint32_t u32BitsPerPixel = 0; + int32_t xOrigin = 0; + int32_t yOrigin = 0; if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) { - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); u32Width = mpDrv->IConnector.cx; u32Height = mpDrv->IConnector.cy; @@ -2052,6 +2346,8 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, u32Width = pFBInfo->w; u32Height = pFBInfo->h; u32BitsPerPixel = pFBInfo->u16BitsPerPixel; + xOrigin = pFBInfo->xOrigin; + yOrigin = pFBInfo->yOrigin; } else { @@ -2064,33 +2360,37 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, *aHeight = u32Height; if (aBitsPerPixel) *aBitsPerPixel = u32BitsPerPixel; + if (aXOrigin) + *aXOrigin = xOrigin; + if (aYOrigin) + *aYOrigin = yOrigin; return S_OK; } -STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, - IFramebuffer *aFramebuffer) +STDMETHODIMP Display::SetFramebuffer(ULONG aScreenId, IFramebuffer *aFramebuffer) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); if (aFramebuffer != NULL) CheckComArgOutPointerValid(aFramebuffer); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); - if (pVM.isOk()) + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) { /* Must release the lock here because the changeFramebuffer will * also obtain it. */ alock.release(); /* send request to the EMT thread */ - int vrc = VMR3ReqCallWait (pVM, VMCPUID_ANY, - (PFNRT) changeFramebuffer, 3, this, aFramebuffer, aScreenId); + int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)changeFramebuffer, 3, this, aFramebuffer, aScreenId); alock.acquire(); @@ -2113,7 +2413,16 @@ STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, alock.release(); if (pVMMDev) - vrc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); + { +#if 0 + if (mhCrOglSvc) + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SCREEN_CHANGED, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); +#else + pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); +#endif + } /*ComAssertRCRet (vrc, E_FAIL);*/ alock.acquire(); @@ -2131,10 +2440,10 @@ STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, return S_OK; } -STDMETHODIMP Display::GetFramebuffer (ULONG aScreenId, - IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin) +STDMETHODIMP Display::GetFramebuffer(ULONG aScreenId, + IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin) { - LogRelFlowFunc (("aScreenId = %d\n", aScreenId)); + LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); CheckComArgOutPointerValid(aFramebuffer); @@ -2169,13 +2478,7 @@ STDMETHODIMP Display::SetVideoModeHint(ULONG aDisplay, BOOL aEnabled, AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); - - /* XXX Ignore these parameters for now: */ - NOREF(aChangeOrigin); - NOREF(aOriginX); - NOREF(aOriginY); - NOREF(aEnabled); + CHECK_CONSOLE_DRV(mpDrv); /* * Do some rough checks for valid input @@ -2215,7 +2518,9 @@ STDMETHODIMP Display::SetVideoModeHint(ULONG aDisplay, BOOL aEnabled, { PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); if (pVMMDevPort) - pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel, aDisplay); + pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel, + aDisplay, aOriginX, aOriginY, + RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin)); } return S_OK; } @@ -2237,9 +2542,83 @@ STDMETHODIMP Display::SetSeamlessMode (BOOL enabled) if (pVMMDevPort) pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled); } + +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + if (!enabled) + { + BOOL is3denabled = FALSE; + + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + + VMMDev *vmmDev = mParent->getVMMDev(); + if (is3denabled && vmmDev) + { + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + /* NULL means disable */ + parm.u.pointer.addr = NULL; + parm.u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */ + + if (mhCrOglSvc) + vmmDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SET_VISIBLE_REGION, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); + + } + } +#endif return S_OK; } +#ifdef VBOX_WITH_CROGL +BOOL Display::displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, uint32_t u32Width, uint32_t u32Height) +{ + BOOL is3denabled; + pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData()) + { + VMMDev *pVMMDev = pDisplay->mParent->getVMMDev(); + if (pVMMDev) + { + CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof (*pScreenshot)); + if (pScreenshot) + { + /* screen id or CRSCREEN_ALL to specify all enabled */ + pScreenshot->u32Screen = aScreenId; + pScreenshot->u32Width = u32Width; + pScreenshot->u32Height = u32Height; + pScreenshot->u32Pitch = u32Width * 4; + pScreenshot->pvBuffer = pu8Data; + pScreenshot->pvContext = NULL; + pScreenshot->pfnScreenshotBegin = NULL; + pScreenshot->pfnScreenshotPerform = NULL; + pScreenshot->pfnScreenshotEnd = NULL; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pScreenshot; + parm.u.pointer.size = sizeof (*pScreenshot); + + int rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_TAKE_SCREENSHOT, 1, &parm); + + RTMemFree(pScreenshot); + + if (RT_SUCCESS(rc)) + return TRUE; + else + { + AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc)); + /* fall back to the non-3d mechanism */ + } + } + } + } + return FALSE; +} +#endif + int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height) { int rc; @@ -2287,15 +2666,15 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ uint32_t u32DstBitsPerPixel = 32; rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, - width, height, - pu8Src, - xSrc, ySrc, - u32SrcWidth, u32SrcHeight, - u32SrcLineSize, u32SrcBitsPerPixel, - pu8Dst, - xDst, yDst, - u32DstWidth, u32DstHeight, - u32DstLineSize, u32DstBitsPerPixel); + width, height, + pu8Src, + xSrc, ySrc, + u32SrcWidth, u32SrcHeight, + u32SrcLineSize, u32SrcBitsPerPixel, + pu8Dst, + xDst, yDst, + u32DstWidth, u32DstHeight, + u32DstLineSize, u32DstBitsPerPixel); if (RT_SUCCESS(rc)) { *ppu8Data = pu8Data; @@ -2306,6 +2685,14 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ else { RTMemFree(pu8Data); + + /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */ + if ( rc == VERR_INVALID_STATE + && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + { + rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, + ppu8Data, pcbData, pu32Width, pu32Height); + } } } } @@ -2327,7 +2714,8 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ return rc; } -static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, BYTE *address, ULONG width, ULONG height) +static int displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, + BYTE *address, ULONG width, ULONG height) { uint8_t *pu8Data = NULL; size_t cbData = 0; @@ -2335,6 +2723,11 @@ static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPL uint32_t cy = 0; int vrc = VINF_SUCCESS; +# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + if (Display::displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height)) + return VINF_SUCCESS; +#endif + int cRetries = 5; while (cRetries-- > 0) @@ -2342,8 +2735,8 @@ static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPL /* Note! Not sure if the priority call is such a good idea here, but it would be nice to have an accurate screenshot for the bug report if the VM deadlocks. */ - vrc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)Display::displayTakeScreenshotEMT, 6, - pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy); + vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::displayTakeScreenshotEMT, 6, + pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy); if (vrc != VERR_TRY_AGAIN) { break; @@ -2419,10 +2812,12 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV(mpDrv); + if (!mpDrv) + return E_FAIL; - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2435,7 +2830,7 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width */ alock.release(); - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, address, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, address, width, height); if (vrc == VERR_NOT_IMPLEMENTED) rc = setError(E_NOTIMPL, @@ -2447,7 +2842,7 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width rc = setError(VBOX_E_IPRT_ERROR, tr("Could not take a screenshot (%Rrc)"), vrc); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2471,10 +2866,12 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV(mpDrv); + if (!mpDrv) + return E_FAIL; - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2493,7 +2890,7 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG if (!pu8Data) return E_OUTOFMEMORY; - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, pu8Data, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, width, height); if (RT_SUCCESS(vrc)) { @@ -2523,7 +2920,7 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG RTMemFree(pu8Data); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2549,8 +2946,9 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2569,7 +2967,7 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO if (!pu8Data) return E_OUTOFMEMORY; - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, pu8Data, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, width, height); if (RT_SUCCESS(vrc)) { @@ -2605,25 +3003,149 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO RTMemFree(pu8Data); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } - -int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height) +int Display::VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens)) { - int rc = VINF_SUCCESS; - pDisplay->vbvaLock(); +#ifdef VBOX_WITH_VPX + com::SafeArray Screens(ComSafeArrayInArg(aScreens)); + for (unsigned i = 0; i < Screens.size(); i++) + maVideoRecEnabled[i] = RT_BOOL(Screens[i]); + return VINF_SUCCESS; +#else + return VERR_NOT_IMPLEMENTED; +#endif +} - DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId]; +/** + * Start video capturing. Does nothing if capturing is already active. + */ +int Display::VideoCaptureStart() +{ +#ifdef VBOX_WITH_VPX + if (VideoRecIsEnabled(mpVideoRecCtx)) + return VINF_SUCCESS; - if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + int rc = VideoRecContextCreate(&mpVideoRecCtx, mcMonitors); + if (RT_FAILURE(rc)) { - if (pFBInfo->u32ResizeStatus == ResizeStatus_Void) + LogFlow(("Failed to create video recording context (%Rrc)!\n", rc)); + return rc; + } + ComPtr pMachine = mParent->machine(); + com::SafeArray screens; + HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens)); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++) + maVideoRecEnabled[i] = i < screens.size() && screens[i]; + ULONG ulWidth; + hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulHeight; + hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulRate; + hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulFPS; + hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + BSTR strFile; + hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + RTTIMESPEC ts; + RTTimeNow(&ts); + RTTIME time; + RTTimeExplode(&time, &ts); + for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++) + { + char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str()); + char *pszExt = RTPathExt(pszAbsPath); + if (pszExt) + pszExt = RTStrDup(pszExt); + RTPathStripExt(pszAbsPath); + if (!pszAbsPath) + rc = VERR_INVALID_PARAMETER; + if (!pszExt) + pszExt = RTStrDup(".webm"); + char *pszName = NULL; + if (RT_SUCCESS(rc)) { - rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height); + if (mcMonitors > 1) + rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszExt); + else + rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszExt); } - } + if (RT_SUCCESS(rc)) + { + rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, + pszName, ulWidth, ulHeight, ulRate, ulFPS); + if (rc == VERR_ALREADY_EXISTS) + { + RTStrFree(pszName); + pszName = NULL; + + if (mcMonitors > 1) + rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s", + pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, + time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, + uScreen+1, pszExt); + else + rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s", + pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, + time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, + pszExt); + if (RT_SUCCESS(rc)) + rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, + pszName, ulWidth, ulHeight, ulRate, ulFPS); + } + } + + if (RT_SUCCESS(rc)) + LogRel(("WebM/VP8 video recording screen #%u with %ux%u @ %u kbps, %u fps to '%s' enabled.\n", + uScreen, ulWidth, ulHeight, ulRate, ulFPS, pszName)); + else + LogRel(("Failed to initialize video recording context #%u (%Rrc)!\n", uScreen, rc)); + RTStrFree(pszName); + RTStrFree(pszExt); + RTStrFree(pszAbsPath); + } + return rc; +#else + return VERR_NOT_IMPLEMENTED; +#endif +} + +/** + * Stop video capturing. Does nothing if video capturing is not active. + */ +void Display::VideoCaptureStop() +{ +#ifdef VBOX_WITH_VPX + if (VideoRecIsEnabled(mpVideoRecCtx)) + LogRel(("WebM/VP8 video recording stopped.\n")); + VideoRecContextClose(mpVideoRecCtx); + mpVideoRecCtx = NULL; +#endif +} + +int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, + ULONG x, ULONG y, ULONG width, ULONG height) +{ + int rc = VINF_SUCCESS; + pDisplay->vbvaLock(); + + DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId]; + + if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + { + if (pFBInfo->u32ResizeStatus == ResizeStatus_Void) + { + rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height); + } + } else if (aScreenId < pDisplay->mcMonitors) { /* Copy the bitmap to the guest VRAM. */ @@ -2661,7 +3183,7 @@ int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, * it to update. And for default format, render the guest VRAM to framebuffer. */ if ( pFBInfo->fDefaultFormat - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled) { address = NULL; HRESULT hrc = pFBInfo->pFramebuffer->COMGETTER(Address) (&address); @@ -2706,15 +3228,16 @@ int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, rc = VERR_INVALID_PARAMETER; } - if (RT_SUCCESS(rc) && pDisplay->maFramebuffers[aScreenId].u32ResizeStatus == ResizeStatus_Void) + if ( RT_SUCCESS(rc) + && pDisplay->maFramebuffers[aScreenId].u32ResizeStatus == ResizeStatus_Void) pDisplay->mParent->consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height); pDisplay->vbvaUnlock(); return rc; } -STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULONG y, - ULONG width, ULONG height) +STDMETHODIMP Display::DrawToScreen(ULONG aScreenId, BYTE *address, + ULONG x, ULONG y, ULONG width, ULONG height) { /// @todo (r=dmik) this function may take too long to complete if the VM // is doing something like saving state right now. Which, in case if it @@ -2722,7 +3245,7 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO // check the machine state here (by enclosing the check and VMRequCall // within the Console lock to make it atomic). - LogRelFlowFunc (("address=%p, x=%d, y=%d, width=%d, height=%d\n", + LogRelFlowFunc(("address=%p, x=%d, y=%d, width=%d, height=%d\n", (void *)address, x, y, width, height)); CheckComArgNotNull(address); @@ -2734,10 +3257,11 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); /* Release lock because the call scheduled on EMT may also try to take it. */ alock.release(); @@ -2746,8 +3270,8 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO * Again we're lazy and make the graphics device do all the * dirty conversion work. */ - int rcVBox = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)Display::drawToScreenEMT, 7, - this, aScreenId, address, x, y, width, height); + int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::drawToScreenEMT, 7, + this, aScreenId, address, x, y, width, height); /* * If the function returns not supported, we'll have to do all the @@ -2769,15 +3293,15 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO // handleDisplayUpdate (x, y, width, height); // } - LogRelFlowFunc (("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } -void Display::InvalidateAndUpdateEMT(Display *pDisplay) +void Display::InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll) { pDisplay->vbvaLock(); unsigned uScreenId; - for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) + for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++) { DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; @@ -2788,7 +3312,8 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) else { if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled + && pFBInfo->u32ResizeStatus == ResizeStatus_Void) { /* Render complete VRAM screen to the framebuffer. * When framebuffer uses VRAM directly, just notify it to update. @@ -2796,6 +3321,10 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) if (pFBInfo->fDefaultFormat) { BYTE *address = NULL; + ULONG uWidth = 0; + ULONG uHeight = 0; + pFBInfo->pFramebuffer->COMGETTER(Width) (&uWidth); + pFBInfo->pFramebuffer->COMGETTER(Height) (&uHeight); HRESULT hrc = pFBInfo->pFramebuffer->COMGETTER(Address) (&address); if (SUCCEEDED(hrc) && address != NULL) { @@ -2819,22 +3348,32 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) uint32_t u32DstLineSize = u32DstWidth * 4; uint32_t u32DstBitsPerPixel = 32; - pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, - width, height, - pu8Src, - xSrc, ySrc, - u32SrcWidth, u32SrcHeight, - u32SrcLineSize, u32SrcBitsPerPixel, - pu8Dst, - xDst, yDst, - u32DstWidth, u32DstHeight, - u32DstLineSize, u32DstBitsPerPixel); + /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h + * implies resize of Framebuffer is in progress and + * copyrect should not be called. + */ + if (uWidth == pFBInfo->w && uHeight == pFBInfo->h) + { + + pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, + width, height, + pu8Src, + xSrc, ySrc, + u32SrcWidth, u32SrcHeight, + u32SrcLineSize, u32SrcBitsPerPixel, + pu8Dst, + xDst, yDst, + u32DstWidth, u32DstHeight, + u32DstLineSize, u32DstBitsPerPixel); + } } } pDisplay->handleDisplayUpdate (uScreenId, 0, 0, pFBInfo->w, pFBInfo->h); } } + if (!fUpdateAll) + break; } pDisplay->vbvaUnlock(); } @@ -2854,28 +3393,29 @@ STDMETHODIMP Display::InvalidateAndUpdate() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; - LogRelFlowFunc (("Sending DPYUPDATE request\n")); + LogRelFlowFunc(("Sending DPYUPDATE request\n")); /* Have to release the lock when calling EMT. */ alock.release(); /* pdm.h says that this has to be called from the EMT thread */ - int rcVBox = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT, - 1, this); + int rcVBox = VMR3ReqCallVoidWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT, + 3, this, 0, true); alock.acquire(); if (RT_FAILURE(rcVBox)) rc = setError(VBOX_E_IPRT_ERROR, tr("Could not invalidate and update the screen (%Rrc)"), rcVBox); - LogRelFlowFunc (("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2887,7 +3427,7 @@ STDMETHODIMP Display::InvalidateAndUpdate() */ STDMETHODIMP Display::ResizeCompleted(ULONG aScreenId) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /// @todo (dmik) can we AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); here? // This will require general code review and may add some details. @@ -2926,33 +3466,33 @@ STDMETHODIMP Display::CompleteVHWACommand(BYTE *pCommand) STDMETHODIMP Display::ViewportChanged(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height) { #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + + if (mcMonitors <= aScreenId) + { + AssertMsgFailed(("invalid screen id\n")); + return E_INVALIDARG; + } + BOOL is3denabled; mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); if (is3denabled) { - VBOXHGCMSVCPARM aParms[5]; - - aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[0].u.uint32 = aScreenId; - - aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[1].u.uint32 = x; - - aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[2].u.uint32 = y; - - - aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[3].u.uint32 = width; - - aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[4].u.uint32 = height; - VMMDev *pVMMDev = mParent->getVMMDev(); if (pVMMDev) - pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_VIEWPORT_CHANGED, SHCRGL_CPARMS_VIEWPORT_CHANGED, aParms); + { + crViewportNotify(pVMMDev, aScreenId, x, y, width, height); + } + else + { + DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId]; + pFb->pendingViewportInfo.fPending = true; + pFb->pendingViewportInfo.x = x; + pFb->pendingViewportInfo.y = y; + pFb->pendingViewportInfo.width = width; + pFb->pendingViewportInfo.height = height; + } } #endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */ return S_OK; @@ -2966,15 +3506,15 @@ STDMETHODIMP Display::ViewportChanged(ULONG aScreenId, ULONG x, ULONG y, ULONG w * * @thread EMT */ -void Display::updateDisplayData(void) +int Display::updateDisplayData(void) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /* the driver might not have been constructed yet */ if (!mpDrv) - return; + return VINF_SUCCESS; -#if DEBUG +#ifdef VBOX_STRICT /* * Sanity check. Note that this method may be called on EMT after Console * has started the power down procedure (but before our #drvDestruct() is @@ -2983,9 +3523,12 @@ void Display::updateDisplayData(void) * build to save some ms (necessary to construct SafeVMPtrQuiet) in this * time-critical method. */ - Console::SafeVMPtrQuiet pVM (mParent); - if (pVM.isOk()) - VM_ASSERT_EMT (pVM.raw()); + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) + { + PVM pVM = VMR3GetVM(ptrVM.rawUVM()); + Assert(VM_IS_EMT(pVM)); + } #endif /* The method is only relevant to the primary framebuffer. */ @@ -3010,6 +3553,14 @@ void Display::updateDisplayData(void) rc = pFramebuffer->COMGETTER(Height) (&height); AssertComRC (rc); + if ( (width != mLastWidth && mLastWidth != 0) + || (height != mLastHeight && mLastHeight != 0)) + { + LogRel(("updateDisplayData: size mismatch w %d(%d) h %d(%d)\n", + width, mLastWidth, height, mLastHeight)); + return VERR_INVALID_STATE; + } + mpDrv->IConnector.pu8Data = (uint8_t *) address; mpDrv->IConnector.cbScanline = bytesPerLine; mpDrv->IConnector.cBits = bitsPerPixel; @@ -3025,8 +3576,57 @@ void Display::updateDisplayData(void) mpDrv->IConnector.cx = 0; mpDrv->IConnector.cy = 0; } - LogRelFlowFunc (("leave\n")); + LogRelFlowFunc(("leave\n")); + return VINF_SUCCESS; +} + +#ifdef VBOX_WITH_CROGL +void Display::crViewportNotify(VMMDev *pVMMDev, ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height) +{ +#if 0 + VBOXHGCMSVCPARM parm; + + CRVBOXHGCMVIEWPORT *pViewportInfo = (CRVBOXHGCMVIEWPORT*)RTMemAlloc(sizeof (*pViewportInfo)); + if(!pViewportInfo) + { + AssertMsgFailed(("RTMemAlloc failed!\n")); + return; + } + + pViewportInfo->u32Screen = aScreenId; + pViewportInfo->x = x; + pViewportInfo->y = y; + pViewportInfo->width = width; + pViewportInfo->height = height; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pViewportInfo; + parm.u.pointer.size = sizeof (*pViewportInfo); + + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_VIEWPORT_CHANGED2, &parm, displayCrAsyncCmdCompletion, this); +#else + VBOXHGCMSVCPARM aParms[5]; + + aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[0].u.uint32 = aScreenId; + + aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[1].u.uint32 = x; + + aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[2].u.uint32 = y; + + + aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[3].u.uint32 = width; + + aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[4].u.uint32 = height; + + pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_VIEWPORT_CHANGED, SHCRGL_CPARMS_VIEWPORT_CHANGED, aParms); +#endif } +#endif #ifdef VBOX_WITH_CRHGSMI void Display::setupCrHgsmiData(void) @@ -3041,8 +3641,8 @@ void Display::setupCrHgsmiData(void) { Assert(mhCrOglSvc); /* setup command completion callback */ - VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION Completion; - Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION; + VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion; + Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB; Completion.Hdr.cbCmd = sizeof (Completion); Completion.hCompletion = mpDrv->pVBVACallbacks; Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync; @@ -3054,7 +3654,23 @@ void Display::setupCrHgsmiData(void) rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm); if (RT_SUCCESS(rc)) + { + ULONG ul; + + for (ul = 0; ul < mcMonitors; ul++) + { + DISPLAYFBINFO *pFb = &maFramebuffers[ul]; + if (!pFb->pendingViewportInfo.fPending) + continue; + + crViewportNotify(pVMMDev, ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y, pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height); + pFb->pendingViewportInfo.fPending = false; + } + + mCrOglCallbacks = Completion.MainInterface; + return; + } AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc)); } @@ -3079,7 +3695,7 @@ void Display::destructCrHgsmiData(void) DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB, unsigned uScreenId) { - LogRelFlowFunc (("uScreenId = %d\n", uScreenId)); + LogRelFlowFunc(("uScreenId = %d\n", uScreenId)); AssertReturn(that, VERR_INVALID_PARAMETER); AssertReturn(uScreenId < that->mcMonitors, VERR_INVALID_PARAMETER); @@ -3137,7 +3753,7 @@ DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB, } } - LogRelFlowFunc (("leave\n")); + LogRelFlowFunc(("leave\n")); return VINF_SUCCESS; } @@ -3151,7 +3767,7 @@ DECLCALLBACK(int) Display::displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterfac { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n", + LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n", bpp, pvVRAM, cbLine, cx, cy)); return pDrv->pDisplay->handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE); @@ -3168,8 +3784,8 @@ DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterfa PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); #ifdef DEBUG_sunlover - LogFlowFunc (("mfVideoAccelEnabled = %d, %d,%d %dx%d\n", - pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy)); + LogFlowFunc(("mfVideoAccelEnabled = %d, %d,%d %dx%d\n", + pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy)); #endif /* DEBUG_sunlover */ /* This call does update regardless of VBVA status. @@ -3184,25 +3800,26 @@ DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterfa * Periodic display refresh callback. * * @see PDMIDISPLAYCONNECTOR::pfnRefresh + * @thread EMT */ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); #ifdef DEBUG_sunlover - STAM_PROFILE_START(&StatDisplayRefresh, a); + STAM_PROFILE_START(&g_StatDisplayRefresh, a); #endif /* DEBUG_sunlover */ #ifdef DEBUG_sunlover_2 - LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d\n", - pDrv->pDisplay->mfVideoAccelEnabled)); + LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n", + pDrv->pDisplay->mfVideoAccelEnabled)); #endif /* DEBUG_sunlover_2 */ Display *pDisplay = pDrv->pDisplay; bool fNoUpdate = false; /* Do not update the display if any of the framebuffers is being resized. */ unsigned uScreenId; - LogFlow(("DisplayRefreshCallback\n")); + Log2(("DisplayRefreshCallback\n")); for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) { DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; @@ -3214,7 +3831,7 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf if (u32ResizeStatus == ResizeStatus_UpdateDisplayData) { - LogRelFlowFunc (("ResizeStatus_UpdateDisplayData %d\n", uScreenId)); + LogRelFlowFunc(("ResizeStatus_UpdateDisplayData %d\n", uScreenId)); fNoUpdate = true; /* Always set it here, because pfnUpdateDisplayAll can cause a new resize. */ /* The framebuffer was resized and display data need to be updated. */ pDisplay->handleResizeCompletedEMT (); @@ -3226,12 +3843,12 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf /* Continue with normal processing because the status here is ResizeStatus_Void. * Repaint all displays because VM continued to run during the framebuffer resize. */ - pDisplay->InvalidateAndUpdateEMT(pDisplay); + pDisplay->InvalidateAndUpdateEMT(pDisplay, uScreenId, false); } else if (u32ResizeStatus == ResizeStatus_InProgress) { /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */ - LogRelFlowFunc (("ResizeStatus_InProcess\n")); + LogRelFlowFunc(("ResizeStatus_InProcess\n")); fNoUpdate = true; continue; } @@ -3275,72 +3892,94 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf } #ifdef VBOX_WITH_VPX - if (VideoRecIsEnabled(pDisplay->mpVideoRecContext)) - { - uint32_t u32VideoRecImgFormat = VPX_IMG_FMT_NONE; - ULONG ulGuestHeight = 0; - ULONG ulGuestWidth = 0; - ULONG ulBitsPerPixel; - int rc; - DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN]; - - if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled) - && pFBInfo->u32ResizeStatus == ResizeStatus_Void) - { - if (pFBInfo->fVBVAEnabled && pFBInfo->pu8FramebufferVRAM) - { - rc = VideoRecCopyToIntBuffer(pDisplay->mpVideoRecContext, 0, 0, - FramebufferPixelFormat_FOURCC_RGB, pFBInfo->u16BitsPerPixel, - pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h, - pFBInfo->pu8FramebufferVRAM); - ulGuestWidth = pFBInfo->w; - ulGuestHeight = pFBInfo->h; - ulBitsPerPixel = pFBInfo->u16BitsPerPixel; - } - else + if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx)) + { + do { +# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + BOOL is3denabled; + pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled) { - rc = VideoRecCopyToIntBuffer(pDisplay->mpVideoRecContext, 0, 0, - FramebufferPixelFormat_FOURCC_RGB, pDrv->IConnector.cBits, - pDrv->IConnector.cbScanline, pDrv->IConnector.cx, - pDrv->IConnector.cy, pDrv->IConnector.pu8Data); - ulGuestWidth = pDrv->IConnector.cx; - ulGuestHeight = pDrv->IConnector.cy; - ulBitsPerPixel = pDrv->IConnector.cBits; - } + if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE)) + { + if (pDisplay->mCrOglCallbacks.pfnHasData()) + { + /* submit */ + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = &pDisplay->mCrOglScreenshotData; + parm.u.pointer.size = sizeof (pDisplay->mCrOglScreenshotData); + + VMMDev *pVMMDev = pDisplay->mParent->getVMMDev(); + if (pVMMDev) + { + int rc = pVMMDev->hgcmHostFastCallAsync(pDisplay->mhCrOglSvc, SHCRGL_HOST_FN_TAKE_SCREENSHOT, &parm, displayVRecCompletion, pDisplay); + if (RT_SUCCESS(rc)) + break; + else + AssertMsgFailed(("hgcmHostFastCallAsync failed %f\n", rc)); + } + else + AssertMsgFailed(("no VMMDev\n")); + } - switch (ulBitsPerPixel) - { - case 32: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB32; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n")); - break; - case 24: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB24; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB24\n")); - break; - case 16: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB565; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB565\n")); - break; - default: - Log2(("No Proper Format detected\n")); + /* no 3D data available, or error has occured, + * go the straight way */ + ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE); + } + else + { + /* record request is still in progress, don't do anything */ break; + } } +# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */ - /* Just return in case of failure without any assertion */ - if( RT_SUCCESS(rc)) - if (RT_SUCCESS(VideoRecDoRGBToYUV(pDisplay->mpVideoRecContext, u32VideoRecImgFormat))) - VideoRecEncodeAndWrite(pDisplay->mpVideoRecContext, ulGuestWidth, ulGuestHeight); - } + uint64_t u64Now = RTTimeProgramMilliTS(); + for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) + { + if (!pDisplay->maVideoRecEnabled[uScreenId]) + continue; + + DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; + + if ( !pFBInfo->pFramebuffer.isNull() + && !pFBInfo->fDisabled + && pFBInfo->u32ResizeStatus == ResizeStatus_Void) + { + int rc; + if ( pFBInfo->fVBVAEnabled + && pFBInfo->pu8FramebufferVRAM) + { + rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, + FramebufferPixelFormat_FOURCC_RGB, + pFBInfo->u16BitsPerPixel, + pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h, + pFBInfo->pu8FramebufferVRAM, u64Now); + } + else + { + rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, + FramebufferPixelFormat_FOURCC_RGB, + pDrv->IConnector.cBits, + pDrv->IConnector.cbScanline, pDrv->IConnector.cx, + pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now); + } + if (rc == VINF_TRY_AGAIN) + break; + } + } + } while (0); } -#endif +#endif /* VBOX_WITH_VPX */ #ifdef DEBUG_sunlover - STAM_PROFILE_STOP(&StatDisplayRefresh, a); + STAM_PROFILE_STOP(&g_StatDisplayRefresh, a); #endif /* DEBUG_sunlover */ #ifdef DEBUG_sunlover_2 - LogFlowFunc (("leave\n")); + LogFlowFunc(("leave\n")); #endif /* DEBUG_sunlover_2 */ } @@ -3353,7 +3992,7 @@ DECLCALLBACK(void) Display::displayResetCallback(PPDMIDISPLAYCONNECTOR pInterfac { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /* Disable VBVA mode. */ pDrv->pDisplay->VideoAccelEnable (false, NULL); @@ -3368,7 +4007,7 @@ DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR p { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("fEnabled=%d\n", fEnabled)); + LogRelFlowFunc(("fEnabled=%d\n", fEnabled)); NOREF(fEnabled); @@ -3611,48 +4250,42 @@ DECLCALLBACK(void) Display::displayProcessDisplayDataCallback(PPDMIDISPLAYCONNEC #ifdef VBOX_WITH_VIDEOHWACCEL -void Display::handleVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) +#ifndef S_FALSE +# define S_FALSE ((HRESULT)1L) +#endif + +int Display::handleVHWACommandProcess(PVBOXVHWACMD pCommand) { unsigned id = (unsigned)pCommand->iDisplay; int rc = VINF_SUCCESS; - if (id < mcMonitors) - { - IFramebuffer *pFramebuffer = maFramebuffers[id].pFramebuffer; -#ifdef DEBUG_misha - Assert (pFramebuffer); -#endif + if (id >= mcMonitors) + return VERR_INVALID_PARAMETER; - if (pFramebuffer != NULL) - { - HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand); - if (FAILED(hr)) - { - rc = (hr == E_NOTIMPL) ? VERR_NOT_IMPLEMENTED : VERR_GENERAL_FAILURE; - } - } - else - { - rc = VERR_NOT_IMPLEMENTED; - } - } - else - { - rc = VERR_INVALID_PARAMETER; - } + ComPtr pFramebuffer; + AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS); + pFramebuffer = maFramebuffers[id].pFramebuffer; + arlock.release(); - if (RT_FAILURE(rc)) - { - /* tell the guest the command is complete */ - pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH); - pCommand->rc = rc; - } + if (pFramebuffer == NULL) + return VERR_INVALID_STATE; /* notify we can not handle request atm */ + + HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand); + if (hr == S_FALSE) + return VINF_SUCCESS; + else if (SUCCEEDED(hr)) + return VINF_CALLBACK_RETURN; + else if (hr == E_ACCESSDENIED) + return VERR_INVALID_STATE; /* notify we can not handle request atm */ + else if (hr == E_NOTIMPL) + return VERR_NOT_IMPLEMENTED; + return VERR_GENERAL_FAILURE; } -DECLCALLBACK(void) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) +DECLCALLBACK(int) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleVHWACommandProcess(pInterface, pCommand); + return pDrv->pDisplay->handleVHWACommandProcess(pCommand); } #endif @@ -3667,9 +4300,9 @@ void Display::handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Functio mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr, result); } -void Display::handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) +void Display::handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCmd; @@ -3695,9 +4328,9 @@ void Display::handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBO handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm); } -void Display::handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl) +void Display::handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCtl; @@ -3721,19 +4354,18 @@ void Display::handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBO handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm); } - DECLCALLBACK(void) Display::displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleCrHgsmiCommandProcess(pInterface, pCmd, cbCmd); + pDrv->pDisplay->handleCrHgsmiCommandProcess(pCmd, cbCmd); } DECLCALLBACK(void) Display::displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleCrHgsmiControlProcess(pInterface, pCmd, cbCmd); + pDrv->pDisplay->handleCrHgsmiControlProcess(pCmd, cbCmd); } DECLCALLBACK(void) Display::displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) @@ -3750,6 +4382,131 @@ DECLCALLBACK(void) Display::displayCrHgsmiControlCompletion(int32_t result, uint } #endif +DECLCALLBACK(void) Display::displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr; + if (pCmd->pfnInternal) + ((PFNCRCTLCOMPLETION)pCmd->pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext); +} + +int Display::handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + VMMDev *pVMMDev = mParent->getVMMDev(); + if (!pVMMDev) + { + AssertMsgFailed(("no vmmdev\n")); + return VERR_INVALID_STATE; + } + + Assert(mhCrOglSvc); + VBOXHGCMSVCPARM parm; + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pCmd; + parm.u.pointer.size = cbCmd; + + pCmd->pfnInternal = (void(*)())pfnCompletion; + int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, displayCrHgcmCtlSubmitCompletion, pvCompletion); + if (!RT_SUCCESS(rc)) + AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc)); + + return rc; +} + +DECLCALLBACK(int) Display::displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface, + struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); + Display *pThis = pDrv->pDisplay; + return pThis->handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion); +} + +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) +DECLCALLBACK(void) Display::displayCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Display *pDisplay = (Display *)pvContext; + pDisplay->handleCrAsyncCmdCompletion(result, u32Function, pParam); +} + + +void Display::handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam) +{ + if (pParam->type == VBOX_HGCM_SVC_PARM_PTR && pParam->u.pointer.addr) + RTMemFree(pParam->u.pointer.addr); +} + +bool Display::handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp) +{ +# if VBOX_WITH_VPX + return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp); +# else + return false; +# endif +} + +void Display::handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp) +{ +} + +void Display::handleCrVRecScreenshotPerform(uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uPixelFormat, + uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED); +# if VBOX_WITH_VPX + int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y, + uPixelFormat, + uBitsPerPixel, uBytesPerLine, + uGuestWidth, uGuestHeight, + pu8BufferAddress, u64TimeStamp); + Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/); +# endif +} + +void Display::handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED); + ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE); +} + +DECLCALLBACK(void) Display::displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen, + uint32_t x, uint32_t y, + uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + pDisplay->handleCrVRecScreenshotPerform(uScreen, + x, y, FramebufferPixelFormat_FOURCC_RGB, uBitsPerPixel, + uBytesPerLine, uGuestWidth, uGuestHeight, + pu8BufferAddress, u64TimeStamp); +} + +DECLCALLBACK(bool) Display::displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + return pDisplay->handleCrVRecScreenshotBegin(uScreen, u64TimeStamp); +} + +DECLCALLBACK(void) Display::displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + pDisplay->handleCrVRecScreenshotEnd(uScreen, u64TimeStamp); +} + +DECLCALLBACK(void) Display::displayVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Display *pDisplay = (Display *)pvContext; + pDisplay->handleVRecCompletion(result, u32Function, pParam, pvContext); +} + +#endif + #ifdef VBOX_WITH_HGSMI DECLCALLBACK(int) Display::displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags) @@ -3868,7 +4625,7 @@ DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInte pDrv->pUpPort->pfnUpdateDisplayRect (pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h); } else if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled) { /* Render VRAM content to the framebuffer. */ BYTE *address = NULL; @@ -3916,7 +4673,7 @@ DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInte pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin; /* @todo new SendUpdate entry which can get a separate cmd header or coords. */ - pThis->mParent->consoleVRDPServer()->SendUpdate (uScreenId, pCmd, cbCmd); + pThis->mParent->consoleVRDPServer()->SendUpdate (uScreenId, pCmd, (uint32_t)cbCmd); *pHdrUnconst = hdrSaved; } @@ -4078,14 +4835,18 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED) { + pThis->notifyCroglResize(pView, pScreen, pvVRAM); + pFBInfo->fDisabled = true; pFBInfo->flags = pScreen->u16Flags; - /* Temporary: ask framebuffer to resize using a default format. The framebuffer will be black. */ - pThis->handleDisplayResize(pScreen->u32ViewIndex, 0, - (uint8_t *)NULL, - pScreen->u32LineSize, pScreen->u32Width, - pScreen->u32Height, pScreen->u16Flags); + /* Ask the framebuffer to resize using a default format. The framebuffer will be black. + * So if the frontend does not support GuestMonitorChangedEventType_Disabled event, + * the VM window will be black. */ + uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640; + uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480; + pThis->handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0, + u32Width, u32Height, pScreen->u16Flags); fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), GuestMonitorChangedEventType_Disabled, @@ -4099,17 +4860,6 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c */ bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull(); - if (pFBInfo->fDisabled) - { - pFBInfo->fDisabled = false; - fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), - GuestMonitorChangedEventType_Enabled, - pScreen->u32ViewIndex, - pScreen->i32OriginX, pScreen->i32OriginY, - pScreen->u32Width, pScreen->u32Height); - /* Continue to update pFBInfo. */ - } - /* Check if this is a real resize or a notification about the screen origin. * The guest uses this VBVAResize call for both. */ @@ -4123,6 +4873,20 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX || pFBInfo->yOrigin != pScreen->i32OriginY; + if (fNewOrigin || fResize) + pThis->notifyCroglResize(pView, pScreen, pvVRAM); + + if (pFBInfo->fDisabled) + { + pFBInfo->fDisabled = false; + fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), + GuestMonitorChangedEventType_Enabled, + pScreen->u32ViewIndex, + pScreen->i32OriginX, pScreen->i32OriginY, + pScreen->u32Width, pScreen->u32Height); + /* Continue to update pFBInfo. */ + } + pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */ pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */ pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */ @@ -4148,34 +4912,13 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c 0, 0); } -#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) - if (fNewOrigin && !fResize) - { - BOOL is3denabled; - pThis->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); - - if (is3denabled) - { - VBOXHGCMSVCPARM parm; - - parm.type = VBOX_HGCM_SVC_PARM_32BIT; - parm.u.uint32 = pScreen->u32ViewIndex; - - VMMDev *pVMMDev = pThis->mParent->getVMMDev(); - - if (pVMMDev) - pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); - } - } -#endif /* VBOX_WITH_CROGL */ - if (!fResize) { /* No parameters of the framebuffer have actually changed. */ if (fNewOrigin) { /* VRDP server still need this notification. */ - LogRelFlowFunc (("Calling VRDP\n")); + LogRelFlowFunc(("Calling VRDP\n")); pThis->mParent->consoleVRDPServer()->SendResize(); } return VINF_SUCCESS; @@ -4244,23 +4987,26 @@ DECLCALLBACK(void *) Display::drvQueryInterface(PPDMIBASE pInterface, const cha */ DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns) { - PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); - LogRelFlowFunc (("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); + LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); - if (pData->pDisplay) + if (pThis->pDisplay) { - AutoWriteLock displayLock(pData->pDisplay COMMA_LOCKVAL_SRC_POS); + AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS); +#ifdef VBOX_WITH_VPX + pThis->pDisplay->VideoCaptureStop(); +#endif #ifdef VBOX_WITH_CRHGSMI - pData->pDisplay->destructCrHgsmiData(); + pThis->pDisplay->destructCrHgsmiData(); #endif - pData->pDisplay->mpDrv = NULL; - pData->pDisplay->mpVMMDev = NULL; - pData->pDisplay->mLastAddress = NULL; - pData->pDisplay->mLastBytesPerLine = 0; - pData->pDisplay->mLastBitsPerPixel = 0, - pData->pDisplay->mLastWidth = 0; - pData->pDisplay->mLastHeight = 0; + pThis->pDisplay->mpDrv = NULL; + pThis->pDisplay->mpVMMDev = NULL; + pThis->pDisplay->mLastAddress = NULL; + pThis->pDisplay->mLastBytesPerLine = 0; + pThis->pDisplay->mLastBitsPerPixel = 0, + pThis->pDisplay->mLastWidth = 0; + pThis->pDisplay->mLastHeight = 0; } } @@ -4272,9 +5018,9 @@ DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { - PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); - LogRelFlowFunc (("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); + LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. @@ -4288,44 +5034,45 @@ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint /* * Init Interfaces. */ - pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface; - - pData->IConnector.pfnResize = Display::displayResizeCallback; - pData->IConnector.pfnUpdateRect = Display::displayUpdateCallback; - pData->IConnector.pfnRefresh = Display::displayRefreshCallback; - pData->IConnector.pfnReset = Display::displayResetCallback; - pData->IConnector.pfnLFBModeChange = Display::displayLFBModeChangeCallback; - pData->IConnector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback; - pData->IConnector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback; + pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface; + + pThis->IConnector.pfnResize = Display::displayResizeCallback; + pThis->IConnector.pfnUpdateRect = Display::displayUpdateCallback; + pThis->IConnector.pfnRefresh = Display::displayRefreshCallback; + pThis->IConnector.pfnReset = Display::displayResetCallback; + pThis->IConnector.pfnLFBModeChange = Display::displayLFBModeChangeCallback; + pThis->IConnector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback; + pThis->IConnector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback; #ifdef VBOX_WITH_VIDEOHWACCEL - pData->IConnector.pfnVHWACommandProcess = Display::displayVHWACommandProcess; + pThis->IConnector.pfnVHWACommandProcess = Display::displayVHWACommandProcess; #endif #ifdef VBOX_WITH_CRHGSMI - pData->IConnector.pfnCrHgsmiCommandProcess = Display::displayCrHgsmiCommandProcess; - pData->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess; + pThis->IConnector.pfnCrHgsmiCommandProcess = Display::displayCrHgsmiCommandProcess; + pThis->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess; #endif + pThis->IConnector.pfnCrHgcmCtlSubmit = Display::displayCrHgcmCtlSubmit; #ifdef VBOX_WITH_HGSMI - pData->IConnector.pfnVBVAEnable = Display::displayVBVAEnable; - pData->IConnector.pfnVBVADisable = Display::displayVBVADisable; - pData->IConnector.pfnVBVAUpdateBegin = Display::displayVBVAUpdateBegin; - pData->IConnector.pfnVBVAUpdateProcess = Display::displayVBVAUpdateProcess; - pData->IConnector.pfnVBVAUpdateEnd = Display::displayVBVAUpdateEnd; - pData->IConnector.pfnVBVAResize = Display::displayVBVAResize; - pData->IConnector.pfnVBVAMousePointerShape = Display::displayVBVAMousePointerShape; + pThis->IConnector.pfnVBVAEnable = Display::displayVBVAEnable; + pThis->IConnector.pfnVBVADisable = Display::displayVBVADisable; + pThis->IConnector.pfnVBVAUpdateBegin = Display::displayVBVAUpdateBegin; + pThis->IConnector.pfnVBVAUpdateProcess = Display::displayVBVAUpdateProcess; + pThis->IConnector.pfnVBVAUpdateEnd = Display::displayVBVAUpdateEnd; + pThis->IConnector.pfnVBVAResize = Display::displayVBVAResize; + pThis->IConnector.pfnVBVAMousePointerShape = Display::displayVBVAMousePointerShape; #endif /* * Get the IDisplayPort interface of the above driver/device. */ - pData->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT); - if (!pData->pUpPort) + pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT); + if (!pThis->pUpPort) { AssertMsgFailed(("Configuration error: No display port interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; } #if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI) - pData->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS); - if (!pData->pVBVACallbacks) + pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS); + if (!pThis->pVBVACallbacks) { AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; @@ -4341,24 +5088,36 @@ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc)); return rc; } - pData->pDisplay = (Display *)pv; /** @todo Check this cast! */ - pData->pDisplay->mpDrv = pData; - + Display *pDisplay = (Display *)pv; /** @todo Check this cast! */ + pThis->pDisplay = pDisplay; + pThis->pDisplay->mpDrv = pThis; /* * Update our display information according to the framebuffer */ - pData->pDisplay->updateDisplayData(); + pDisplay->updateDisplayData(); /* * Start periodic screen refreshes */ - pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 20); + pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20); #ifdef VBOX_WITH_CRHGSMI - pData->pDisplay->setupCrHgsmiData(); + pDisplay->setupCrHgsmiData(); #endif - return VINF_SUCCESS; +#ifdef VBOX_WITH_VPX + ComPtr pMachine = pDisplay->mParent->machine(); + BOOL fEnabled = false; + HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + if (fEnabled) + { + rc = pDisplay->VideoCaptureStart(); + fireVideoCaptureChangedEvent(pDisplay->mParent->getEventSource()); + } +#endif + + return rc; } diff --git a/src/VBox/Main/src-client/EbmlWriter.cpp b/src/VBox/Main/src-client/EbmlWriter.cpp new file mode 100644 index 00000000..552e9d36 --- /dev/null +++ b/src/VBox/Main/src-client/EbmlWriter.cpp @@ -0,0 +1,504 @@ +/* $Id: EbmlWriter.cpp $ */ +/** @file + * EbmlWriter.cpp - EBML writer + WebM container + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * This code is based on: + * + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "EbmlWriter.h" +#include +#include +#include +#include + +static int ebml_Write(EbmlGlobal *glob, const void *pv, size_t cb) +{ + return RTFileWrite(glob->file, pv, cb, NULL); +} + +static int ebml_WriteU8(EbmlGlobal *glob, uint8_t u8) +{ + return ebml_Write(glob, &u8, 1); +} + +static int ebml_WriteU16(EbmlGlobal *glob, uint16_t u16) +{ + return ebml_Write(glob, &u16, 2); +} + +static int ebml_WriteU32(EbmlGlobal *glob, uint32_t u32) +{ + return ebml_Write(glob, &u32, 4); +} + +static int ebml_WriteU64(EbmlGlobal *glob, uint64_t u64) +{ + return ebml_Write(glob, &u64, 8); +} + +static int ebml_Serialize(EbmlGlobal *glob, const uint8_t *pb, size_t cb) +{ + for (; cb; cb--) + { + int rc = ebml_WriteU8(glob, pb[cb-1]); + if (RT_FAILURE(rc)) + return rc; + } + return VINF_SUCCESS; +} + +static int ebml_WriteID(EbmlGlobal *glob, uint32_t class_id) +{ + int rc; + if (class_id >= 0x01000000) + rc = ebml_WriteU32(glob, RT_H2BE_U32(class_id)); + else if (class_id >= 0x00010000) + rc = ebml_Serialize(glob, (uint8_t*)&class_id, 3); + else if (class_id >= 0x00000100) + rc = ebml_WriteU16(glob, RT_H2BE_U16((uint16_t)class_id)); + else + rc = ebml_WriteU8(glob, (uint8_t)class_id); + return rc; +} + +static int ebml_SerializeUnsigned32(EbmlGlobal *glob, uint32_t class_id, uint32_t ui) +{ + int rc = ebml_WriteID(glob, class_id); + rc = ebml_WriteU8(glob, 4 | 0x80); + if (RT_SUCCESS(rc)) + rc = ebml_WriteU32(glob, RT_H2BE_U32(ui)); + return rc; +} + +static int ebml_StartSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc, uint32_t class_id) +{ + // todo this is always taking 8 bytes, this may need later optimization + // this is a key that says lenght unknown + uint64_t unknownLen = UINT64_C(0x01FFFFFFFFFFFFFF); + + ebml_WriteID(glob, class_id); + *ebmlLoc = RTFileTell(glob->file); + return ebml_WriteU64(glob, RT_H2BE_U64(unknownLen)); +} + +static int ebml_EndSubElement(EbmlGlobal *glob, uint64_t ebmlLoc) +{ + /* Save the current file pointer */ + uint64_t pos = RTFileTell(glob->file); + + /* Calculate the size of this element */ + uint64_t size = pos - ebmlLoc - 8; + size |= UINT64_C(0x0100000000000000); + + /* Seek back to the beginning of the element and write the new size */ + RTFileSeek(glob->file, ebmlLoc, RTFILE_SEEK_BEGIN, NULL); + int rc = ebml_WriteU64(glob, RT_H2BE_U64(size)); + + /* Reset the file pointer */ + RTFileSeek(glob->file, pos, RTFILE_SEEK_BEGIN, NULL); + + return rc; +} + +static int ebml_WriteLen(EbmlGlobal *glob, uint64_t val) +{ + //TODO check and make sure we are not > than 0x0100000000000000LLU + size_t size = 8; + uint64_t minVal = UINT64_C(0x00000000000000ff); //mask to compare for byte size + + for (size = 1; size < 8; size ++) + { + if (val < minVal) + break; + + minVal = (minVal << 7); + } + + val |= (UINT64_C(0x000000000000080) << ((size - 1) * 7)); + + return ebml_Serialize(glob, (uint8_t *)&val, size); +} + +static int ebml_WriteString(EbmlGlobal *glob, const char *str) +{ + const size_t cb = strlen(str); + int rc = ebml_WriteLen(glob, cb); + //TODO: it's not clear from the spec whether the nul terminator + //should be serialized too. For now we omit the null terminator. + if (RT_SUCCESS(rc)) + rc = ebml_Write(glob, str, cb); + return rc; +} + +int Ebml_SerializeUnsigned64(EbmlGlobal *glob, uint32_t class_id, uint64_t ui) +{ + int rc = ebml_WriteID(glob, class_id); + if (RT_SUCCESS(rc)) + rc = ebml_WriteU8(glob, 8 | 0x80); + if (RT_SUCCESS(rc)) + rc = ebml_WriteU64(glob, RT_H2BE_U64(ui)); + return rc; +} + +int Ebml_SerializeUnsigned(EbmlGlobal *glob, uint32_t class_id, uint32_t ui) +{ + int rc = ebml_WriteID(glob, class_id); + if (RT_FAILURE(rc)) + return rc; + + uint32_t minVal = 0x7fLU; //mask to compare for byte size + size_t size = 8; //size in bytes to output + for (size = 1; size < 4; size ++) + { + if (ui < minVal) + break; + + minVal <<= 7; + } + + rc = ebml_WriteU8(glob, 0x80 | size); + if (RT_SUCCESS(rc)) + rc = ebml_Serialize(glob, (uint8_t*)&ui, size); + return rc; +} + +//TODO: perhaps this is a poor name for this id serializer helper function +int Ebml_SerializeBinary(EbmlGlobal *glob, uint32_t class_id, uint32_t bin) +{ + int size; + for (size = 4; size > 1; size--) + { + if (bin & 0x000000ff << ((size-1) * 8)) + break; + } + int rc = ebml_WriteID(glob, class_id); + if (RT_SUCCESS(rc)) + rc = ebml_WriteLen(glob, size); + if (RT_SUCCESS(rc)) + rc = ebml_WriteID(glob, bin); + return rc; +} + +int Ebml_SerializeFloat(EbmlGlobal *glob, uint32_t class_id, double d) +{ + int rc = ebml_WriteID(glob, class_id); + if (RT_SUCCESS(rc)) + rc = ebml_WriteU8(glob, 0x80 | 8); + if (RT_SUCCESS(rc)) + rc = ebml_WriteU64(glob, RT_H2BE_U64(*(uint64_t*)&d)); + return rc; +} + +int Ebml_SerializeString(EbmlGlobal *glob, uint32_t class_id, const char *s) +{ + int rc = ebml_WriteID(glob, class_id); + if (RT_SUCCESS(rc)) + rc = ebml_WriteString(glob, s); + return rc; +} + +int Ebml_WriteWebMSeekElement(EbmlGlobal *ebml, uint32_t id, uint64_t pos) +{ + uint64_t offset = pos - ebml->position_reference; + uint64_t start; + int rc = ebml_StartSubElement(ebml, &start, Seek); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeBinary(ebml, SeekID, id); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned64(ebml, SeekPosition, offset); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(ebml, start); + return rc; +} + +int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml) +{ + int rc = VINF_SUCCESS; + + /* Save the current file pointer */ + uint64_t pos = RTFileTell(ebml->file); + + if (ebml->seek_info_pos) + rc = RTFileSeek(ebml->file, ebml->seek_info_pos, RTFILE_SEEK_BEGIN, NULL); + else + ebml->seek_info_pos = pos; + + { + uint64_t start; + + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(ebml, &start, SeekHead); + if (RT_SUCCESS(rc)) + rc = Ebml_WriteWebMSeekElement(ebml, Tracks, ebml->track_pos); + if (RT_SUCCESS(rc)) + rc = Ebml_WriteWebMSeekElement(ebml, Cues, ebml->cue_pos); + if (RT_SUCCESS(rc)) + rc = Ebml_WriteWebMSeekElement(ebml, Info, ebml->segment_info_pos); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(ebml, start); + } + { + //segment info + uint64_t startInfo; + uint64_t frame_time; + + frame_time = (uint64_t)1000 * ebml->framerate.den / ebml->framerate.num; + ebml->segment_info_pos = RTFileTell(ebml->file); + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(ebml, &startInfo, Info); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeFloat(ebml, Segment_Duration, + (double)(ebml->last_pts_ms + frame_time)); + char szVersion[64]; + RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%", + ebml->debug ? vpx_codec_version_str() : ""); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeString(ebml, MuxingApp, szVersion); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeString(ebml, WritingApp, szVersion); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(ebml, startInfo); + } + return rc; +} + +int Ebml_WriteWebMFileHeader(EbmlGlobal *glob, + const vpx_codec_enc_cfg_t *cfg, + const struct vpx_rational *fps) +{ + int rc = VINF_SUCCESS; + { + uint64_t start; + rc = ebml_StartSubElement(glob, &start, EBML); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, EBMLVersion, 1); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeString(glob, DocType, "webm"); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, start); + } + { + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &glob->startSegment, Segment); + glob->position_reference = RTFileTell(glob->file); + glob->framerate = *fps; + if (RT_SUCCESS(rc)) + rc = Ebml_WriteWebMSeekInfo(glob); + { + uint64_t trackStart; + glob->track_pos = RTFileTell(glob->file); + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &trackStart, Tracks); + { + uint32_t trackNumber = 1; + uint32_t trackID = 0; + + uint64_t start; + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &start, TrackEntry); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); + glob->track_id_pos = RTFileTell(glob->file); + ebml_SerializeUnsigned32(glob, TrackUID, trackID); + Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 + Ebml_SerializeString(glob, CodecID, "V_VP8"); + { + uint64_t videoStart; + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &videoStart, Video); + uint32_t pixelWidth = cfg->g_w; + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); + uint32_t pixelHeight = cfg->g_h; + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); + double frameRate = (double)fps->num / (double)fps->den; + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeFloat(glob, FrameRate, frameRate); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, videoStart); + } + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, start); //Track Entry + } + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, trackStart); + } + // segment element is open + } + return rc; +} + +int Ebml_WriteWebMBlock(EbmlGlobal *glob, + const vpx_codec_enc_cfg_t *cfg, + const vpx_codec_cx_pkt_t *pkt) +{ + uint16_t block_timecode = 0; + int64_t pts_ms; + int start_cluster = 0; + int rc = VINF_SUCCESS; + + /* Calculate the PTS of this frame in milliseconds */ + pts_ms = pkt->data.frame.pts * 1000 + * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; + if (pts_ms <= glob->last_pts_ms) + pts_ms = glob->last_pts_ms + 1; + glob->last_pts_ms = pts_ms; + + /* Calculate the relative time of this block */ + if (pts_ms - glob->cluster_timecode > 65536) + start_cluster = 1; + else + block_timecode = (uint16_t)(pts_ms - glob->cluster_timecode); + + int fKeyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); + if (start_cluster || fKeyframe) + { + if (glob->cluster_open) + rc = ebml_EndSubElement(glob, glob->startCluster); + + /* Open the new cluster */ + block_timecode = 0; + glob->cluster_open = 1; + glob->cluster_timecode = (uint32_t)pts_ms; + glob->cluster_pos = RTFileTell(glob->file); + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); + + /* Save a cue point if this is a keyframe. */ + if (fKeyframe) + { + struct cue_entry *cue; + + glob->cue_list = (cue_entry*)RTMemRealloc(glob->cue_list, (glob->cues+1) * sizeof(cue_entry)); + cue = &glob->cue_list[glob->cues]; + cue->time = glob->cluster_timecode; + cue->loc = glob->cluster_pos; + glob->cues++; + } + } + + /* Write the Simple Block */ + if (RT_SUCCESS(rc)) + rc = ebml_WriteID(glob, SimpleBlock); + + uint32_t block_length = pkt->data.frame.sz + 4; + block_length |= 0x10000000; + if (RT_SUCCESS(rc)) + rc = ebml_WriteU32(glob, RT_H2BE_U32(block_length)); + + uint8_t track_number = 0x80 | 1; + if (RT_SUCCESS(rc)) + rc = ebml_WriteU8(glob, track_number); + + if (RT_SUCCESS(rc)) + rc = ebml_WriteU16(glob, RT_H2BE_U16(block_timecode)); + + uint8_t flags = 0; + if (fKeyframe) + flags |= 0x80; + if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) + flags |= 0x08; + if (RT_SUCCESS(rc)) + rc = ebml_WriteU8(glob, flags); + + if (RT_SUCCESS(rc)) + rc = ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz); + + return rc; +} + +int Ebml_WriteWebMFileFooter(EbmlGlobal *glob, long hash) +{ + int rc = VINF_SUCCESS; + if (glob->cluster_open) + rc = ebml_EndSubElement(glob, glob->startCluster); + + { + uint64_t start; + + glob->cue_pos = RTFileTell(glob->file); + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &start, Cues); + for (unsigned i = 0; i < glob->cues; i++) + { + struct cue_entry *cue = &glob->cue_list[i]; + uint64_t startSub; + + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &startSub, CuePoint); + { + uint64_t startSubsub; + + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, CueTime, cue->time); + if (RT_SUCCESS(rc)) + rc = ebml_StartSubElement(glob, &startSubsub, CueTrackPositions); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned(glob, CueTrack, 1); + if (RT_SUCCESS(rc)) + rc = Ebml_SerializeUnsigned64(glob, CueClusterPosition, + cue->loc - glob->position_reference); + //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber); + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, startSubsub); + } + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, startSub); + } + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, start); + } + + if (RT_SUCCESS(rc)) + rc = ebml_EndSubElement(glob, glob->startSegment); + + /* Patch up the seek info block */ + if (RT_SUCCESS(rc)) + rc = Ebml_WriteWebMSeekInfo(glob); + + /* Patch up the track id */ + if (RT_SUCCESS(rc)) + rc = RTFileSeek(glob->file, glob->track_id_pos, RTFILE_SEEK_BEGIN, NULL); + if (RT_SUCCESS(rc)) + rc = ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); + + if (RT_SUCCESS(rc)) + rc = RTFileSeek(glob->file, 0, RTFILE_SEEK_END, NULL); + return rc; +} diff --git a/src/VBox/Main/src-client/EbmlWriter.h b/src/VBox/Main/src-client/EbmlWriter.h new file mode 100644 index 00000000..e24740c1 --- /dev/null +++ b/src/VBox/Main/src-client/EbmlWriter.h @@ -0,0 +1,291 @@ +/* $Id: EbmlWriter.h $ */ +/** @file + * EbmlWriter.h - EBML writer + WebM container. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * This code is based on: + * + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ____EBMLWRITER +#define ____EBMLWRITER + +#include +#include + +enum mkv +{ + EBML = 0x1A45DFA3, + EBMLVersion = 0x4286, + EBMLReadVersion = 0x42F7, + EBMLMaxIDLength = 0x42F2, + EBMLMaxSizeLength = 0x42F3, + DocType = 0x4282, + DocTypeVersion = 0x4287, + DocTypeReadVersion = 0x4285, +// CRC_32 = 0xBF, + Void = 0xEC, + SignatureSlot = 0x1B538667, + SignatureAlgo = 0x7E8A, + SignatureHash = 0x7E9A, + SignaturePublicKey = 0x7EA5, + Signature = 0x7EB5, + SignatureElements = 0x7E5B, + SignatureElementList = 0x7E7B, + SignedElement = 0x6532, + //segment + Segment = 0x18538067, + //Meta Seek Information + SeekHead = 0x114D9B74, + Seek = 0x4DBB, + SeekID = 0x53AB, + SeekPosition = 0x53AC, + //Segment Information + Info = 0x1549A966, +// SegmentUID = 0x73A4, +// SegmentFilename = 0x7384, +// PrevUID = 0x3CB923, +// PrevFilename = 0x3C83AB, +// NextUID = 0x3EB923, +// NextFilename = 0x3E83BB, +// SegmentFamily = 0x4444, +// ChapterTranslate = 0x6924, +// ChapterTranslateEditionUID = 0x69FC, +// ChapterTranslateCodec = 0x69BF, +// ChapterTranslateID = 0x69A5, + TimecodeScale = 0x2AD7B1, + Segment_Duration = 0x4489, + DateUTC = 0x4461, +// Title = 0x7BA9, + MuxingApp = 0x4D80, + WritingApp = 0x5741, + //Cluster + Cluster = 0x1F43B675, + Timecode = 0xE7, +// SilentTracks = 0x5854, +// SilentTrackNumber = 0x58D7, +// Position = 0xA7, + PrevSize = 0xAB, + BlockGroup = 0xA0, + Block = 0xA1, +// BlockVirtual = 0xA2, +// BlockAdditions = 0x75A1, +// BlockMore = 0xA6, +// BlockAddID = 0xEE, +// BlockAdditional = 0xA5, + BlockDuration = 0x9B, +// ReferencePriority = 0xFA, + ReferenceBlock = 0xFB, +// ReferenceVirtual = 0xFD, +// CodecState = 0xA4, +// Slices = 0x8E, +// TimeSlice = 0xE8, + LaceNumber = 0xCC, +// FrameNumber = 0xCD, +// BlockAdditionID = 0xCB, +// MkvDelay = 0xCE, +// Cluster_Duration = 0xCF, + SimpleBlock = 0xA3, +// EncryptedBlock = 0xAF, + //Track + Tracks = 0x1654AE6B, + TrackEntry = 0xAE, + TrackNumber = 0xD7, + TrackUID = 0x73C5, + TrackType = 0x83, + FlagEnabled = 0xB9, + FlagDefault = 0x88, + FlagForced = 0x55AA, + FlagLacing = 0x9C, +// MinCache = 0x6DE7, +// MaxCache = 0x6DF8, + DefaultDuration = 0x23E383, +// TrackTimecodeScale = 0x23314F, +// TrackOffset = 0x537F, +// MaxBlockAdditionID = 0x55EE, + Name = 0x536E, + Language = 0x22B59C, + CodecID = 0x86, + CodecPrivate = 0x63A2, + CodecName = 0x258688, +// AttachmentLink = 0x7446, +// CodecSettings = 0x3A9697, +// CodecInfoURL = 0x3B4040, +// CodecDownloadURL = 0x26B240, +// CodecDecodeAll = 0xAA, +// TrackOverlay = 0x6FAB, +// TrackTranslate = 0x6624, +// TrackTranslateEditionUID = 0x66FC, +// TrackTranslateCodec = 0x66BF, +// TrackTranslateTrackID = 0x66A5, + //video + Video = 0xE0, + FlagInterlaced = 0x9A, +// StereoMode = 0x53B8, + PixelWidth = 0xB0, + PixelHeight = 0xBA, + PixelCropBottom = 0x54AA, + PixelCropTop = 0x54BB, + PixelCropLeft = 0x54CC, + PixelCropRight = 0x54DD, + DisplayWidth = 0x54B0, + DisplayHeight = 0x54BA, + DisplayUnit = 0x54B2, + AspectRatioType = 0x54B3, +// ColourSpace = 0x2EB524, +// GammaValue = 0x2FB523, + FrameRate = 0x2383E3, + //end video + //audio + Audio = 0xE1, + SamplingFrequency = 0xB5, + OutputSamplingFrequency = 0x78B5, + Channels = 0x9F, +// ChannelPositions = 0x7D7B, + BitDepth = 0x6264, + //end audio + //content encoding +// ContentEncodings = 0x6d80, +// ContentEncoding = 0x6240, +// ContentEncodingOrder = 0x5031, +// ContentEncodingScope = 0x5032, +// ContentEncodingType = 0x5033, +// ContentCompression = 0x5034, +// ContentCompAlgo = 0x4254, +// ContentCompSettings = 0x4255, +// ContentEncryption = 0x5035, +// ContentEncAlgo = 0x47e1, +// ContentEncKeyID = 0x47e2, +// ContentSignature = 0x47e3, +// ContentSigKeyID = 0x47e4, +// ContentSigAlgo = 0x47e5, +// ContentSigHashAlgo = 0x47e6, + //end content encoding + //Cueing Data + Cues = 0x1C53BB6B, + CuePoint = 0xBB, + CueTime = 0xB3, + CueTrackPositions = 0xB7, + CueTrack = 0xF7, + CueClusterPosition = 0xF1, + CueBlockNumber = 0x5378 +// CueCodecState = 0xEA, +// CueReference = 0xDB, +// CueRefTime = 0x96, +// CueRefCluster = 0x97, +// CueRefNumber = 0x535F, +// CueRefCodecState = 0xEB, + //Attachment +// Attachments = 0x1941A469, +// AttachedFile = 0x61A7, +// FileDescription = 0x467E, +// FileName = 0x466E, +// FileMimeType = 0x4660, +// FileData = 0x465C, +// FileUID = 0x46AE, +// FileReferral = 0x4675, + //Chapters +// Chapters = 0x1043A770, +// EditionEntry = 0x45B9, +// EditionUID = 0x45BC, +// EditionFlagHidden = 0x45BD, +// EditionFlagDefault = 0x45DB, +// EditionFlagOrdered = 0x45DD, +// ChapterAtom = 0xB6, +// ChapterUID = 0x73C4, +// ChapterTimeStart = 0x91, +// ChapterTimeEnd = 0x92, +// ChapterFlagHidden = 0x98, +// ChapterFlagEnabled = 0x4598, +// ChapterSegmentUID = 0x6E67, +// ChapterSegmentEditionUID = 0x6EBC, +// ChapterPhysicalEquiv = 0x63C3, +// ChapterTrack = 0x8F, +// ChapterTrackNumber = 0x89, +// ChapterDisplay = 0x80, +// ChapString = 0x85, +// ChapLanguage = 0x437C, +// ChapCountry = 0x437E, +// ChapProcess = 0x6944, +// ChapProcessCodecID = 0x6955, +// ChapProcessPrivate = 0x450D, +// ChapProcessCommand = 0x6911, +// ChapProcessTime = 0x6922, +// ChapProcessData = 0x6933, + //Tagging +// Tags = 0x1254C367, +// Tag = 0x7373, +// Targets = 0x63C0, +// TargetTypeValue = 0x68CA, +// TargetType = 0x63CA, +// Tagging_TrackUID = 0x63C5, +// Tagging_EditionUID = 0x63C9, +// Tagging_ChapterUID = 0x63C4, +// AttachmentUID = 0x63C6, +// SimpleTag = 0x67C8, +// TagName = 0x45A3, +// TagLanguage = 0x447A, +// TagDefault = 0x4484, +// TagString = 0x4487, +// TagBinary = 0x4485, +}; + +struct cue_entry +{ + uint32_t time; + uint64_t loc; +}; + +struct EbmlGlobal +{ + int debug; + RTFILE file; + int64_t last_pts_ms; + vpx_rational_t framerate; + + uint64_t position_reference; + uint64_t seek_info_pos; + uint64_t segment_info_pos; + uint64_t track_pos; + uint64_t cue_pos; + uint64_t cluster_pos; + + uint64_t track_id_pos; + + uint64_t startSegment; + uint64_t startCluster; + + uint32_t cluster_timecode; + int cluster_open; + + struct cue_entry *cue_list; + unsigned int cues; +}; + +int Ebml_WriteWebMSeekElement(EbmlGlobal *ebml, uint32_t id, uint64_t pos); +int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml); +int Ebml_WriteWebMFileHeader(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps); +int Ebml_WriteWebMBlock(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const vpx_codec_cx_pkt_t *pkt); +int Ebml_WriteWebMFileFooter(EbmlGlobal *glob, long hash); + +#endif diff --git a/src/VBox/Main/src-client/EmulatedUSBImpl.cpp b/src/VBox/Main/src-client/EmulatedUSBImpl.cpp new file mode 100644 index 00000000..8c8aa8fd --- /dev/null +++ b/src/VBox/Main/src-client/EmulatedUSBImpl.cpp @@ -0,0 +1,692 @@ +/* $Id: EmulatedUSBImpl.cpp $ */ +/** @file + * + * Emulated USB manager implementation. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_MAIN_EMULATEDUSB + +#include "EmulatedUSBImpl.h" +#include "ConsoleImpl.h" +#include "Logging.h" + +#include + + +/* + * Emulated USB webcam device instance. + */ +typedef std::map EUSBSettingsMap; + +typedef enum EUSBDEVICESTATUS +{ + EUSBDEVICE_CREATED, + EUSBDEVICE_ATTACHING, + EUSBDEVICE_ATTACHED +} EUSBDEVICESTATUS; + +class EUSBWEBCAM /* : public EUSBDEVICE */ +{ + private: + int32_t volatile mcRefs; + + EmulatedUSB *mpEmulatedUSB; + + RTUUID mUuid; + char mszUuid[RTUUID_STR_LENGTH]; + + Utf8Str mPath; + Utf8Str mSettings; + + EUSBSettingsMap mDevSettings; + EUSBSettingsMap mDrvSettings; + + void *mpvObject; + + static DECLCALLBACK(int) emulatedWebcamAttach(PUVM pUVM, EUSBWEBCAM *pThis, const char *pszDriver); + static DECLCALLBACK(int) emulatedWebcamDetach(PUVM pUVM, EUSBWEBCAM *pThis); + + HRESULT settingsParse(void); + + ~EUSBWEBCAM() + { + } + + public: + EUSBWEBCAM() + : + mcRefs(1), + mpEmulatedUSB(NULL), + mpvObject(NULL), + enmStatus(EUSBDEVICE_CREATED) + { + RT_ZERO(mUuid); + RT_ZERO(mszUuid); + } + + int32_t AddRef(void) + { + return ASMAtomicIncS32(&mcRefs); + } + + void Release(void) + { + int32_t c = ASMAtomicDecS32(&mcRefs); + if (c == 0) + { + delete this; + } + } + + HRESULT Initialize(Console *pConsole, + EmulatedUSB *pEmulatedUSB, + const com::Utf8Str *aPath, + const com::Utf8Str *aSettings, + void *pvObject); + HRESULT Attach(Console *pConsole, + PUVM pUVM, + const char *pszDriver); + HRESULT Detach(Console *pConsole, + PUVM pUVM); + + bool HasId(const char *pszId) { return RTStrCmp(pszId, mszUuid) == 0;} + + EUSBDEVICESTATUS enmStatus; +}; + +static int emulatedWebcamInsertSettings(PCFGMNODE pConfig, EUSBSettingsMap *pSettings) +{ + int rc = VINF_SUCCESS; + + EUSBSettingsMap::const_iterator it; + for (it = pSettings->begin(); it != pSettings->end(); ++it) + { + /* Convert some well known settings for backward compatibility. */ + if ( RTStrCmp(it->first.c_str(), "MaxPayloadTransferSize") == 0 + || RTStrCmp(it->first.c_str(), "MaxFramerate") == 0) + { + uint32_t u32 = 0; + rc = RTStrToUInt32Full(it->second.c_str(), 10, &u32); + if (rc == VINF_SUCCESS) + { + rc = CFGMR3InsertInteger(pConfig, it->first.c_str(), u32); + } + else + { + if (RT_SUCCESS(rc)) /* VWRN_* */ + { + rc = VERR_INVALID_PARAMETER; + } + } + } + else + { + rc = CFGMR3InsertString(pConfig, it->first.c_str(), it->second.c_str()); + } + + if (RT_FAILURE(rc)) + { + break; + } + } + + return rc; +} + +/* static */ DECLCALLBACK(int) EUSBWEBCAM::emulatedWebcamAttach(PUVM pUVM, EUSBWEBCAM *pThis, const char *pszDriver) +{ + PCFGMNODE pInstance = CFGMR3CreateTree(pUVM); + PCFGMNODE pConfig; + CFGMR3InsertNode(pInstance, "Config", &pConfig); + int rc = emulatedWebcamInsertSettings(pConfig, &pThis->mDevSettings); + if (RT_FAILURE(rc)) + return rc; + PCFGMNODE pEUSB; + CFGMR3InsertNode(pConfig, "EmulatedUSB", &pEUSB); + CFGMR3InsertString(pEUSB, "Id", pThis->mszUuid); + CFGMR3InsertInteger(pEUSB, "pfnCallback", (uintptr_t)EmulatedUSB::eusbCallback); + CFGMR3InsertInteger(pEUSB, "pvCallback", (uintptr_t)pThis->mpEmulatedUSB); + + PCFGMNODE pLunL0; + CFGMR3InsertNode(pInstance, "LUN#0", &pLunL0); + CFGMR3InsertString(pLunL0, "Driver", pszDriver); + CFGMR3InsertNode(pLunL0, "Config", &pConfig); + CFGMR3InsertString(pConfig, "DevicePath", pThis->mPath.c_str()); + CFGMR3InsertInteger(pConfig, "Object", (uintptr_t)pThis->mpvObject); + rc = emulatedWebcamInsertSettings(pConfig, &pThis->mDrvSettings); + if (RT_FAILURE(rc)) + return rc; + + /* pInstance will be used by PDM and deallocated on error. */ + rc = PDMR3UsbCreateEmulatedDevice(pUVM, "Webcam", pInstance, &pThis->mUuid); + LogRelFlowFunc(("PDMR3UsbCreateEmulatedDevice %Rrc\n", rc)); + return rc; +} + +/* static */ DECLCALLBACK(int) EUSBWEBCAM::emulatedWebcamDetach(PUVM pUVM, EUSBWEBCAM *pThis) +{ + return PDMR3UsbDetachDevice(pUVM, &pThis->mUuid); +} + +HRESULT EUSBWEBCAM::Initialize(Console *pConsole, + EmulatedUSB *pEmulatedUSB, + const com::Utf8Str *aPath, + const com::Utf8Str *aSettings, + void *pvObject) +{ + HRESULT hrc = S_OK; + + int vrc = RTUuidCreate(&mUuid); + if (RT_SUCCESS(vrc)) + { + RTStrPrintf(mszUuid, sizeof(mszUuid), "%RTuuid", &mUuid); + hrc = mPath.assignEx(*aPath); + if (SUCCEEDED(hrc)) + { + hrc = mSettings.assignEx(*aSettings); + } + + if (SUCCEEDED(hrc)) + { + hrc = settingsParse(); + + if (SUCCEEDED(hrc)) + { + mpEmulatedUSB = pEmulatedUSB; + mpvObject = pvObject; + } + } + } + + if (SUCCEEDED(hrc) && RT_FAILURE(vrc)) + { + LogFlowThisFunc(("%Rrc\n", vrc)); + hrc = pConsole->setError(VBOX_E_IPRT_ERROR, + "Init emulated USB webcam (%Rrc)", vrc); + } + + return hrc; +} + +HRESULT EUSBWEBCAM::settingsParse(void) +{ + HRESULT hr = S_OK; + + /* Parse mSettings string: + * "[dev:|drv:]Name1=Value1;[dev:|drv:]Name2=Value2" + */ + char *pszSrc = mSettings.mutableRaw(); + + if (pszSrc) + { + while (*pszSrc) + { + /* Does the setting belong to device of driver. Default is both. */ + bool fDev = true; + bool fDrv = true; + if (RTStrNICmp(pszSrc, "drv:", strlen("drv:")) == 0) + { + pszSrc += strlen("drv:"); + fDev = false; + } + else if (RTStrNICmp(pszSrc, "dev:", strlen("dev:")) == 0) + { + pszSrc += strlen("dev:"); + fDrv = false; + } + + char *pszEq = RTStrStr(pszSrc, "="); + if (!pszEq) + { + hr = E_INVALIDARG; + break; + } + + char *pszEnd = RTStrStr(pszEq, ";"); + if (!pszEnd) + { + pszEnd = pszEq + strlen(pszEq); + } + + *pszEq = 0; + char chEnd = *pszEnd; + *pszEnd = 0; + + /* Empty strings not allowed. */ + if (*pszSrc != 0 && pszEq[1] != 0) + { + if (fDev) + { + mDevSettings[pszSrc] = &pszEq[1]; + } + if (fDrv) + { + mDrvSettings[pszSrc] = &pszEq[1]; + } + } + + *pszEq = '='; + *pszEnd = chEnd; + + pszSrc = pszEnd; + if (*pszSrc == ';') + { + pszSrc++; + } + } + + if (SUCCEEDED(hr)) + { + EUSBSettingsMap::const_iterator it; + for (it = mDevSettings.begin(); it != mDevSettings.end(); ++it) + LogRelFlowFunc(("[dev:%s] = [%s]\n", it->first.c_str(), it->second.c_str())); + for (it = mDrvSettings.begin(); it != mDrvSettings.end(); ++it) + LogRelFlowFunc(("[drv:%s] = [%s]\n", it->first.c_str(), it->second.c_str())); + } + } + + return hr; +} + +HRESULT EUSBWEBCAM::Attach(Console *pConsole, + PUVM pUVM, + const char *pszDriver) +{ + HRESULT hrc = S_OK; + + int vrc = VMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */, + (PFNRT)emulatedWebcamAttach, 3, + pUVM, this, pszDriver); + + if (SUCCEEDED(hrc) && RT_FAILURE(vrc)) + { + LogFlowThisFunc(("%Rrc\n", vrc)); + hrc = pConsole->setError(VBOX_E_IPRT_ERROR, + "Attach emulated USB webcam (%Rrc)", vrc); + } + + return hrc; +} + +HRESULT EUSBWEBCAM::Detach(Console *pConsole, + PUVM pUVM) +{ + HRESULT hrc = S_OK; + + int vrc = VMR3ReqCallWaitU(pUVM, 0 /* idDstCpu (saved state, see #6232) */, + (PFNRT)emulatedWebcamDetach, 2, + pUVM, this); + + if (SUCCEEDED(hrc) && RT_FAILURE(vrc)) + { + LogFlowThisFunc(("%Rrc\n", vrc)); + hrc = pConsole->setError(VBOX_E_IPRT_ERROR, + "Detach emulated USB webcam (%Rrc)", vrc); + } + + return hrc; +} + + +/* + * EmulatedUSB implementation. + */ +DEFINE_EMPTY_CTOR_DTOR(EmulatedUSB) + +HRESULT EmulatedUSB::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void EmulatedUSB::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + +/* + * Initializes the instance. + * + * @param pConsole The owner. + */ +HRESULT EmulatedUSB::init(ComObjPtr pConsole) +{ + LogFlowThisFunc(("\n")); + + ComAssertRet(!pConsole.isNull(), E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m.pConsole = pConsole; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + +/* + * Uninitializes the instance. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void EmulatedUSB::uninit() +{ + LogFlowThisFunc(("\n")); + + m.pConsole.setNull(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + WebcamsMap::iterator it = m.webcams.begin(); + while (it != m.webcams.end()) + { + EUSBWEBCAM *p = it->second; + m.webcams.erase(it++); + p->Release(); + } + alock.release(); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; +} + +HRESULT EmulatedUSB::getWebcams(std::vector &aWebcams) +{ + HRESULT hrc = S_OK; + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + try + { + aWebcams.resize(m.webcams.size()); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + catch (...) + { + hrc = E_FAIL; + } + + if (SUCCEEDED(hrc)) + { + size_t i; + WebcamsMap::const_iterator it; + for (i = 0, it = m.webcams.begin(); it != m.webcams.end(); ++it) + aWebcams[i++] = it->first; + } + + return hrc; +} + +static const Utf8Str s_pathDefault(".0"); + +HRESULT EmulatedUSB::webcamAttach(const com::Utf8Str &aPath, + const com::Utf8Str &aSettings) +{ + return webcamAttachInternal(aPath, aSettings, "HostWebcam", NULL); +} + +HRESULT EmulatedUSB::webcamAttachInternal(const com::Utf8Str &aPath, + const com::Utf8Str &aSettings, + const char *pszDriver, + void *pvObject) +{ + HRESULT hrc = S_OK; + + const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath; + + Console::SafeVMPtr ptrVM(m.pConsole); + if (ptrVM.isOk()) + { + EUSBWEBCAM *p = new EUSBWEBCAM(); + if (p) + { + hrc = p->Initialize(m.pConsole, this, &path, &aSettings, pvObject); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + WebcamsMap::const_iterator it = m.webcams.find(path); + if (it == m.webcams.end()) + { + p->AddRef(); + try + { + m.webcams[path] = p; + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + catch (...) + { + hrc = E_FAIL; + } + p->enmStatus = EUSBDEVICE_ATTACHING; + } + else + { + hrc = E_FAIL; + } + } + + if (SUCCEEDED(hrc)) + { + hrc = p->Attach(m.pConsole, ptrVM.rawUVM(), pszDriver); + } + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (SUCCEEDED(hrc)) + { + p->enmStatus = EUSBDEVICE_ATTACHED; + } + else + { + if (p->enmStatus != EUSBDEVICE_CREATED) + { + m.webcams.erase(path); + } + } + alock.release(); + + p->Release(); + } + else + { + hrc = E_OUTOFMEMORY; + } + } + else + { + hrc = VBOX_E_INVALID_VM_STATE; + } + + return hrc; +} + +HRESULT EmulatedUSB::webcamDetach(const com::Utf8Str &aPath) +{ + return webcamDetachInternal(aPath); +} + +HRESULT EmulatedUSB::webcamDetachInternal(const com::Utf8Str &aPath) +{ + HRESULT hrc = S_OK; + + const Utf8Str &path = aPath.isEmpty() || aPath == "."? s_pathDefault: aPath; + + Console::SafeVMPtr ptrVM(m.pConsole); + if (ptrVM.isOk()) + { + EUSBWEBCAM *p = NULL; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + WebcamsMap::iterator it = m.webcams.find(path); + if (it != m.webcams.end()) + { + if (it->second->enmStatus == EUSBDEVICE_ATTACHED) + { + p = it->second; + m.webcams.erase(it); + } + } + alock.release(); + + if (p) + { + hrc = p->Detach(m.pConsole, ptrVM.rawUVM()); + p->Release(); + } + else + { + hrc = E_INVALIDARG; + } + } + else + { + hrc = VBOX_E_INVALID_VM_STATE; + } + + return hrc; +} + +/* static */ DECLCALLBACK(int) EmulatedUSB::eusbCallbackEMT(EmulatedUSB *pThis, char *pszId, uint32_t iEvent, + void *pvData, uint32_t cbData) +{ + LogRelFlowFunc(("id %s event %d, data %p %d\n", pszId, iEvent, pvData, cbData)); + + NOREF(cbData); + + int rc = VINF_SUCCESS; + if (iEvent == 0) + { + com::Utf8Str path; + HRESULT hr = pThis->webcamPathFromId(&path, pszId); + if (SUCCEEDED(hr)) + { + hr = pThis->webcamDetach(path); + if (FAILED(hr)) + { + rc = VERR_INVALID_STATE; + } + } + else + { + rc = VERR_NOT_FOUND; + } + } + else + { + rc = VERR_INVALID_PARAMETER; + } + + RTMemFree(pszId); + RTMemFree(pvData); + + LogRelFlowFunc(("rc %Rrc\n", rc)); + return rc; +} + +/* static */ DECLCALLBACK(int) EmulatedUSB::eusbCallback(void *pv, const char *pszId, uint32_t iEvent, + const void *pvData, uint32_t cbData) +{ + /* Make a copy of parameters, forward to EMT and leave the callback to not hold any lock in the device. */ + int rc = VINF_SUCCESS; + + void *pvIdCopy = NULL; + void *pvDataCopy = NULL; + if (cbData > 0) + { + pvDataCopy = RTMemDup(pvData, cbData); + if (!pvDataCopy) + { + rc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(rc)) + { + pvIdCopy = RTMemDup(pszId, strlen(pszId) + 1); + if (!pvIdCopy) + { + rc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(rc)) + { + EmulatedUSB *pThis = (EmulatedUSB *)pv; + Console::SafeVMPtr ptrVM(pThis->m.pConsole); + if (ptrVM.isOk()) + { + /* No wait. */ + rc = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), 0 /* idDstCpu */, + (PFNRT)EmulatedUSB::eusbCallbackEMT, 5, + pThis, pvIdCopy, iEvent, pvDataCopy, cbData); + } + else + { + rc = VERR_INVALID_STATE; + } + } + + if (RT_FAILURE(rc)) + { + RTMemFree(pvIdCopy); + RTMemFree(pvDataCopy); + } + + return rc; +} + +HRESULT EmulatedUSB::webcamPathFromId(com::Utf8Str *pPath, const char *pszId) +{ + HRESULT hr = S_OK; + + Console::SafeVMPtr ptrVM(m.pConsole); + if (ptrVM.isOk()) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + WebcamsMap::const_iterator it; + for (it = m.webcams.begin(); it != m.webcams.end(); ++it) + { + EUSBWEBCAM *p = it->second; + if (p->HasId(pszId)) + { + *pPath = it->first; + break; + } + } + + if (it == m.webcams.end()) + { + hr = E_FAIL; + } + alock.release(); + } + else + { + hr = VBOX_E_INVALID_VM_STATE; + } + + return hr; +} + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-client/GuestCtrlImpl.cpp b/src/VBox/Main/src-client/GuestCtrlImpl.cpp index 42c97541..384d5f57 100644 --- a/src/VBox/Main/src-client/GuestCtrlImpl.cpp +++ b/src/VBox/Main/src-client/GuestCtrlImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,6 +22,7 @@ #include "Global.h" #include "ConsoleImpl.h" #include "ProgressImpl.h" +#include "VBoxEvents.h" #include "VMMDev.h" #include "AutoCaller.h" @@ -64,8 +65,8 @@ /* static */ DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, - void *pvParms, - uint32_t cbParms) + void *pvData, + uint32_t cbData) { using namespace guestControl; @@ -74,7 +75,7 @@ DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension, * changes to the object state. */ LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", - pvExtension, u32Function, pvParms, cbParms)); + pvExtension, u32Function, pvData, cbData)); ComObjPtr pGuest = reinterpret_cast(pvExtension); Assert(!pGuest.isNull()); @@ -85,58 +86,35 @@ DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension, * - Extract the session ID out of the context ID * - Dispatch the whole stuff to the appropriate session (if still exists) */ + if (cbData != sizeof(VBOXGUESTCTRLHOSTCALLBACK)) + return VERR_NOT_SUPPORTED; + PVBOXGUESTCTRLHOSTCALLBACK pSvcCb = (PVBOXGUESTCTRLHOSTCALLBACK)pvData; + AssertPtr(pSvcCb); - PCALLBACKHEADER pHeader = (PCALLBACKHEADER)pvParms; - AssertPtr(pHeader); + if (!pSvcCb->mParms) /* At least context ID must be present. */ + return VERR_INVALID_PARAMETER; + uint32_t uContextID; + int rc = pSvcCb->mpaParms[0].getUInt32(&uContextID); + AssertMsgRCReturn(rc, ("Unable to extract callback context ID, pvData=%p\n", pSvcCb), rc); #ifdef DEBUG LogFlowFunc(("CID=%RU32, uSession=%RU32, uObject=%RU32, uCount=%RU32\n", - pHeader->u32ContextID, - VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHeader->u32ContextID), - VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHeader->u32ContextID), - VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pHeader->u32ContextID))); + uContextID, + VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID), + VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID), + VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID))); #endif - bool fDispatch = true; -#ifdef DEBUG - /* - * Pre-check: If we got a status message with an error and VERR_TOO_MUCH_DATA - * it means that that guest could not handle the entire message - * because of its exceeding size. This should not happen on daily - * use but testcases might try this. It then makes no sense to dispatch - * this further because we don't have a valid context ID. - */ - if (u32Function == GUEST_EXEC_SEND_STATUS) - { - PCALLBACKDATAEXECSTATUS pCallbackData = reinterpret_cast(pvParms); - AssertPtr(pCallbackData); - AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER); - AssertReturn(CALLBACKDATAMAGIC_EXEC_STATUS == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER); - - if ( pCallbackData->u32Status == PROC_STS_ERROR - && ((int)pCallbackData->u32Flags) == VERR_TOO_MUCH_DATA) - { - LogFlowFunc(("Requested command with too much data, skipping dispatching ...\n")); + VBOXGUESTCTRLHOSTCBCTX ctxCb = { u32Function, uContextID }; + rc = pGuest->dispatchToSession(&ctxCb, pSvcCb); - Assert(pCallbackData->u32PID == 0); - fDispatch = false; - } - } -#endif - int rc = VINF_SUCCESS; - if (fDispatch) - { - rc = pGuest->dispatchToSession(pHeader->u32ContextID, u32Function, pvParms, cbParms); - if (RT_SUCCESS(rc)) - return rc; - } - - LogFlowFuncLeaveRC(rc); + LogFlowFunc(("Returning rc=%Rrc\n", rc)); return rc; } #endif /* VBOX_WITH_GUEST_CONTROL */ -STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress) +STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(IN_BSTR, aArguments), + ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); @@ -151,7 +129,7 @@ STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(Additio uint32_t fFlags = AdditionsUpdateFlag_None; if (aFlags) { - com::SafeArray flags(ComSafeArrayInArg(aFlags)); + com::SafeArray flags(ComSafeArrayInArg(aFlags)); for (size_t i = 0; i < flags.size(); i++) fFlags |= flags[i]; } @@ -162,19 +140,44 @@ STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(Additio return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags); } + int rc = VINF_SUCCESS; + + ProcessArguments aArgs; + if (aArguments) + { + try + { + com::SafeArray arguments(ComSafeArrayInArg(aArguments)); + for (size_t i = 0; i < arguments.size(); i++) + aArgs.push_back(Utf8Str(arguments[i])); + } + catch(std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } + } + HRESULT hr = S_OK; - /* Create an anonymous session. This is required to run the Guest Additions - * update process with administrative rights. */ + /* + * Create an anonymous session. This is required to run the Guest Additions + * update process with administrative rights. + */ + GuestSessionStartupInfo startupInfo; + startupInfo.mName = "Updating Guest Additions"; + + GuestCredentials guestCreds; + RT_ZERO(guestCreds); + ComObjPtr pSession; - int rc = sessionCreate("" /* User */, "" /* Password */, "" /* Domain */, - "Updating Guest Additions" /* Name */, pSession); + if (RT_SUCCESS(rc)) + rc = sessionCreate(startupInfo, guestCreds, pSession); if (RT_FAILURE(rc)) { switch (rc) { case VERR_MAX_PROCS_REACHED: - hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"), + hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), VBOX_GUESTCTRL_MAX_SESSIONS); break; @@ -188,10 +191,13 @@ STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(Additio else { Assert(!pSession.isNull()); - rc = pSession->queryInfo(); + int guestRc; + rc = pSession->startSessionInternal(&guestRc); if (RT_FAILURE(rc)) { - hr = setError(VBOX_E_IPRT_ERROR, tr("Could not query guest session information: %Rrc"), rc); + /** @todo Handle guestRc! */ + + hr = setError(VBOX_E_IPRT_ERROR, tr("Could not open guest session: %Rrc"), rc); } else { @@ -199,7 +205,7 @@ STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(Additio { ComObjPtr pProgress; SessionTaskUpdateAdditions *pTask = new SessionTaskUpdateAdditions(pSession /* GuestSession */, - Utf8Str(aSource), fFlags); + Utf8Str(aSource), aArgs, fFlags); rc = pSession->startTaskAsync(tr("Updating Guest Additions"), pTask, pProgress); if (RT_SUCCESS(rc)) { @@ -223,27 +229,113 @@ STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(Additio // private methods ///////////////////////////////////////////////////////////////////////////// -int Guest::dispatchToSession(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData) +int Guest::dispatchToSession(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) { - LogFlowFuncEnter(); + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + LogFlowFunc(("uFunction=%RU32, uContextID=%RU32, uProtocol=%RU32\n", + pCtxCb->uFunction, pCtxCb->uContextID, pCtxCb->uProtocol)); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID); + uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtxCb->uContextID); #ifdef DEBUG - LogFlowFunc(("uSessionID=%RU32 (%RU32 total)\n", + LogFlowFunc(("uSessionID=%RU32 (%zu total)\n", uSessionID, mData.mGuestSessions.size())); #endif - int rc; GuestSessions::const_iterator itSession = mData.mGuestSessions.find(uSessionID); + + int rc; if (itSession != mData.mGuestSessions.end()) { ComObjPtr pSession(itSession->second); Assert(!pSession.isNull()); alock.release(); - rc = pSession->dispatchToProcess(uContextID, uFunction, pvData, cbData); + + bool fDispatch = true; +#ifdef DEBUG + /* + * Pre-check: If we got a status message with an error and VERR_TOO_MUCH_DATA + * it means that that guest could not handle the entire message + * because of its exceeding size. This should not happen on daily + * use but testcases might try this. It then makes no sense to dispatch + * this further because we don't have a valid context ID. + */ + if ( pCtxCb->uFunction == GUEST_EXEC_STATUS + && pSvcCb->mParms >= 5) + { + CALLBACKDATA_PROC_STATUS dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + pSvcCb->mpaParms[1].getUInt32(&dataCb.uPID); + pSvcCb->mpaParms[2].getUInt32(&dataCb.uStatus); + pSvcCb->mpaParms[3].getUInt32(&dataCb.uFlags); + pSvcCb->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData); + + if ( ( dataCb.uStatus == PROC_STS_ERROR) + /** @todo Note: Due to legacy reasons we cannot change uFlags to + * int32_t, so just cast it for now. */ + && ((int32_t)dataCb.uFlags == VERR_TOO_MUCH_DATA)) + { + LogFlowFunc(("Requested command with too much data, skipping dispatching ...\n")); + + Assert(dataCb.uPID == 0); + fDispatch = false; + } + } +#endif + if (fDispatch) + { + switch (pCtxCb->uFunction) + { + case GUEST_DISCONNECTED: + rc = pSession->dispatchToThis(pCtxCb, pSvcCb); + break; + + case GUEST_EXEC_STATUS: + case GUEST_EXEC_OUTPUT: + case GUEST_EXEC_INPUT_STATUS: + case GUEST_EXEC_IO_NOTIFY: + rc = pSession->dispatchToProcess(pCtxCb, pSvcCb); + break; + + case GUEST_FILE_NOTIFY: + rc = pSession->dispatchToFile(pCtxCb, pSvcCb); + break; + + case GUEST_SESSION_NOTIFY: + rc = pSession->dispatchToThis(pCtxCb, pSvcCb); + break; + + default: + /* + * Try processing generic messages which might + * (or might not) supported by certain objects. + * If the message either is not found or supported + * by the approprirate object, try handling it + * in this session object. + */ + rc = pSession->dispatchToObject(pCtxCb, pSvcCb); + if ( rc == VERR_NOT_FOUND + || rc == VERR_NOT_SUPPORTED) + { + alock.acquire(); + + rc = pSession->dispatchGeneric(pCtxCb, pSvcCb); + } +#ifndef DEBUG_andy + if (rc == VERR_NOT_IMPLEMENTED) + AssertMsgFailed(("Received not handled function %RU32\n", pCtxCb->uFunction)); +#endif + break; + } + } + else + rc = VERR_NOT_FOUND; } else rc = VERR_NOT_FOUND; @@ -254,35 +346,54 @@ int Guest::dispatchToSession(uint32_t uContextID, uint32_t uFunction, void *pvDa int Guest::sessionRemove(GuestSession *pSession) { + AssertPtrReturn(pSession, VERR_INVALID_POINTER); + LogFlowThisFuncEnter(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); int rc = VERR_NOT_FOUND; - LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId())); + LogFlowThisFunc(("Removing session (ID=%RU32) ...\n", pSession->getId())); - for (GuestSessions::iterator itSessions = mData.mGuestSessions.begin(); - itSessions != mData.mGuestSessions.end(); ++itSessions) + GuestSessions::iterator itSessions = mData.mGuestSessions.begin(); + while (itSessions != mData.mGuestSessions.end()) { if (pSession == itSessions->second) { - LogFlowFunc(("Removing session (pSession=%p, ID=%RU32) (now total %ld sessions)\n", - (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1)); +#ifdef DEBUG_andy + ULONG cRefs = pSession->AddRef(); + Assert(cRefs >= 2); + LogFlowThisFunc(("pCurSession=%p, cRefs=%RU32\n", pSession, cRefs - 2)); + pSession->Release(); +#endif + /* Make sure to consume the pointer before the one of the + * iterator gets released. */ + ComObjPtr pCurSession = pSession; + + LogFlowThisFunc(("Removing session (pSession=%p, ID=%RU32) (now total %ld sessions)\n", + pSession, pSession->getId(), mData.mGuestSessions.size() - 1)); + rc = pSession->onRemove(); mData.mGuestSessions.erase(itSessions); - rc = VINF_SUCCESS; + alock.release(); /* Release lock before firing off event. */ + + fireGuestSessionRegisteredEvent(mEventSource, pCurSession, + false /* Unregistered */); + pCurSession.setNull(); break; } + + itSessions++; } LogFlowFuncLeaveRC(rc); return rc; } -int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain, - const Utf8Str &strSessionName, ComObjPtr &pGuestSession) +int Guest::sessionCreate(const GuestSessionStartupInfo &ssInfo, + const GuestCredentials &guestCreds, ComObjPtr &pGuestSession) { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -293,7 +404,7 @@ int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, con try { /* Create a new session ID and assign it. */ - uint32_t uNewSessionID = 0; + uint32_t uNewSessionID = VBOX_GUESTCTRL_SESSION_ID_BASE; uint32_t uTries = 0; for (;;) @@ -306,9 +417,9 @@ int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, con } uNewSessionID++; if (uNewSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS) - uNewSessionID = 0; + uNewSessionID = VBOX_GUESTCTRL_SESSION_ID_BASE; - if (++uTries == UINT32_MAX) + if (++uTries == VBOX_GUESTCTRL_MAX_SESSIONS) break; /* Don't try too hard. */ } if (RT_FAILURE(rc)) throw rc; @@ -317,20 +428,48 @@ int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, con HRESULT hr = pGuestSession.createObject(); if (FAILED(hr)) throw VERR_COM_UNEXPECTED; - rc = pGuestSession->init(this, uNewSessionID, - strUser, strPassword, strDomain, strSessionName); + /** @todo Use an overloaded copy operator. Later. */ + GuestSessionStartupInfo startupInfo; + startupInfo.mID = uNewSessionID; /* Assign new session ID. */ + startupInfo.mName = ssInfo.mName; + startupInfo.mOpenFlags = ssInfo.mOpenFlags; + startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS; + + GuestCredentials guestCredentials; + if (!guestCreds.mUser.isEmpty()) + { + /** @todo Use an overloaded copy operator. Later. */ + guestCredentials.mUser = guestCreds.mUser; + guestCredentials.mPassword = guestCreds.mPassword; + guestCredentials.mDomain = guestCreds.mDomain; + } + else + { + /* Internal (annonymous) session. */ + startupInfo.mIsInternal = true; + } + + rc = pGuestSession->init(this, startupInfo, guestCredentials); if (RT_FAILURE(rc)) throw rc; + /* + * Add session object to our session map. This is necessary + * before calling openSession because the guest calls back + * with the creation result of this session. + */ mData.mGuestSessions[uNewSessionID] = pGuestSession; - LogFlowFunc(("Added new session (pSession=%p, ID=%RU32), now %ld sessions total\n", - (GuestSession *)pGuestSession, uNewSessionID, mData.mGuestSessions.size())); + alock.release(); /* Release lock before firing off event. */ + + fireGuestSessionRegisteredEvent(mEventSource, pGuestSession, + true /* Registered */); } catch (int rc2) { rc = rc2; } + LogFlowFuncLeaveRC(rc); return rc; } @@ -343,7 +482,8 @@ inline bool Guest::sessionExists(uint32_t uSessionID) // implementation of public methods ///////////////////////////////////////////////////////////////////////////// -STDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, IN_BSTR aSessionName, IGuestSession **aGuestSession) +STDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, + IN_BSTR aSessionName, IGuestSession **aGuestSession) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); @@ -351,48 +491,62 @@ STDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDom LogFlowFuncEnter(); - /* Do not allow anonymous sessions (with system rights) with official API. */ + /* Do not allow anonymous sessions (with system rights) with public API. */ if (RT_UNLIKELY((aUser) == NULL || *(aUser) == '\0')) return setError(E_INVALIDARG, tr("No user name specified")); + if (RT_UNLIKELY((aPassword) == NULL)) /* Allow empty passwords. */ + return setError(E_INVALIDARG, tr("No password specified")); CheckComArgOutPointerValid(aGuestSession); /* Rest is optional. */ AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - HRESULT hr = S_OK; + GuestSessionStartupInfo startupInfo; + startupInfo.mName = aSessionName; + + GuestCredentials guestCreds; + guestCreds.mUser = aUser; + guestCreds.mPassword = aPassword; + guestCreds.mDomain = aDomain; ComObjPtr pSession; - int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, pSession); + int rc = sessionCreate(startupInfo, guestCreds, pSession); if (RT_SUCCESS(rc)) { /* Return guest session to the caller. */ HRESULT hr2 = pSession.queryInterfaceTo(aGuestSession); if (FAILED(hr2)) rc = VERR_COM_OBJECT_NOT_FOUND; + } - if (RT_SUCCESS(rc)) - rc = pSession->queryInfo(); + if (RT_SUCCESS(rc)) + { + /* Start (fork) the session asynchronously + * on the guest. */ + rc = pSession->startSessionAsync(); } + HRESULT hr = S_OK; + if (RT_FAILURE(rc)) { switch (rc) { case VERR_MAX_PROCS_REACHED: - hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"), + hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), VBOX_GUESTCTRL_MAX_SESSIONS); break; /** @todo Add more errors here. */ - default: - hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session, rc=%Rrc"), rc); + default: + hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc); break; } } - LogFlowFuncLeaveRC(rc); + LogFlowThisFunc(("Returning rc=%Rhrc\n", hr)); return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } diff --git a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp index 1a504aa4..1b0fb663 100644 --- a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp +++ b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2012 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,8 +20,11 @@ * Header Files * ******************************************************************************/ #include "GuestCtrlImplPrivate.h" +#include "GuestSessionImpl.h" +#include "VMMDev.h" #include +#include /* For unconst(). */ #include #ifdef DEBUG # include @@ -37,306 +40,6 @@ * Structures and Typedefs * ******************************************************************************/ -GuestCtrlEvent::GuestCtrlEvent(void) - : fCanceled(false), - fCompleted(false), - hEventSem(NIL_RTSEMEVENT), - mRC(VINF_SUCCESS) -{ -} - -GuestCtrlEvent::~GuestCtrlEvent(void) -{ - Destroy(); -} - -int GuestCtrlEvent::Cancel(void) -{ - int rc = VINF_SUCCESS; - if (!ASMAtomicReadBool(&fCompleted)) - { - if (!ASMAtomicReadBool(&fCanceled)) - { - ASMAtomicXchgBool(&fCanceled, true); - - LogFlowThisFunc(("Cancelling event ...\n")); - rc = hEventSem != NIL_RTSEMEVENT - ? RTSemEventSignal(hEventSem) : VINF_SUCCESS; - } - } - - return rc; -} - -bool GuestCtrlEvent::Canceled(void) -{ - return ASMAtomicReadBool(&fCanceled); -} - -void GuestCtrlEvent::Destroy(void) -{ - int rc = Cancel(); - AssertRC(rc); - - if (hEventSem != NIL_RTSEMEVENT) - { - RTSemEventDestroy(hEventSem); - hEventSem = NIL_RTSEMEVENT; - } -} - -int GuestCtrlEvent::Init(void) -{ - return RTSemEventCreate(&hEventSem); -} - -int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/) -{ - AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); - - mRC = rc; - - return RTSemEventSignal(hEventSem); -} - -int GuestCtrlEvent::Wait(ULONG uTimeoutMS) -{ - LogFlowThisFuncEnter(); - - AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); - - RTMSINTERVAL msInterval = uTimeoutMS; - if (!uTimeoutMS) - msInterval = RT_INDEFINITE_WAIT; - int rc = RTSemEventWait(hEventSem, msInterval); - if (RT_SUCCESS(rc)) - ASMAtomicWriteBool(&fCompleted, true); - - LogFlowFuncLeaveRC(rc); - return rc; -} - -/////////////////////////////////////////////////////////////////////////////// - -GuestCtrlCallback::GuestCtrlCallback(void) - : pvData(NULL), - cbData(0), - mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), - uFlags(0), - pvPayload(NULL), - cbPayload(0) -{ -} - -GuestCtrlCallback::GuestCtrlCallback(eVBoxGuestCtrlCallbackType enmType) - : pvData(NULL), - cbData(0), - mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), - uFlags(0), - pvPayload(NULL), - cbPayload(0) -{ - int rc = Init(enmType); - AssertRC(rc); -} - -GuestCtrlCallback::~GuestCtrlCallback(void) -{ - Destroy(); -} - -int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType) -{ - AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER); - Assert((pvData == NULL) && !cbData); - - switch (enmType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START: - { - pvData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECSTATUS)); - cbData = sizeof(CALLBACKDATAEXECSTATUS); - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - pvData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECOUT)); - cbData = sizeof(CALLBACKDATAEXECOUT); - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS: - { - pvData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECINSTATUS)); - cbData = sizeof(CALLBACKDATAEXECINSTATUS); - break; - } - - default: - AssertMsgFailed(("Unknown callback type specified (%d)\n", enmType)); - break; - } - - int rc = GuestCtrlEvent::Init(); - if (RT_SUCCESS(rc)) - mType = enmType; - - return rc; -} - -void GuestCtrlCallback::Destroy(void) -{ - GuestCtrlEvent::Destroy(); - - switch (mType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData; - AssertPtr(pThis); - if (pThis->pvData) - RTMemFree(pThis->pvData); - } - - default: - break; - } - - mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN; - if (pvData) - { - RTMemFree(pvData); - pvData = NULL; - } - cbData = 0; - - if (pvPayload) - { - RTMemFree(pvPayload); - pvPayload = NULL; - } - cbPayload = 0; -} - -int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback) -{ - if (!cbCallback) - return VINF_SUCCESS; - AssertPtr(pvCallback); - - switch (mType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START: - { - PCALLBACKDATAEXECSTATUS pThis = (PCALLBACKDATAEXECSTATUS)pvData; - PCALLBACKDATAEXECSTATUS pCB = (PCALLBACKDATAEXECSTATUS)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECSTATUS)); - - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - pThis->u32Status = pCB->u32Status; - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData; - PCALLBACKDATAEXECOUT pCB = (PCALLBACKDATAEXECOUT)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECOUT)); - - pThis->cbData = pCB->cbData; - if (pThis->cbData) - { - pThis->pvData = RTMemAlloc(pCB->cbData); - AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY); - memcpy(pThis->pvData, pCB->pvData, pCB->cbData); - } - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS: - { - PCALLBACKDATAEXECINSTATUS pThis = (PCALLBACKDATAEXECINSTATUS)pvData; - PCALLBACKDATAEXECINSTATUS pCB = (PCALLBACKDATAEXECINSTATUS)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECINSTATUS)); - - pThis->cbProcessed = pCB->cbProcessed; - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - pThis->u32Status = pCB->u32Status; - break; - } - - default: - AssertMsgFailed(("Callback type not handled (%d)\n", mType)); - break; - } - - return VINF_SUCCESS; -} - -int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite) -{ - if (!cbToWrite) - return VINF_SUCCESS; - AssertPtr(pvToWrite); - - Assert(pvPayload == NULL); /* Can't reuse callbacks! */ - pvPayload = RTMemAlloc(cbToWrite); - if (!pvPayload) - return VERR_NO_MEMORY; - - memcpy(pvPayload, pvToWrite, cbToWrite); - cbPayload = cbToWrite; - - return VINF_SUCCESS; -} - -/////////////////////////////////////////////////////////////////////////////// - -GuestProcessWaitEvent::GuestProcessWaitEvent(void) - : mFlags(0), - mResult(ProcessWaitResult_None) -{ -} - -GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags) - : mFlags(uWaitFlags) -{ - int rc = GuestCtrlEvent::Init(); - AssertRC(rc); -} - -GuestProcessWaitEvent::~GuestProcessWaitEvent(void) -{ - Destroy(); -} - -void GuestProcessWaitEvent::Destroy(void) -{ - GuestCtrlEvent::Destroy(); - - mFlags = ProcessWaitForFlag_None; -} - -int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/) -{ - mResult = enmResult; - - return GuestCtrlEvent::Signal(rc); -} - -/////////////////////////////////////////////////////////////////////////////// - int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars) { AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER); @@ -473,7 +176,7 @@ int GuestEnvironment::Set(const Utf8Str &strPair) int rc = VINF_SUCCESS; size_t p = 0; - while(p < listPair.size() && RT_SUCCESS(rc)) + while (p < listPair.size() && RT_SUCCESS(rc)) { Utf8Str strKey = listPair.at(p++); if ( strKey.isEmpty() @@ -623,6 +326,32 @@ int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk) return rc; } +int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk) +{ + LogFlowFunc(("\n")); + + int rc; + + try + { +#ifdef DEBUG + strmBlk.DumpToLog(); +#endif + /* Object name. */ + mName = strmBlk.GetString("name"); + if (mName.isEmpty()) throw VERR_NOT_FOUND; + /* Assign the stream block's rc. */ + rc = strmBlk.GetRc(); + } + catch (int rc2) + { + rc = rc2; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk) { LogFlowFunc(("\n")); @@ -676,10 +405,10 @@ GuestProcessStreamBlock::GuestProcessStreamBlock(void) /* GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock) { - for (GuestCtrlStreamPairsIter it = otherBlock.m_mapPairs.begin(); + for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin(); it != otherBlock.end(); it++) { - m_mapPairs[it->first] = new + mPairs[it->first] = new if (it->second.pszValue) { RTMemFree(it->second.pszValue); @@ -700,17 +429,17 @@ GuestProcessStreamBlock::~GuestProcessStreamBlock() */ void GuestProcessStreamBlock::Clear(void) { - m_mapPairs.clear(); + mPairs.clear(); } #ifdef DEBUG void GuestProcessStreamBlock::DumpToLog(void) const { LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n", - this, m_mapPairs.size())); + this, mPairs.size())); - for (GuestCtrlStreamPairMapIterConst it = m_mapPairs.begin(); - it != m_mapPairs.end(); it++) + for (GuestCtrlStreamPairMapIterConst it = mPairs.begin(); + it != mPairs.end(); it++) { LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str())); } @@ -758,7 +487,22 @@ int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const */ size_t GuestProcessStreamBlock::GetCount(void) const { - return m_mapPairs.size(); + return mPairs.size(); +} + +/** + * Gets the return code (name = "rc") of this stream block. + * + * @return IPRT status code. + */ +int GuestProcessStreamBlock::GetRc(void) const +{ + const char *pszValue = GetString("rc"); + if (pszValue) + { + return RTStrToInt16(pszValue); + } + return VERR_NOT_FOUND; } /** @@ -773,8 +517,8 @@ const char* GuestProcessStreamBlock::GetString(const char *pszKey) const try { - GuestCtrlStreamPairMapIterConst itPairs = m_mapPairs.find(Utf8Str(pszKey)); - if (itPairs != m_mapPairs.end()) + GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey)); + if (itPairs != mPairs.end()) return itPairs->second.mValue.c_str(); } catch (const std::exception &ex) @@ -836,17 +580,17 @@ int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue) /* Take a shortcut and prevent crashes on some funny versions * of STL if map is empty initially. */ - if (!m_mapPairs.empty()) + if (!mPairs.empty()) { - GuestCtrlStreamPairMapIter it = m_mapPairs.find(Utf8Key); - if (it != m_mapPairs.end()) - m_mapPairs.erase(it); + GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key); + if (it != mPairs.end()) + mPairs.erase(it); } if (pszValue) { GuestProcessStreamValue val(pszValue); - m_mapPairs[Utf8Key] = val; + mPairs[Utf8Key] = val; } } catch (const std::exception &ex) @@ -975,22 +719,6 @@ void GuestProcessStream::Dump(const char *pszFile) } #endif -/** - * Returns the current offset of the parser within - * the internal data buffer. - * - * @return uint32_t Parser offset. - */ -uint32_t GuestProcessStream::GetOffset() -{ - return m_cbOffset; -} - -uint32_t GuestProcessStream::GetSize() -{ - return m_cbSize; -} - /** * Tries to parse the next upcoming pair block within the internal * buffer. @@ -1075,3 +803,590 @@ int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock) return rc; } +GuestBase::GuestBase(void) + : mConsole(NULL), + mNextContextID(0) +{ +} + +GuestBase::~GuestBase(void) +{ +} + +int GuestBase::baseInit(void) +{ + int rc = RTCritSectInit(&mWaitEventCritSect); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +void GuestBase::baseUninit(void) +{ + LogFlowThisFuncEnter(); + + int rc = RTCritSectDelete(&mWaitEventCritSect); + + LogFlowFuncLeaveRC(rc); + /* No return value. */ +} + +int GuestBase::cancelWaitEvents(void) +{ + LogFlowThisFuncEnter(); + + int rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + GuestEventGroup::iterator itEventGroups = mWaitEventGroups.begin(); + while (itEventGroups != mWaitEventGroups.end()) + { + GuestWaitEvents::iterator itEvents = itEventGroups->second.begin(); + while (itEvents != itEventGroups->second.end()) + { + GuestWaitEvent *pEvent = itEvents->second; + AssertPtr(pEvent); + + /* + * Just cancel the event, but don't remove it from the + * wait events map. Don't delete it though, this (hopefully) + * is done by the caller using unregisterWaitEvent(). + */ + int rc2 = pEvent->Cancel(); + AssertRC(rc2); + + itEvents++; + } + + itEventGroups++; + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestBase::dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + int vrc = VINF_SUCCESS; + + try + { + LogFlowFunc(("uFunc=%RU32, cParms=%RU32\n", + pCtxCb->uFunction, pSvcCb->mParms)); + + switch (pCtxCb->uFunction) + { + case GUEST_MSG_PROGRESS_UPDATE: + break; + + case GUEST_MSG_REPLY: + { + if (pSvcCb->mParms >= 3) + { + int idx = 1; /* Current parameter index. */ + CALLBACKDATA_MSG_REPLY dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType); + AssertRCReturn(vrc, vrc); + vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc); + AssertRCReturn(vrc, vrc); + vrc = pSvcCb->mpaParms[idx++].getPointer(&dataCb.pvPayload, &dataCb.cbPayload); + AssertRCReturn(vrc, vrc); + + GuestWaitEventPayload evPayload(dataCb.uType, dataCb.pvPayload, dataCb.cbPayload); + int rc2 = signalWaitEventInternal(pCtxCb, dataCb.rc, &evPayload); + AssertRC(rc2); + } + else + vrc = VERR_INVALID_PARAMETER; + break; + } + + default: + vrc = VERR_NOT_SUPPORTED; + break; + } + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + catch (int rc) + { + vrc = rc; + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID) +{ + AssertPtrReturn(puContextID, VERR_INVALID_POINTER); + + if ( uSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS + || uObjectID >= VBOX_GUESTCTRL_MAX_OBJECTS) + return VERR_INVALID_PARAMETER; + + uint32_t uCount = ASMAtomicIncU32(&mNextContextID); + if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS) + uCount = 0; + + uint32_t uNewContextID = + VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); + + *puContextID = uNewContextID; + +#if 0 + LogFlowThisFunc(("mNextContextID=%RU32, uSessionID=%RU32, uObjectID=%RU32, uCount=%RU32, uNewContextID=%RU32\n", + mNextContextID, uSessionID, uObjectID, uCount, uNewContextID)); +#endif + return VINF_SUCCESS; +} + +int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, + GuestWaitEvent **ppEvent) +{ + GuestEventTypes eventTypesEmpty; + return registerWaitEvent(uSessionID, uObjectID, eventTypesEmpty, ppEvent); +} + +int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, + const GuestEventTypes &lstEvents, + GuestWaitEvent **ppEvent) +{ + AssertPtrReturn(ppEvent, VERR_INVALID_POINTER); + + uint32_t uContextID; + int rc = generateContextID(uSessionID, uObjectID, &uContextID); + if (RT_FAILURE(rc)) + return rc; + + rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + try + { + GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents); + AssertPtr(pEvent); + + LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID)); + + /* Insert event into matching event group. This is for faster per-group + * lookup of all events later. */ + for (GuestEventTypes::const_iterator itEvents = lstEvents.begin(); + itEvents != lstEvents.end(); itEvents++) + { + mWaitEventGroups[(*itEvents)].insert( + std::pair(uContextID, pEvent)); + /** @todo Check for key collision. */ + } + + /* Register event in regular event list. */ + /** @todo Check for key collisions. */ + mWaitEvents[uContextID] = pEvent; + + *ppEvent = pEvent; + } + catch(std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + return rc; +} + +int GuestBase::signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent) +{ + int rc = RTCritSectEnter(&mWaitEventCritSect); +#ifdef DEBUG + uint32_t cEvents = 0; +#endif + if (RT_SUCCESS(rc)) + { + GuestEventGroup::iterator itGroup = mWaitEventGroups.find(aType); + if (itGroup != mWaitEventGroups.end()) + { + GuestWaitEvents::iterator itEvents = itGroup->second.begin(); + while (itEvents != itGroup->second.end()) + { +#ifdef DEBUG + LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %RU32: Session=%RU32, Object=%RU32, Count=%RU32) ...\n", + itEvents->second, aType, itEvents->first, + VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(itEvents->first), + VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(itEvents->first), + VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(itEvents->first))); +#endif + ComPtr pThisEvent = aEvent; + Assert(!pThisEvent.isNull()); + int rc2 = itEvents->second->SignalExternal(aEvent); + if (RT_SUCCESS(rc)) + rc = rc2; + + if (RT_SUCCESS(rc2)) + { + /* Remove the event from all other event groups (except the + * original one!) because it was signalled. */ + AssertPtr(itEvents->second); + const GuestEventTypes evTypes = itEvents->second->Types(); + for (GuestEventTypes::const_iterator itType = evTypes.begin(); + itType != evTypes.end(); itType++) + { + if ((*itType) != aType) /* Only remove all other groups. */ + { + /* Get current event group. */ + GuestEventGroup::iterator evGroup = mWaitEventGroups.find((*itType)); + Assert(evGroup != mWaitEventGroups.end()); + + /* Lookup event in event group. */ + GuestWaitEvents::iterator evEvent = evGroup->second.find(itEvents->first /* Context ID */); + Assert(evEvent != evGroup->second.end()); + + LogFlowThisFunc(("Removing event=%p (type %ld)\n", evEvent->second, (*itType))); + evGroup->second.erase(evEvent); + + LogFlowThisFunc(("%zu events for type=%ld left\n", + evGroup->second.size(), aType)); + } + } + + /* Remove the event from the passed-in event group. */ + itGroup->second.erase(itEvents++); + } + else + itEvents++; +#ifdef DEBUG + cEvents++; +#endif + } + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + +#ifdef DEBUG + LogFlowThisFunc(("Signalled %RU32 events, rc=%Rrc\n", cEvents, rc)); +#endif + return rc; +} + +int GuestBase::signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, + int guestRc, const GuestWaitEventPayload *pPayload) +{ + if (RT_SUCCESS(guestRc)) + return signalWaitEventInternalEx(pCbCtx, VINF_SUCCESS, + 0 /* Guest rc */, pPayload); + + return signalWaitEventInternalEx(pCbCtx, VERR_GSTCTL_GUEST_ERROR, + guestRc, pPayload); +} + +int GuestBase::signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, + int rc, int guestRc, + const GuestWaitEventPayload *pPayload) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + /* pPayload is optional. */ + + int rc2; + GuestWaitEvents::iterator itEvent = mWaitEvents.find(pCbCtx->uContextID); + if (itEvent != mWaitEvents.end()) + { + LogFlowThisFunc(("Signalling event=%p (CID %RU32, rc=%Rrc, guestRc=%Rrc, pPayload=%p) ...\n", + itEvent->second, itEvent->first, rc, guestRc, pPayload)); + GuestWaitEvent *pEvent = itEvent->second; + AssertPtr(pEvent); + rc2 = pEvent->SignalInternal(rc, guestRc, pPayload); + } + else + rc2 = VERR_NOT_FOUND; + + return rc2; +} + +void GuestBase::unregisterWaitEvent(GuestWaitEvent *pEvent) +{ + if (!pEvent) /* Nothing to unregister. */ + return; + + int rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + LogFlowThisFunc(("pEvent=%p\n", pEvent)); + + const GuestEventTypes lstTypes = pEvent->Types(); + for (GuestEventTypes::const_iterator itEvents = lstTypes.begin(); + itEvents != lstTypes.end(); itEvents++) + { + /** @todo Slow O(n) lookup. Optimize this. */ + GuestWaitEvents::iterator itCurEvent = mWaitEventGroups[(*itEvents)].begin(); + while (itCurEvent != mWaitEventGroups[(*itEvents)].end()) + { + if (itCurEvent->second == pEvent) + { + mWaitEventGroups[(*itEvents)].erase(itCurEvent++); + break; + } + else + itCurEvent++; + } + } + + delete pEvent; + pEvent = NULL; + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } +} + +/** + * Waits for a formerly registered guest event. + * + * @return IPRT status code. + * @param pEvent Pointer to event to wait for. + * @param uTimeoutMS Timeout (in ms) for waiting. + * @param pType Event type of following IEvent. + * Optional. + * @param ppEvent Pointer to IEvent which got triggered + * for this event. Optional. + */ +int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, + VBoxEventType_T *pType, IEvent **ppEvent) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + /* pType is optional. */ + /* ppEvent is optional. */ + + int vrc = pEvent->Wait(uTimeoutMS); + if (RT_SUCCESS(vrc)) + { + const ComPtr pThisEvent = pEvent->Event(); + if (!pThisEvent.isNull()) /* Having a VBoxEventType_ event is optional. */ + { + if (pType) + { + HRESULT hr = pThisEvent->COMGETTER(Type)(pType); + if (FAILED(hr)) + vrc = VERR_COM_UNEXPECTED; + } + if ( RT_SUCCESS(vrc) + && ppEvent) + pThisEvent.queryInterfaceTo(ppEvent); + + unconst(pThisEvent).setNull(); + } + } + + return vrc; +} + +GuestObject::GuestObject(void) + : mSession(NULL), + mObjectID(0) +{ +} + +GuestObject::~GuestObject(void) +{ +} + +int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID) +{ + AssertPtrReturn(pConsole, VERR_INVALID_POINTER); + AssertPtrReturn(pSession, VERR_INVALID_POINTER); + + mConsole = pConsole; + mSession = pSession; + mObjectID = uObjectID; + + return VINF_SUCCESS; +} + +int GuestObject::registerWaitEvent(const GuestEventTypes &lstEvents, + GuestWaitEvent **ppEvent) +{ + AssertPtr(mSession); + return GuestBase::registerWaitEvent(mSession->getId(), mObjectID, lstEvents, ppEvent); +} + +int GuestObject::sendCommand(uint32_t uFunction, + uint32_t uParms, PVBOXHGCMSVCPARM paParms) +{ +#ifndef VBOX_GUESTCTRL_TEST_CASE + ComObjPtr pConsole = mConsole; + Assert(!pConsole.isNull()); + + int vrc = VERR_HGCM_SERVICE_NOT_FOUND; + + /* Forward the information to the VMM device. */ + VMMDev *pVMMDev = pConsole->getVMMDev(); + if (pVMMDev) + { + LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); + vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms); + if (RT_FAILURE(vrc)) + { + /** @todo What to do here? */ + } + } +#else + LogFlowThisFuncEnter(); + + /* Not needed within testcases. */ + int vrc = VINF_SUCCESS; +#endif + return vrc; +} + +GuestWaitEventBase::GuestWaitEventBase(void) + : mfAborted(false), + mCID(0), + mEventSem(NIL_RTSEMEVENT), + mRc(VINF_SUCCESS), + mGuestRc(VINF_SUCCESS) +{ +} + +GuestWaitEventBase::~GuestWaitEventBase(void) +{ +} + +int GuestWaitEventBase::Init(uint32_t uCID) +{ + mCID = uCID; + + return RTSemEventCreate(&mEventSem); +} + +int GuestWaitEventBase::SignalInternal(int rc, int guestRc, + const GuestWaitEventPayload *pPayload) +{ + if (ASMAtomicReadBool(&mfAborted)) + return VERR_CANCELLED; + +#ifdef VBOX_STRICT + if (rc == VERR_GSTCTL_GUEST_ERROR) + AssertMsg(RT_FAILURE(guestRc), ("Guest error indicated but no actual guest error set (%Rrc)\n", guestRc)); + else + AssertMsg(RT_SUCCESS(guestRc), ("No guest error indicated but actual guest error set (%Rrc)\n", guestRc)); +#endif + + int rc2; + if (pPayload) + rc2 = mPayload.CopyFromDeep(*pPayload); + else + rc2 = VINF_SUCCESS; + if (RT_SUCCESS(rc2)) + { + mRc = rc; + mGuestRc = guestRc; + + rc2 = RTSemEventSignal(mEventSem); + } + + return rc2; +} + +int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS) +{ + int rc = VINF_SUCCESS; + + if (ASMAtomicReadBool(&mfAborted)) + rc = VERR_CANCELLED; + + if (RT_SUCCESS(rc)) + { + AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); + + RTMSINTERVAL msInterval = uTimeoutMS; + if (!uTimeoutMS) + msInterval = RT_INDEFINITE_WAIT; + rc = RTSemEventWait(mEventSem, msInterval); + if (ASMAtomicReadBool(&mfAborted)) + rc = VERR_CANCELLED; + if (RT_SUCCESS(rc)) + { + /* If waiting succeeded, return the overall + * result code. */ + rc = mRc; + } + } + + return rc; +} + +GuestWaitEvent::GuestWaitEvent(uint32_t uCID, + const GuestEventTypes &lstEvents) +{ + int rc2 = Init(uCID); + AssertRC(rc2); /** @todo Throw exception here. */ + + mEventTypes = lstEvents; +} + +GuestWaitEvent::GuestWaitEvent(uint32_t uCID) +{ + int rc2 = Init(uCID); + AssertRC(rc2); /** @todo Throw exception here. */ +} + +GuestWaitEvent::~GuestWaitEvent(void) +{ + +} + +/** + * Cancels the event. + */ +int GuestWaitEvent::Cancel(void) +{ + AssertReturn(!mfAborted, VERR_CANCELLED); + ASMAtomicWriteBool(&mfAborted, true); + +#ifdef DEBUG_andy + LogFlowThisFunc(("Cancelling %p ...\n")); +#endif + return RTSemEventSignal(mEventSem); +} + +int GuestWaitEvent::Init(uint32_t uCID) +{ + return GuestWaitEventBase::Init(uCID); +} + +/** + * Signals the event. + * + * @return IPRT status code. + * @param pEvent Public IEvent to associate. + * Optional. + */ +int GuestWaitEvent::SignalExternal(IEvent *pEvent) +{ + AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); + + if (pEvent) + mEvent = pEvent; + + return RTSemEventSignal(mEventSem); +} + diff --git a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp index 36d262b9..52d0cf95 100644 --- a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp +++ b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp @@ -1,11 +1,11 @@ /* $Id: GuestDirectoryImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest directory handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -58,54 +58,72 @@ void GuestDirectory::FinalRelease(void) // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// -int GuestDirectory::init(GuestSession *aSession, - const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags) +int GuestDirectory::init(Console *pConsole, GuestSession *pSession, + ULONG uDirID, const GuestDirectoryOpenInfo &openInfo) { - LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n", - strPath.c_str(), strFilter.c_str(), uFlags)); + LogFlowThisFunc(("pConsole=%p, pSession=%p, uDirID=%RU32, strPath=%s, strFilter=%s, uFlags=%x\n", + pConsole, pSession, uDirID, openInfo.mPath.c_str(), openInfo.mFilter.c_str(), + openInfo.mFlags)); + + AssertPtrReturn(pConsole, VERR_INVALID_POINTER); + AssertPtrReturn(pSession, VERR_INVALID_POINTER); /* Enclose the state transition NotReady->InInit->Ready. */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); - mData.mSession = aSession; - mData.mName = strPath; - mData.mFilter = strFilter; - mData.mFlags = uFlags; - - /* Start the directory process on the guest. */ - GuestProcessStartupInfo procInfo; - procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str())); - procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS); - procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */ - procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; - - procInfo.mArguments.push_back(Utf8Str("--machinereadable")); - /* We want the long output format which contains all the object details. */ - procInfo.mArguments.push_back(Utf8Str("-l")); +#ifndef VBOX_WITH_GUEST_CONTROL + autoInitSpan.setSucceeded(); + return VINF_SUCCESS; +#else + int vrc = bindToSession(pConsole, pSession, uDirID /* Object ID */); + if (RT_SUCCESS(vrc)) + { + mSession = pSession; + + mData.mID = uDirID; + mData.mOpenInfo = openInfo; + } + + if (RT_SUCCESS(vrc)) + { + /* Start the directory process on the guest. */ + GuestProcessStartupInfo procInfo; + procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", openInfo.mPath.c_str())); + procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS); + procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */ + procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; + + procInfo.mArguments.push_back(Utf8Str("--machinereadable")); + /* We want the long output format which contains all the object details. */ + procInfo.mArguments.push_back(Utf8Str("-l")); #if 0 /* Flags are not supported yet. */ - if (uFlags & DirectoryOpenFlag_NoSymlinks) - procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */ + if (uFlags & DirectoryOpenFlag_NoSymlinks) + procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */ #endif - /** @todo Recursion support? */ - procInfo.mArguments.push_back(strPath); /* The directory we want to open. */ + /** @todo Recursion support? */ + procInfo.mArguments.push_back(openInfo.mPath); /* The directory we want to open. */ + + /* + * Start the process asynchronously and keep it around so that we can use + * it later in subsequent read() calls. + * Note: No guest rc available because operation is asynchronous. + */ + vrc = mData.mProcessTool.Init(mSession, procInfo, + true /* Async */, NULL /* Guest rc */); + } - /* - * Start the process asynchronously and keep it around so that we can use - * it later in subsequent read() calls. - * Note: No guest rc available because operation is asynchronous. - */ - int rc = mData.mProcessTool.Init(mData.mSession, procInfo, - true /* Async */, NULL /* Guest rc */); - if (RT_SUCCESS(rc)) + if (RT_SUCCESS(vrc)) { /* Confirm a successful initialization when it's the case. */ autoInitSpan.setSucceeded(); - return rc; + return vrc; } + else + autoInitSpan.setFailed(); - autoInitSpan.setFailed(); - return rc; + return vrc; +#endif /* VBOX_WITH_GUEST_CONTROL */ } /** @@ -114,7 +132,7 @@ int GuestDirectory::init(GuestSession *aSession, */ void GuestDirectory::uninit(void) { - LogFlowThisFunc(("\n")); + LogFlowThisFuncEnter(); /* Enclose the state transition Ready->InUninit->NotReady. */ AutoUninitSpan autoUninitSpan(this); @@ -138,7 +156,7 @@ STDMETHODIMP GuestDirectory::COMGETTER(DirectoryName)(BSTR *aName) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mName.cloneTo(aName); + mData.mOpenInfo.mPath.cloneTo(aName); return S_OK; } @@ -154,7 +172,7 @@ STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mFilter.cloneTo(aFilter); + mData.mOpenInfo.mFilter.cloneTo(aFilter); return S_OK; } @@ -162,6 +180,96 @@ STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter) // private methods ///////////////////////////////////////////////////////////////////////////// +int GuestDirectory::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + LogFlowThisFunc(("strPath=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n", + mData.mOpenInfo.mPath.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); + + int vrc; + switch (pCbCtx->uFunction) + { + case GUEST_DIR_NOTIFY: + { + int idx = 1; /* Current parameter index. */ + CALLBACKDATA_DIR_NOTIFY dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType); + pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc); + + int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ + + LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n", + dataCb.uType, guestRc)); + + switch (dataCb.uType) + { + /* Nothing here yet, nothing to dispatch further. */ + + default: + vrc = VERR_NOT_SUPPORTED; + break; + } + break; + } + + default: + /* Silently ignore not implemented functions. */ + vrc = VERR_NOT_SUPPORTED; + break; + } + +#ifdef DEBUG + LogFlowFuncLeaveRC(vrc); +#endif + return vrc; +} + +/* static */ +Utf8Str GuestDirectory::guestErrorToString(int guestRc) +{ + Utf8Str strError; + + /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ + switch (guestRc) + { + case VERR_DIR_NOT_EMPTY: + strError += Utf8StrFmt("Directoy is not empty"); + break; + + default: + strError += Utf8StrFmt("%Rrc", guestRc); + break; + } + + return strError; +} + +/** + * Called by IGuestSession right before this directory gets + * removed from the public directory list. + */ +int GuestDirectory::onRemove(void) +{ + LogFlowThisFuncEnter(); + + int vrc = VINF_SUCCESS; + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/* static */ +HRESULT GuestDirectory::setErrorExternal(VirtualBoxBase *pInterface, int guestRc) +{ + AssertPtr(pInterface); + AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n")); + + return pInterface->setError(VBOX_E_IPRT_ERROR, GuestDirectory::guestErrorToString(guestRc).c_str()); +} + // implementation of public methods ///////////////////////////////////////////////////////////////////////////// @@ -175,20 +283,38 @@ STDMETHODIMP GuestDirectory::Close(void) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - AssertPtr(mData.mSession); - int rc = mData.mSession->directoryRemoveFromList(this); + HRESULT hr = S_OK; + + int guestRc; + int rc = mData.mProcessTool.Terminate(30 * 1000, &guestRc); + if (RT_FAILURE(rc)) + { + switch (rc) + { + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestProcess::setErrorExternal(this, guestRc); + break; - mData.mProcessTool.Terminate(); + case VERR_NOT_SUPPORTED: + /* Silently skip old Guest Additions which do not support killing the + * the guest directory handling process. */ + break; - /* - * Release autocaller before calling uninit. - */ - autoCaller.release(); + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Terminating open guest directory \"%s\" failed: %Rrc"), + mData.mOpenInfo.mPath.c_str(), rc); + break; + } + } - uninit(); + AssertPtr(mSession); + int rc2 = mSession->directoryRemoveFromList(this); + if (RT_SUCCESS(rc)) + rc = rc2; - LogFlowFuncLeaveRC(rc); - return S_OK; + LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -262,34 +388,34 @@ STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; case VERR_ACCESS_DENIED: hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"), - mData.mName.c_str()); + mData.mOpenInfo.mPath.c_str()); break; case VERR_PATH_NOT_FOUND: hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"), - mData.mName.c_str()); + mData.mOpenInfo.mPath.c_str()); break; case VERR_NO_MORE_FILES: /* See SDK reference. */ hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""), - mData.mName.c_str()); + mData.mOpenInfo.mPath.c_str()); break; default: hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"), - mData.mName.c_str(), rc); + mData.mOpenInfo.mPath.c_str(), rc); break; } } - LogFlowFuncLeaveRC(rc); + LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } diff --git a/src/VBox/Main/src-client/GuestDnDImpl.cpp b/src/VBox/Main/src-client/GuestDnDImpl.cpp index 2e07a950..6732e163 100644 --- a/src/VBox/Main/src-client/GuestDnDImpl.cpp +++ b/src/VBox/Main/src-client/GuestDnDImpl.cpp @@ -440,7 +440,7 @@ void GuestDnDPrivate::toFormatSafeArray(const RTCString &strFormats, ComSafeArra { RTCList list = strFormats.split("\r\n"); size_t i = 0; - while(i < list.size()) + while (i < list.size()) { /* Only keep allowed format types. */ if (!m_sstrAllowedMimeTypes.contains(list.at(i))) diff --git a/src/VBox/Main/src-client/GuestFileImpl.cpp b/src/VBox/Main/src-client/GuestFileImpl.cpp index 19afbcc2..8a0ce53e 100644 --- a/src/VBox/Main/src-client/GuestFileImpl.cpp +++ b/src/VBox/Main/src-client/GuestFileImpl.cpp @@ -1,11 +1,10 @@ - /* $Id: GuestFileImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest file handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,11 +22,18 @@ #include "GuestFileImpl.h" #include "GuestSessionImpl.h" #include "GuestCtrlImplPrivate.h" +#include "ConsoleImpl.h" +#include "VirtualBoxErrorInfoImpl.h" #include "Global.h" #include "AutoCaller.h" +#include "VBoxEvents.h" + +#include /* For unconst(). */ +#include #include +#include #ifdef LOG_GROUP #undef LOG_GROUP @@ -36,6 +42,64 @@ #include +/** + * Internal listener class to serve events in an + * active manner, e.g. without polling delays. + */ +class GuestFileListener +{ +public: + + GuestFileListener(void) + { + } + + HRESULT init(GuestFile *pFile) + { + AssertPtrReturn(pFile, E_POINTER); + mFile = pFile; + return S_OK; + } + + void uninit(void) + { + mFile = NULL; + } + + STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent) + { + switch (aType) + { + case VBoxEventType_OnGuestFileStateChanged: + case VBoxEventType_OnGuestFileOffsetChanged: + case VBoxEventType_OnGuestFileRead: + case VBoxEventType_OnGuestFileWrite: + { + AssertPtrReturn(mFile, E_POINTER); + int rc2 = mFile->signalWaitEvent(aType, aEvent); +#ifdef DEBUG_andy + LogFlowFunc(("Signalling events of type=%RU32, file=%p resulted in rc=%Rrc\n", + aType, mFile, rc2)); +#endif + break; + } + + default: + AssertMsgFailed(("Unhandled event %RU32\n", aType)); + break; + } + + return S_OK; + } + +private: + + GuestFile *mFile; +}; +typedef ListenerImpl GuestFileListenerImpl; + +VBOX_LISTENER_DECLARE(GuestFileListenerImpl) + // constructor / destructor ///////////////////////////////////////////////////////////////////////////// @@ -43,7 +107,7 @@ DEFINE_EMPTY_CTOR_DTOR(GuestFile) HRESULT GuestFile::FinalConstruct(void) { - LogFlowThisFunc(("\n")); + LogFlowThisFuncEnter(); return BaseFinalConstruct(); } @@ -58,29 +122,100 @@ void GuestFile::FinalRelease(void) // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// -int GuestFile::init(GuestSession *pSession, const Utf8Str &strPath, - const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, - int64_t iOffset, int *pGuestRc) +/** + * Initializes a file object but does *not* open the file on the guest + * yet. This is done in the dedidcated openFile call. + * + * @return IPRT status code. + * @param pConsole Pointer to console object. + * @param pSession Pointer to session object. + * @param uFileID Host-based file ID (part of the context ID). + * @param openInfo File opening information. + */ +int GuestFile::init(Console *pConsole, GuestSession *pSession, + ULONG uFileID, const GuestFileOpenInfo &openInfo) { - /* Enclose the state transition NotReady->InInit->Ready. */ - AutoInitSpan autoInitSpan(this); - AssertReturn(autoInitSpan.isOk(), E_FAIL); + LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n", + pConsole, pSession, uFileID, openInfo.mFileName.c_str())); - mData.mSession = pSession; - mData.mCreationMode = uCreationMode; - mData.mDisposition = GuestFile::getDispositionFromString(strDisposition); - mData.mFileName = strPath; - mData.mInitialSize = 0; - mData.mOpenMode = GuestFile::getOpenModeFromString(strOpenMode); - mData.mOffset = iOffset; + AssertPtrReturn(pConsole, VERR_INVALID_POINTER); + AssertPtrReturn(pSession, VERR_INVALID_POINTER); - /** @todo Validate parameters! */ - /** @todo Implement guest side file handling! */ + /* Enclose the state transition NotReady->InInit->Ready. */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); - /* Confirm a successful initialization when it's the case. */ +#ifndef VBOX_WITH_GUEST_CONTROL autoInitSpan.setSucceeded(); - return VINF_SUCCESS; +#else + int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */); + if (RT_SUCCESS(vrc)) + { + mSession = pSession; + + mData.mID = uFileID; + mData.mInitialSize = 0; + mData.mStatus = FileStatus_Undefined; + mData.mOpenInfo = openInfo; + + unconst(mEventSource).createObject(); + HRESULT hr = mEventSource->init(); + if (FAILED(hr)) + vrc = VERR_COM_UNEXPECTED; + } + + if (RT_SUCCESS(vrc)) + { + try + { + GuestFileListener *pListener = new GuestFileListener(); + ComObjPtr thisListener; + HRESULT hr = thisListener.createObject(); + if (SUCCEEDED(hr)) + hr = thisListener->init(pListener, this); + + if (SUCCEEDED(hr)) + { + com::SafeArray eventTypes; + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileRead); + eventTypes.push_back(VBoxEventType_OnGuestFileWrite); + hr = mEventSource->RegisterListener(thisListener, + ComSafeArrayAsInParam(eventTypes), + TRUE /* Active listener */); + if (SUCCEEDED(hr)) + { + vrc = baseInit(); + if (RT_SUCCESS(vrc)) + { + mLocalListener = thisListener; + } + } + else + vrc = VERR_COM_UNEXPECTED; + } + else + vrc = VERR_COM_UNEXPECTED; + } + catch(std::bad_alloc &) + { + vrc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(vrc)) + { + /* Confirm a successful initialization when it's the case. */ + autoInitSpan.setSucceeded(); + } + else + autoInitSpan.setFailed(); + + LogFlowFuncLeaveRC(vrc); + return vrc; +#endif /* VBOX_WITH_GUEST_CONTROL */ } /** @@ -89,13 +224,16 @@ int GuestFile::init(GuestSession *pSession, const Utf8Str &strPath, */ void GuestFile::uninit(void) { - LogFlowThisFunc(("\n")); - /* Enclose the state transition Ready->InUninit->NotReady. */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; + LogFlowThisFuncEnter(); + +#ifdef VBOX_WITH_GUEST_CONTROL + baseUninit(); +#endif LogFlowThisFuncLeave(); } @@ -114,13 +252,13 @@ STDMETHODIMP GuestFile::COMGETTER(CreationMode)(ULONG *aCreationMode) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aCreationMode = mData.mCreationMode; + *aCreationMode = mData.mOpenInfo.mCreationMode; return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } -STDMETHODIMP GuestFile::COMGETTER(Disposition)(ULONG *aDisposition) +STDMETHODIMP GuestFile::COMGETTER(Disposition)(BSTR *aDisposition) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); @@ -132,7 +270,24 @@ STDMETHODIMP GuestFile::COMGETTER(Disposition)(ULONG *aDisposition) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aDisposition = mData.mDisposition; + mData.mOpenInfo.mDisposition.cloneTo(aDisposition); + + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestFile::COMGETTER(EventSource)(IEventSource ** aEventSource) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + CheckComArgOutPointerValid(aEventSource); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* No need to lock - lifetime constant. */ + mEventSource.queryInterfaceTo(aEventSource); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ @@ -150,7 +305,25 @@ STDMETHODIMP GuestFile::COMGETTER(FileName)(BSTR *aFileName) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mFileName.cloneTo(aFileName); + mData.mOpenInfo.mFileName.cloneTo(aFileName); + + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestFile::COMGETTER(Id)(ULONG *aID) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + CheckComArgOutPointerValid(aID); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aID = mData.mID; return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ @@ -186,13 +359,13 @@ STDMETHODIMP GuestFile::COMGETTER(Offset)(LONG64 *aOffset) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aOffset = mData.mOffset; + *aOffset = mData.mOffCurrent; return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } -STDMETHODIMP GuestFile::COMGETTER(OpenMode)(ULONG *aOpenMode) +STDMETHODIMP GuestFile::COMGETTER(OpenMode)(BSTR *aOpenMode) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); @@ -204,7 +377,25 @@ STDMETHODIMP GuestFile::COMGETTER(OpenMode)(ULONG *aOpenMode) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aOpenMode = mData.mOpenMode; + mData.mOpenInfo.mOpenMode.cloneTo(aOpenMode); + + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aStatus = mData.mStatus; return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ @@ -213,16 +404,865 @@ STDMETHODIMP GuestFile::COMGETTER(OpenMode)(ULONG *aOpenMode) // private methods ///////////////////////////////////////////////////////////////////////////// +int GuestFile::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n", + mData.mOpenInfo.mFileName.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); + + int vrc; + switch (pCbCtx->uFunction) + { + case GUEST_DISCONNECTED: + vrc = onGuestDisconnected(pCbCtx, pSvcCb); + break; + + case GUEST_FILE_NOTIFY: + vrc = onFileNotify(pCbCtx, pSvcCb); + break; + + default: + /* Silently ignore not implemented functions. */ + vrc = VERR_NOT_SUPPORTED; + break; + } + +#ifdef DEBUG + LogFlowFuncLeaveRC(vrc); +#endif + return vrc; +} + +int GuestFile::closeFile(int *pGuestRc) +{ + LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str())); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* Guest file ID */); + + vrc = sendCommand(HOST_FILE_CLOSE, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */, + NULL /* FileStatus */, pGuestRc); + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + /* static */ -uint32_t GuestFile::getDispositionFromString(const Utf8Str &strDisposition) +Utf8Str GuestFile::guestErrorToString(int guestRc) { - return 0; /** @todo Implement me! */ + Utf8Str strError; + + /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ + switch (guestRc) + { + case VERR_ALREADY_EXISTS: + strError += Utf8StrFmt(tr("File already exists")); + break; + + case VERR_FILE_NOT_FOUND: + strError += Utf8StrFmt(tr("File not found")); + break; + + case VERR_NET_HOST_NOT_FOUND: + strError += Utf8StrFmt(tr("Host name not found")); + break; + + case VERR_SHARING_VIOLATION: + strError += Utf8StrFmt(tr("Sharing violation")); + break; + + default: + strError += Utf8StrFmt("%Rrc", guestRc); + break; + } + + return strError; +} + +int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); + + LogFlowThisFuncEnter(); + + if (pSvcCbData->mParms < 3) + return VERR_INVALID_PARAMETER; + + int vrc = VINF_SUCCESS; + + int idx = 1; /* Current parameter index. */ + CALLBACKDATA_FILE_NOTIFY dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType); + pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc); + + FileStatus_T fileStatus = FileStatus_Undefined; + int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ + + LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n", + dataCb.uType, guestRc)); + + if (RT_FAILURE(guestRc)) + { + int rc2 = setFileStatus(FileStatus_Error, guestRc); + AssertRC(rc2); + + rc2 = signalWaitEventInternal(pCbCtx, + guestRc, NULL /* pPayload */); + AssertRC(rc2); + + return VINF_SUCCESS; /* Report to the guest. */ + } + + switch (dataCb.uType) + { + case GUEST_FILE_NOTIFYTYPE_ERROR: + { + int rc2 = setFileStatus(FileStatus_Error, guestRc); + AssertRC(rc2); + + break; + } + + case GUEST_FILE_NOTIFYTYPE_OPEN: + { + if (pSvcCbData->mParms == 4) + { + pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID), + ("File ID %RU32 does not match context ID %RU32\n", mData.mID, + VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID))); + + /* Set the initial offset. On the guest the whole opening operation + * would fail if an initial seek isn't possible. */ + mData.mOffCurrent = mData.mOpenInfo.mInitialOffset; + } + + /* Set the process status. */ + int rc2 = setFileStatus(FileStatus_Open, guestRc); + AssertRC(rc2); + } + else + vrc = VERR_NOT_SUPPORTED; + + break; + } + + case GUEST_FILE_NOTIFYTYPE_CLOSE: + { + int rc2 = setFileStatus(FileStatus_Closed, guestRc); + AssertRC(rc2); + + break; + } + + case GUEST_FILE_NOTIFYTYPE_READ: + { + if (pSvcCbData->mParms == 4) + { + pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData, + &dataCb.u.read.cbData); + uint32_t cbRead = dataCb.u.read.cbData; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + mData.mOffCurrent += cbRead; + + alock.release(); + + com::SafeArray data((size_t)cbRead); + data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead); + + fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, + cbRead, ComSafeArrayAsInParam(data)); + } + else + vrc = VERR_NOT_SUPPORTED; + break; + } + + case GUEST_FILE_NOTIFYTYPE_WRITE: + { + if (pSvcCbData->mParms == 4) + { + pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + mData.mOffCurrent += dataCb.u.write.cbWritten; + uint64_t uOffCurrent = mData.mOffCurrent; + + alock.release(); + + fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent, + dataCb.u.write.cbWritten); + } + else + vrc = VERR_NOT_SUPPORTED; + break; + } + + case GUEST_FILE_NOTIFYTYPE_SEEK: + { + if (pSvcCbData->mParms == 4) + { + pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + mData.mOffCurrent = dataCb.u.seek.uOffActual; + + alock.release(); + + fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, + dataCb.u.seek.uOffActual, 0 /* Processed */); + } + else + vrc = VERR_NOT_SUPPORTED; + break; + } + + case GUEST_FILE_NOTIFYTYPE_TELL: + { + if (pSvcCbData->mParms == 4) + { + pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + mData.mOffCurrent = dataCb.u.tell.uOffActual; + + alock.release(); + + fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, + dataCb.u.tell.uOffActual, 0 /* Processed */); + } + else + vrc = VERR_NOT_SUPPORTED; + break; + } + + default: + vrc = VERR_NOT_SUPPORTED; + break; + } + + if (RT_SUCCESS(vrc)) + { + GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb)); + int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload); + AssertRC(rc2); + } + + LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n", + dataCb.uType, dataCb.rc)); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); + + int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/** + * Called by IGuestSession right before this file gets removed + * from the public file list. + */ +int GuestFile::onRemove(void) +{ + LogFlowThisFuncEnter(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc = VINF_SUCCESS; + + /* + * Note: The event source stuff holds references to this object, + * so make sure that this is cleaned up *before* calling uninit(). + */ + if (!mEventSource.isNull()) + { + mEventSource->UnregisterListener(mLocalListener); + + mLocalListener.setNull(); + unconst(mEventSource).setNull(); + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::openFile(uint32_t uTimeoutMS, int *pGuestRc) +{ + LogFlowThisFuncEnter(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + LogFlowThisFunc(("strFile=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%RU32, uOffset=%RU64\n", + mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(), + mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mInitialOffset)); + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[8]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(), + (ULONG)mData.mOpenInfo.mFileName.length() + 1); + paParms[i++].setPointer((void*)mData.mOpenInfo.mOpenMode.c_str(), + (ULONG)mData.mOpenInfo.mOpenMode.length() + 1); + paParms[i++].setPointer((void*)mData.mOpenInfo.mDisposition.c_str(), + (ULONG)mData.mOpenInfo.mDisposition.length() + 1); + paParms[i++].setPointer((void*)mData.mOpenInfo.mSharingMode.c_str(), + (ULONG)mData.mOpenInfo.mSharingMode.length() + 1); + paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode); + paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset); + + alock.release(); /* Drop write lock before sending. */ + + vrc = sendCommand(HOST_FILE_OPEN, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForStatusChange(pEvent, uTimeoutMS, + NULL /* FileStatus */, pGuestRc); + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, + void* pvData, uint32_t cbData, uint32_t* pcbRead) +{ + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + + LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", + uSize, uTimeoutMS, pvData, cbData)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileRead); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* File handle */); + paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); + + alock.release(); /* Drop write lock before sending. */ + + uint32_t cbRead; + vrc = sendCommand(HOST_FILE_READ, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead); + + if (RT_SUCCESS(vrc)) + { + LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); + + if (pcbRead) + *pcbRead = cbRead; + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, + void* pvData, size_t cbData, size_t* pcbRead) +{ + LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", + uOffset, uSize, uTimeoutMS, pvData, cbData)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileRead); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* File handle */); + paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); + paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); + + alock.release(); /* Drop write lock before sending. */ + + uint32_t cbRead; + vrc = sendCommand(HOST_FILE_READ_AT, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead); + + if (RT_SUCCESS(vrc)) + { + LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); + + if (pcbRead) + *pcbRead = cbRead; + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType, + uint32_t uTimeoutMS, uint64_t *puOffset) +{ + LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n", + iOffset, uTimeoutMS)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* File handle */); + paParms[i++].setUInt32(eSeekType /* Seek method */); + /** @todo uint64_t vs. int64_t! */ + paParms[i++].setUInt64((uint64_t)iOffset /* Offset (in bytes) to start reading */); + + alock.release(); /* Drop write lock before sending. */ + + vrc = sendCommand(HOST_FILE_SEEK, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForOffsetChange(pEvent, uTimeoutMS, puOffset); + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; } /* static */ -uint32_t GuestFile::getOpenModeFromString(const Utf8Str &strOpenMode) +HRESULT GuestFile::setErrorExternal(VirtualBoxBase *pInterface, int guestRc) +{ + AssertPtr(pInterface); + AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n")); + + return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::guestErrorToString(guestRc).c_str()); +} + +int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc) +{ + LogFlowThisFuncEnter(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n", + mData.mStatus, fileStatus, fileRc)); + +#ifdef VBOX_STRICT + if (fileStatus == FileStatus_Error) + { + AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc)); + } + else + AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc)); +#endif + + if (mData.mStatus != fileStatus) + { + mData.mStatus = fileStatus; + mData.mLastError = fileRc; + + ComObjPtr errorInfo; + HRESULT hr = errorInfo.createObject(); + ComAssertComRC(hr); + if (RT_FAILURE(fileRc)) + { + hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc, + COM_IIDOF(IGuestFile), getComponentName(), + guestErrorToString(fileRc)); + ComAssertComRC(hr); + } + + alock.release(); /* Release lock before firing off event. */ + + fireGuestFileStateChangedEvent(mEventSource, mSession, + this, fileStatus, errorInfo); + } + + return VINF_SUCCESS; +} + +int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent, + uint32_t uTimeoutMS, uint64_t *puOffset) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + if (evtType == VBoxEventType_OnGuestFileOffsetChanged) + { + if (puOffset) + { + ComPtr pFileEvent = pIEvent; + Assert(!pFileEvent.isNull()); + + HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset); + ComAssertComRC(hr); + } + } + else + vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; + } + + return vrc; +} + +int GuestFile::waitForRead(GuestWaitEvent *pEvent, + uint32_t uTimeoutMS, + void *pvData, size_t cbData, uint32_t *pcbRead) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + if (evtType == VBoxEventType_OnGuestFileRead) + { + ComPtr pFileEvent = pIEvent; + Assert(!pFileEvent.isNull()); + + HRESULT hr; + if (pvData) + { + com::SafeArray data; + hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data)); + ComAssertComRC(hr); + size_t cbRead = data.size(); + if ( cbRead + && cbRead <= cbData) + { + memcpy(pvData, data.raw(), data.size()); + } + else + vrc = VERR_BUFFER_OVERFLOW; + } + if (pcbRead) + { + hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead); + ComAssertComRC(hr); + } + } + else + vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; + } + + return vrc; +} + +int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, + FileStatus_T *pFileStatus, int *pGuestRc) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + /* pFileStatus is optional. */ + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + Assert(evtType == VBoxEventType_OnGuestFileStateChanged); + ComPtr pFileEvent = pIEvent; + Assert(!pFileEvent.isNull()); + + HRESULT hr; + if (pFileStatus) + { + hr = pFileEvent->COMGETTER(Status)(pFileStatus); + ComAssertComRC(hr); + } + + ComPtr errorInfo; + hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam()); + ComAssertComRC(hr); + + LONG lGuestRc; + hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc); + ComAssertComRC(hr); + + LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n", + lGuestRc, lGuestRc)); + + if (RT_FAILURE((int)lGuestRc)) + vrc = VERR_GSTCTL_GUEST_ERROR; + + if (pGuestRc) + *pGuestRc = (int)lGuestRc; + } + + return vrc; +} + +int GuestFile::waitForWrite(GuestWaitEvent *pEvent, + uint32_t uTimeoutMS, uint32_t *pcbWritten) { - return 0; /** @todo Implement me! */ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + if (evtType == VBoxEventType_OnGuestFileWrite) + { + if (pcbWritten) + { + ComPtr pFileEvent = pIEvent; + Assert(!pFileEvent.isNull()); + + HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten); + ComAssertComRC(hr); + } + } + else + vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; + } + + return vrc; +} + +int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, + uint32_t *pcbWritten) +{ + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + + LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", + uTimeoutMS, pvData, cbData)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileWrite); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[8]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* File handle */); + paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); + paParms[i++].setPointer(pvData, cbData); + + alock.release(); /* Drop write lock before sending. */ + + uint32_t cbWritten; + vrc = sendCommand(HOST_FILE_WRITE, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten); + + if (RT_SUCCESS(vrc)) + { + LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); + + if (cbWritten) + *pcbWritten = cbWritten; + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, + void *pvData, uint32_t cbData, uint32_t *pcbWritten) +{ + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + + LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", + uOffset, uTimeoutMS, pvData, cbData)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestFileWrite); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[8]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mID /* File handle */); + paParms[i++].setUInt64(uOffset /* Offset where to starting writing */); + paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); + paParms[i++].setPointer(pvData, cbData); + + alock.release(); /* Drop write lock before sending. */ + + uint32_t cbWritten; + vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten); + + if (RT_SUCCESS(vrc)) + { + LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); + + if (cbWritten) + *pcbWritten = cbWritten; + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; } // implementation of public methods @@ -238,17 +1278,27 @@ STDMETHODIMP GuestFile::Close(void) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - AssertPtr(mData.mSession); - int rc = mData.mSession->fileRemoveFromList(this); + /* Close file on guest. */ + int guestRc; + int rc = closeFile(&guestRc); + /* On failure don't return here, instead do all the cleanup + * work first and then return an error. */ - /* - * Release autocaller before calling uninit. - */ - autoCaller.release(); + AssertPtr(mSession); + int rc2 = mSession->fileRemoveFromList(this); + if (RT_SUCCESS(rc)) + rc = rc2; - uninit(); + if (RT_FAILURE(rc)) + { + if (rc == VERR_GSTCTL_GUEST_ERROR) + return GuestFile::setErrorExternal(this, guestRc); + + return setError(VBOX_E_IPRT_ERROR, + tr("Closing guest file failed with %Rrc\n"), rc); + } - LogFlowFuncLeaveRC(rc); + LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -270,10 +1320,41 @@ STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BY #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + if (aToRead == 0) + return setError(E_INVALIDARG, tr("The size to read is zero")); + CheckComArgOutSafeArrayPointerValid(aData); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + com::SafeArray data((size_t)aToRead); + Assert(data.size() >= aToRead); + + HRESULT hr = S_OK; + + uint32_t cbRead; + int vrc = readData(aToRead, aTimeoutMS, + data.raw(), aToRead, &cbRead); + if (RT_SUCCESS(vrc)) + { + if (data.size() != cbRead) + data.resize(cbRead); + data.detachTo(ComSafeArrayOutArg(aData)); + } + else + { + switch (vrc) + { + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Reading from file \"%s\" failed: %Rrc"), + mData.mOpenInfo.mFileName.c_str(), vrc); + break; + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -282,10 +1363,41 @@ STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + if (aToRead == 0) + return setError(E_INVALIDARG, tr("The size to read is zero")); + CheckComArgOutSafeArrayPointerValid(aData); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + com::SafeArray data((size_t)aToRead); + Assert(data.size() >= aToRead); + + HRESULT hr = S_OK; + + size_t cbRead; + int vrc = readDataAt(aOffset, aToRead, aTimeoutMS, + data.raw(), aToRead, &cbRead); + if (RT_SUCCESS(vrc)) + { + if (data.size() != cbRead) + data.resize(cbRead); + data.detachTo(ComSafeArrayOutArg(aData)); + } + else + { + switch (vrc) + { + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"), + mData.mOpenInfo.mFileName.c_str(), aOffset, vrc); + break; + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -294,10 +1406,45 @@ STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType) #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + LogFlowThisFuncEnter(); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = S_OK; + + GUEST_FILE_SEEKTYPE eSeekType; + switch (aType) + { + case FileSeekType_Set: + eSeekType = GUEST_FILE_SEEKTYPE_BEGIN; + break; + + case FileSeekType_Current: + eSeekType = GUEST_FILE_SEEKTYPE_CURRENT; + break; + + default: + return setError(E_INVALIDARG, tr("Invalid seek type specified")); + break; /* Never reached. */ + } + + int vrc = seekAt(aOffset, eSeekType, + 30 * 1000 /* 30s timeout */, NULL /* puOffset */); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"), + mData.mOpenInfo.mFileName.c_str(), aOffset, vrc); + break; + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -318,10 +1465,33 @@ STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULO #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + LogFlowThisFuncEnter(); + + CheckComArgSafeArrayNotNull(aData); + CheckComArgOutPointerValid(aWritten); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = S_OK; + + com::SafeArray data(ComSafeArrayInArg(aData)); + int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), + (uint32_t*)aWritten); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Writing %zubytes to file \"%s\" failed: %Rrc"), + data.size(), mData.mOpenInfo.mFileName.c_str(), vrc); + break; + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -330,10 +1500,33 @@ STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULO #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + LogFlowThisFuncEnter(); + + CheckComArgSafeArrayNotNull(aData); + CheckComArgOutPointerValid(aWritten); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = S_OK; + + com::SafeArray data(ComSafeArrayInArg(aData)); + int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), + (uint32_t*)aWritten); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"), + data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc); + break; + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } diff --git a/src/VBox/Main/src-client/GuestFsObjInfoImpl.cpp b/src/VBox/Main/src-client/GuestFsObjInfoImpl.cpp index 99219da7..64547edc 100644 --- a/src/VBox/Main/src-client/GuestFsObjInfoImpl.cpp +++ b/src/VBox/Main/src-client/GuestFsObjInfoImpl.cpp @@ -1,7 +1,6 @@ - /* $Id: GuestFsObjInfoImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest file system object information handling. */ /* diff --git a/src/VBox/Main/src-client/GuestImpl.cpp b/src/VBox/Main/src-client/GuestImpl.cpp index 4f096e4e..41469b0c 100644 --- a/src/VBox/Main/src-client/GuestImpl.cpp +++ b/src/VBox/Main/src-client/GuestImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,9 +29,12 @@ #include "AutoCaller.h" #include "Logging.h" #include "Performance.h" +#include "VBoxEvents.h" #include #include +#include +#include #include #include #include @@ -77,31 +80,41 @@ HRESULT Guest::init(Console *aParent) autoInitSpan.setSucceeded(); ULONG aMemoryBalloonSize; - HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize); - if (ret == S_OK) + HRESULT hr = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize); + if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ mMemoryBalloonSize = aMemoryBalloonSize; else - mMemoryBalloonSize = 0; /* Default is no ballooning */ + mMemoryBalloonSize = 0; /* Default is no ballooning */ BOOL fPageFusionEnabled; - ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled); - if (ret == S_OK) + hr = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled); + if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ mfPageFusionEnabled = fPageFusionEnabled; else - mfPageFusionEnabled = false; /* Default is no page fusion*/ + mfPageFusionEnabled = false; /* Default is no page fusion*/ - mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */ + mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */ mCollectVMMStats = false; /* Clear statistics. */ + mNetStatRx = mNetStatTx = 0; + mNetStatLastTs = RTTimeNanoTS(); for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++) mCurrentGuestStat[i] = 0; - mGuestValidStats = pm::GUESTSTATMASK_NONE; + mVmValidStats = pm::VMSTATMASK_NONE; mMagic = GUEST_MAGIC; int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */, &Guest::staticUpdateStats, this); - AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc)); + AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc)); + +#ifdef VBOX_WITH_GUEST_CONTROL + hr = unconst(mEventSource).createObject(); + if (SUCCEEDED(hr)) + hr = mEventSource->init(); +#else + hr = S_OK; +#endif try { @@ -112,10 +125,10 @@ HRESULT Guest::init(Console *aParent) } catch(std::bad_alloc &) { - return E_OUTOFMEMORY; + hr = E_OUTOFMEMORY; } - return S_OK; + return hr; } /** @@ -145,7 +158,7 @@ void Guest::uninit() { #ifdef DEBUG ULONG cRefs = itSessions->second->AddRef(); - LogFlowThisFunc(("pSession=%p, cRefs=%RU32\n", (GuestSession *)itSessions->second, cRefs > 0 ? cRefs - 1 : 0)); + LogFlowThisFunc(("sessionID=%RU32, cRefs=%RU32\n", itSessions->first, cRefs > 1 ? cRefs - 1 : 0)); itSessions->second->Release(); #endif itSessions->second->uninit(); @@ -162,13 +175,16 @@ void Guest::uninit() } #endif +#ifdef VBOX_WITH_GUEST_CONTROL + unconst(mEventSource).setNull(); +#endif unconst(mParent) = NULL; LogFlowFuncLeave(); } /* static */ -void Guest::staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick) +DECLCALLBACK(void) Guest::staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick) { AssertReturnVoid(pvUser != NULL); Guest *guest = static_cast(pvUser); @@ -179,84 +195,155 @@ void Guest::staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick) NOREF(hTimerLR); } +/* static */ +int Guest::staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + STAMVISIBILITY enmVisiblity, const char *pszDesc, void *pvUser) +{ + AssertLogRelMsgReturn(enmType == STAMTYPE_COUNTER, ("Unexpected sample type %d ('%s')\n", enmType, pszName), VINF_SUCCESS); + AssertLogRelMsgReturn(enmUnit == STAMUNIT_BYTES, ("Unexpected sample unit %d ('%s')\n", enmUnit, pszName), VINF_SUCCESS); + + /* Get the base name w/ slash. */ + const char *pszLastSlash = strrchr(pszName, '/'); + AssertLogRelMsgReturn(pszLastSlash, ("Unexpected sample '%s'\n", pszName), VINF_SUCCESS); + + /* Receive or transmit? */ + bool fRx; + if (!strcmp(pszLastSlash, "/BytesReceived")) + fRx = true; + else if (!strcmp(pszLastSlash, "/BytesTransmitted")) + fRx = false; + else + AssertLogRelMsgFailedReturn(("Unexpected sample '%s'\n", pszName), VINF_SUCCESS); + +#if 0 /* not used for anything, so don't bother parsing it. */ + /* Find start of instance number. ASSUMES '/Public/Net/Name/Bytes...' */ + do + --pszLastSlash; + while (pszLastSlash > pszName && RT_C_IS_DIGIT(*pszLastSlash)); + pszLastSlash++; + + uint8_t uInstance; + int rc = RTStrToUInt8Ex(pszLastSlash, NULL, 10, &uInstance); + AssertLogRelMsgReturn(RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG && rc != VWRN_NEGATIVE_UNSIGNED, + ("%Rrc '%s'\n", rc, pszName), VINF_SUCCESS) +#endif + + /* Add the bytes to our counters. */ + PSTAMCOUNTER pCnt = (PSTAMCOUNTER)pvSample; + Guest *pGuest = (Guest *)pvUser; + uint64_t cb = pCnt->c; +#if 0 + LogFlowFunc(("%s i=%u d=%s %llu bytes\n", pszName, uInstance, fRx ? "RX" : "TX", cb)); +#else + LogFlowFunc(("%s d=%s %llu bytes\n", pszName, fRx ? "RX" : "TX", cb)); +#endif + if (fRx) + pGuest->mNetStatRx += cb; + else + pGuest->mNetStatTx += cb; + + return VINF_SUCCESS; +} + void Guest::updateStats(uint64_t iTick) { - uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal; - uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem; + uint64_t cbFreeTotal = 0; + uint64_t cbAllocTotal = 0; + uint64_t cbBalloonedTotal = 0; + uint64_t cbSharedTotal = 0; + uint64_t cbSharedMem = 0; + ULONG uNetStatRx = 0; + ULONG uNetStatTx = 0; + ULONG aGuestStats[GUESTSTATTYPE_MAX]; + RT_ZERO(aGuestStats); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - ULONG aGuestStats[GUESTSTATTYPE_MAX]; - RT_ZERO(aGuestStats); - ULONG validStats = mGuestValidStats; + ULONG validStats = mVmValidStats; /* Check if we have anything to report */ if (validStats) { - mGuestValidStats = pm::GUESTSTATMASK_NONE; + mVmValidStats = pm::VMSTATMASK_NONE; memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats)); } alock.release(); + /* * Calling SessionMachine may take time as the object resides in VBoxSVC * process. This is why we took a snapshot of currently collected stats * and released the lock. */ - uFreeTotal = 0; - uAllocTotal = 0; - uBalloonedTotal = 0; - uSharedTotal = 0; - uTotalMem = 0; - uPrivateMem = 0; - uSharedMem = 0; - uZeroMem = 0; - - Console::SafeVMPtr pVM(mParent); - if (pVM.isOk()) + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) { int rc; /* * There is no point in collecting VM shared memory if other memory - * statistics are not available yet. Or is it? + * statistics are not available yet. Or is there? */ if (validStats) { /* Query the missing per-VM memory statistics. */ - rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem); + uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbZeroMemIgn; + rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn); if (rc == VINF_SUCCESS) - { - validStats |= pm::GUESTSTATMASK_MEMSHARED; - } + validStats |= pm::VMSTATMASK_GUEST_MEMSHARED; } if (mCollectVMMStats) { - rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal); + rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal); AssertRC(rc); if (rc == VINF_SUCCESS) - { - validStats |= pm::GUESTSTATMASK_ALLOCVMM|pm::GUESTSTATMASK_FREEVMM| - pm::GUESTSTATMASK_BALOONVMM|pm::GUESTSTATMASK_SHAREDVMM; - } + validStats |= pm::VMSTATMASK_VMM_ALLOC | pm::VMSTATMASK_VMM_FREE + | pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED; } + uint64_t uRxPrev = mNetStatRx; + uint64_t uTxPrev = mNetStatTx; + mNetStatRx = mNetStatTx = 0; + rc = STAMR3Enum(ptrVM.rawUVM(), "/Public/Net/*/Bytes*", staticEnumStatsCallback, this); + AssertRC(rc); + + uint64_t uTsNow = RTTimeNanoTS(); + uint64_t cNsPassed = uTsNow - mNetStatLastTs; + if (cNsPassed >= 1000) + { + mNetStatLastTs = uTsNow; + + uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */ + uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */ + validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX; + LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, cNsPassed)); + } + else + { + /* Can happen on resume or if we're using a non-monotonic clock + source for the timer and the time is adjusted. */ + mNetStatRx = uRxPrev; + mNetStatTx = uTxPrev; + LogThisFunc(("Net Ts=%llu cNsPassed=%llu - too small interval\n", uTsNow, cNsPassed)); + } } - mParent->reportGuestStatistics(validStats, - aGuestStats[GUESTSTATTYPE_CPUUSER], - aGuestStats[GUESTSTATTYPE_CPUKERNEL], - aGuestStats[GUESTSTATTYPE_CPUIDLE], - /* Convert the units for RAM usage stats: page (4K) -> 1KB units */ - mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K), - mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K), - mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K), - (ULONG)(uSharedMem / _1K), /* bytes -> KB */ - mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K), - mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K), - (ULONG)(uAllocTotal / _1K), /* bytes -> KB */ - (ULONG)(uFreeTotal / _1K), - (ULONG)(uBalloonedTotal / _1K), - (ULONG)(uSharedTotal / _1K)); + mParent->reportVmStatistics(validStats, + aGuestStats[GUESTSTATTYPE_CPUUSER], + aGuestStats[GUESTSTATTYPE_CPUKERNEL], + aGuestStats[GUESTSTATTYPE_CPUIDLE], + /* Convert the units for RAM usage stats: page (4K) -> 1KB units */ + mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K), + mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K), + mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K), + (ULONG)(cbSharedMem / _1K), /* bytes -> KB */ + mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K), + mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K), + (ULONG)(cbAllocTotal / _1K), /* bytes -> KB */ + (ULONG)(cbFreeTotal / _1K), + (ULONG)(cbBalloonedTotal / _1K), + (ULONG)(cbSharedTotal / _1K), + uNetStatRx, + uNetStatTx); } // IGuest properties @@ -407,6 +494,26 @@ STDMETHODIMP Guest::COMGETTER(AdditionsRevision)(ULONG *a_puAdditionsRevision) return hrc; } +STDMETHODIMP Guest::COMGETTER(EventSource)(IEventSource ** aEventSource) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aEventSource); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + // no need to lock - lifetime constant + mEventSource.queryInterfaceTo(aEventSource); + + LogFlowFuncLeaveRC(S_OK); + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + STDMETHODIMP Guest::COMGETTER(Facilities)(ComSafeArrayOut(IAdditionsFacility *, aFacilities)) { CheckComArgOutSafeArrayPointerValid(aFacilities); @@ -570,47 +677,35 @@ STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, UL *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */ *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */ + /* Play safe or smth? */ + *aMemAllocTotal = 0; + *aMemFreeTotal = 0; + *aMemBalloonTotal = 0; + *aMemSharedTotal = 0; + *aMemShared = 0; + /* MUST release all locks before calling any PGM statistics queries, * as they are executed by EMT and that might deadlock us by VMM device * activity which waits for the Guest object lock. */ alock.release(); - Console::SafeVMPtr pVM (mParent); - if (pVM.isOk()) - { - uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal; - *aMemFreeTotal = 0; - int rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal); - AssertRC(rc); - if (rc == VINF_SUCCESS) - { - *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */ - *aMemFreeTotal = (ULONG)(uFreeTotal / _1K); - *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K); - *aMemSharedTotal = (ULONG)(uSharedTotal / _1K); - } - else - return E_FAIL; - - /* Query the missing per-VM memory statistics. */ - *aMemShared = 0; - uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem; - rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem); - if (rc == VINF_SUCCESS) - { - *aMemShared = (ULONG)(uSharedMem / _1K); - } - else - return E_FAIL; - } - else - { - *aMemAllocTotal = 0; - *aMemFreeTotal = 0; - *aMemBalloonTotal = 0; - *aMemSharedTotal = 0; - *aMemShared = 0; + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) return E_FAIL; - } + + uint64_t cbFreeTotal, cbAllocTotal, cbBalloonedTotal, cbSharedTotal; + int rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal); + AssertRCReturn(rc, E_FAIL); + + *aMemAllocTotal = (ULONG)(cbAllocTotal / _1K); /* bytes -> KB */ + *aMemFreeTotal = (ULONG)(cbFreeTotal / _1K); + *aMemBalloonTotal = (ULONG)(cbBalloonedTotal / _1K); + *aMemSharedTotal = (ULONG)(cbSharedTotal / _1K); + + /* Query the missing per-VM memory statistics. */ + uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbSharedMem, cbZeroMemIgn; + rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn); + AssertRCReturn(rc, E_FAIL); + *aMemShared = (ULONG)(cbSharedMem / _1K); return S_OK; } @@ -619,15 +714,15 @@ HRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal) { static ULONG indexToPerfMask[] = { - pm::GUESTSTATMASK_CPUUSER, - pm::GUESTSTATMASK_CPUKERNEL, - pm::GUESTSTATMASK_CPUIDLE, - pm::GUESTSTATMASK_MEMTOTAL, - pm::GUESTSTATMASK_MEMFREE, - pm::GUESTSTATMASK_MEMBALLOON, - pm::GUESTSTATMASK_MEMCACHE, - pm::GUESTSTATMASK_PAGETOTAL, - pm::GUESTSTATMASK_NONE + pm::VMSTATMASK_GUEST_CPUUSER, + pm::VMSTATMASK_GUEST_CPUKERNEL, + pm::VMSTATMASK_GUEST_CPUIDLE, + pm::VMSTATMASK_GUEST_MEMTOTAL, + pm::VMSTATMASK_GUEST_MEMFREE, + pm::VMSTATMASK_GUEST_MEMBALLOON, + pm::VMSTATMASK_GUEST_MEMCACHE, + pm::VMSTATMASK_GUEST_PAGETOTAL, + pm::VMSTATMASK_NONE }; AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -638,7 +733,7 @@ HRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal) return E_INVALIDARG; mCurrentGuestStat[enmType] = aVal; - mGuestValidStats |= indexToPerfMask[enmType]; + mVmValidStats |= indexToPerfMask[enmType]; return S_OK; } @@ -1051,6 +1146,31 @@ void Guest::facilityUpdate(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilit } } +/** + * Issued by the guest when a guest user changed its state. + * + * @return IPRT status code. + * @param aUser Guest user name. + * @param aDomain Domain of guest user account. Optional. + * @param enmState New state to indicate. + * @param puDetails Pointer to state details. Optional. + * @param cbDetails Size (in bytes) of state details. Pass 0 if not used. + */ +void Guest::onUserStateChange(Bstr aUser, Bstr aDomain, VBoxGuestUserState enmState, + const uint8_t *puDetails, uint32_t cbDetails) +{ + LogFlowThisFunc(("\n")); + + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); + + Bstr strDetails; /** @todo Implement state details here. */ + + fireGuestUserStateChangedEvent(mEventSource, aUser.raw(), aDomain.raw(), + (GuestUserState_T)enmState, strDetails.raw()); + LogFlowFuncLeave(); +} + /** * Sets the status of a certain Guest Additions facility. * diff --git a/src/VBox/Main/src-client/GuestProcessImpl.cpp b/src/VBox/Main/src-client/GuestProcessImpl.cpp index feffba96..4ccf1e44 100644 --- a/src/VBox/Main/src-client/GuestProcessImpl.cpp +++ b/src/VBox/Main/src-client/GuestProcessImpl.cpp @@ -1,11 +1,10 @@ - /* $Id: GuestProcessImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest process handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -32,16 +31,20 @@ #include "GuestSessionImpl.h" #include "GuestCtrlImplPrivate.h" #include "ConsoleImpl.h" +#include "VirtualBoxErrorInfoImpl.h" #include "Global.h" #include "AutoCaller.h" -#include "VMMDev.h" +#include "VBoxEvents.h" #include /* For auto_ptr. */ #include +#include /* For unconst(). */ #include -#include + +#include + #include #ifdef LOG_GROUP @@ -79,6 +82,62 @@ public: : GuestProcessTask(pProcess) { } }; +/** + * Internal listener class to serve events in an + * active manner, e.g. without polling delays. + */ +class GuestProcessListener +{ +public: + + GuestProcessListener(void) + { + } + + HRESULT init(GuestProcess *pProcess) + { + AssertPtrReturn(pProcess, E_POINTER); + mProcess = pProcess; + return S_OK; + } + + void uninit(void) + { + mProcess = NULL; + } + + STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent) + { + switch (aType) + { + case VBoxEventType_OnGuestProcessStateChanged: + case VBoxEventType_OnGuestProcessInputNotify: + case VBoxEventType_OnGuestProcessOutput: + { + AssertPtrReturn(mProcess, E_POINTER); + int rc2 = mProcess->signalWaitEvent(aType, aEvent); +#ifdef DEBUG + LogFlowThisFunc(("Signalling events of type=%RU32, pProcess=%p resulted in rc=%Rrc\n", + aType, &mProcess, rc2)); +#endif + break; + } + + default: + AssertMsgFailed(("Unhandled event %RU32\n", aType)); + break; + } + + return S_OK; + } + +private: + + GuestProcess *mProcess; +}; +typedef ListenerImpl GuestProcessListenerImpl; + +VBOX_LISTENER_DECLARE(GuestProcessListenerImpl) // constructor / destructor ///////////////////////////////////////////////////////////////////////////// @@ -88,19 +147,7 @@ DEFINE_EMPTY_CTOR_DTOR(GuestProcess) HRESULT GuestProcess::FinalConstruct(void) { LogFlowThisFuncEnter(); - - mData.mExitCode = 0; - mData.mNextContextID = 0; - mData.mPID = 0; - mData.mProcessID = 0; - mData.mRC = VINF_SUCCESS; - mData.mStatus = ProcessStatus_Undefined; - - mData.mWaitCount = 0; - mData.mWaitEvent = NULL; - - HRESULT hr = BaseFinalConstruct(); - return hr; + return BaseFinalConstruct(); } void GuestProcess::FinalRelease(void) @@ -114,72 +161,124 @@ void GuestProcess::FinalRelease(void) // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// -int GuestProcess::init(Console *aConsole, GuestSession *aSession, ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo) +int GuestProcess::init(Console *aConsole, GuestSession *aSession, + ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo) { LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32\n", aConsole, aSession, aProcessID)); + AssertPtrReturn(aConsole, VERR_INVALID_POINTER); AssertPtrReturn(aSession, VERR_INVALID_POINTER); /* Enclose the state transition NotReady->InInit->Ready. */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); - mData.mConsole = aConsole; - mData.mParent = aSession; - mData.mProcessID = aProcessID; - mData.mProcess = aProcInfo; - /* Everything else will be set by the actual starting routine. */ - - /* Confirm a successful initialization when it's the case. */ +#ifndef VBOX_WITH_GUEST_CONTROL autoInitSpan.setSucceeded(); - return VINF_SUCCESS; +#else + HRESULT hr; + + int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */); + if (RT_SUCCESS(vrc)) + { + hr = unconst(mEventSource).createObject(); + if (FAILED(hr)) + vrc = VERR_NO_MEMORY; + else + { + hr = mEventSource->init(); + if (FAILED(hr)) + vrc = VERR_COM_UNEXPECTED; + } + } + + if (RT_SUCCESS(vrc)) + { + try + { + GuestProcessListener *pListener = new GuestProcessListener(); + ComObjPtr thisListener; + hr = thisListener.createObject(); + if (SUCCEEDED(hr)) + hr = thisListener->init(pListener, this); + + if (SUCCEEDED(hr)) + { + com::SafeArray eventTypes; + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify); + eventTypes.push_back(VBoxEventType_OnGuestProcessOutput); + hr = mEventSource->RegisterListener(thisListener, + ComSafeArrayAsInParam(eventTypes), + TRUE /* Active listener */); + if (SUCCEEDED(hr)) + { + vrc = baseInit(); + if (RT_SUCCESS(vrc)) + { + mLocalListener = thisListener; + } + } + else + vrc = VERR_COM_UNEXPECTED; + } + else + vrc = VERR_COM_UNEXPECTED; + } + catch(std::bad_alloc &) + { + vrc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(vrc)) + { + mData.mProcess = aProcInfo; + mData.mExitCode = 0; + mData.mPID = 0; + mData.mLastError = VINF_SUCCESS; + mData.mStatus = ProcessStatus_Undefined; + /* Everything else will be set by the actual starting routine. */ + + /* Confirm a successful initialization when it's the case. */ + autoInitSpan.setSucceeded(); + + return vrc; + } + + autoInitSpan.setFailed(); + return vrc; +#endif } /** * Uninitializes the instance. - * Called from FinalRelease(). + * Called from FinalRelease() or IGuestSession::uninit(). */ void GuestProcess::uninit(void) { - LogFlowThisFunc(("mCmd=%s, PID=%RU32\n", - mData.mProcess.mCommand.c_str(), mData.mPID)); - /* Enclose the state transition Ready->InUninit->NotReady. */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; - int vrc = VINF_SUCCESS; - #ifdef VBOX_WITH_GUEST_CONTROL - /* - * Cancel all callbacks + waiters. - * Note: Deleting them is the job of the caller! - */ - for (GuestCtrlCallbacks::iterator itCallbacks = mData.mCallbacks.begin(); - itCallbacks != mData.mCallbacks.end(); ++itCallbacks) - { - GuestCtrlCallback *pCallback = itCallbacks->second; - AssertPtr(pCallback); - int rc2 = pCallback->Cancel(); - if (RT_SUCCESS(vrc)) - vrc = rc2; - } - mData.mCallbacks.clear(); + LogFlowThisFunc(("mCmd=%s, PID=%RU32\n", + mData.mProcess.mCommand.c_str(), mData.mPID)); - if (mData.mWaitEvent) - { - int rc2 = mData.mWaitEvent->Cancel(); - if (RT_SUCCESS(vrc)) - vrc = rc2; - } + /* Terminate process if not already done yet. */ + int guestRc = VINF_SUCCESS; + int vrc = terminateProcess(30 * 1000, &guestRc); /** @todo Make timeouts configurable. */ + /* Note: Don't return here yet; first uninit all other stuff in + * case of failure. */ - mData.mStatus = ProcessStatus_Down; /** @todo Correct? */ -#endif + baseUninit(); - LogFlowFuncLeaveRC(vrc); + LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n", + vrc, guestRc)); +#endif } // implementation of public getters/setters for attributes @@ -241,6 +340,26 @@ STDMETHODIMP GuestProcess::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnviron #endif /* VBOX_WITH_GUEST_CONTROL */ } +STDMETHODIMP GuestProcess::COMGETTER(EventSource)(IEventSource ** aEventSource) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aEventSource); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + // no need to lock - lifetime constant + mEventSource.queryInterfaceTo(aEventSource); + + LogFlowThisFuncLeave(); + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + STDMETHODIMP GuestProcess::COMGETTER(ExecutablePath)(BSTR *aExecutablePath) { #ifndef VBOX_WITH_GUEST_CONTROL @@ -342,143 +461,45 @@ STDMETHODIMP GuestProcess::COMGETTER(Status)(ProcessStatus_T *aStatus) // private methods ///////////////////////////////////////////////////////////////////////////// -inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID) -{ - const ComObjPtr pSession(mData.mParent); - Assert(!pSession.isNull()); - ULONG uSessionID = 0; - HRESULT hr = pSession->COMGETTER(Id)(&uSessionID); - ComAssertComRC(hr); - - /* Create a new context ID and assign it. */ - int vrc = VERR_NOT_FOUND; - - ULONG uCount = mData.mNextContextID++; - ULONG uNewContextID = 0; - ULONG uTries = 0; - for (;;) - { - if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS) - uCount = 0; - - /* Create a new context ID ... */ - uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, - mData.mProcessID, uCount); - - /* Is the context ID already used? Try next ID ... */ - if (!callbackExists(uCount)) - { - /* Callback with context ID was not found. This means - * we can use this context ID for our new callback we want - * to add below. */ - vrc = VINF_SUCCESS; - break; - } - - uCount++; - if (++uTries == UINT32_MAX) - break; /* Don't try too hard. */ - } - - if (RT_SUCCESS(vrc)) - { - /* Add callback with new context ID to our callback map. - * Note: This is *not* uNewContextID (which also includes - * the session + process ID), just the context count - * will be used here. */ - mData.mCallbacks[uCount] = pCallback; - Assert(mData.mCallbacks.size()); - - /* Report back new context ID. */ - if (puContextID) - *puContextID = uNewContextID; - - LogFlowThisFunc(("Added new callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n", - uSessionID, mData.mProcessID, uCount, uNewContextID)); - } - - return vrc; -} - -int GuestProcess::callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData) +int GuestProcess::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) { + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); #ifdef DEBUG - LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pvData=%p, cbData=%RU32\n", - mData.mPID, uContextID, uFunction, pvData, cbData)); + LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n", + mData.mPID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); #endif - AssertPtrReturn(pvData, VERR_INVALID_POINTER); - AssertReturn(cbData, VERR_INVALID_PARAMETER); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - int vrc; - - /* Get the optional callback associated to this context ID. - * The callback may not be around anymore if just kept locally by the caller when - * doing the actual HGCM sending stuff. */ - GuestCtrlCallback *pCallback = NULL; - GuestCtrlCallbacks::const_iterator it - = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)); - if (it != mData.mCallbacks.end()) - { - pCallback = it->second; - AssertPtr(pCallback); -#ifdef DEBUG - LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n", - pCallback, uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID))); -#endif - } - - switch (uFunction) + switch (pCbCtx->uFunction) { case GUEST_DISCONNECTED: { - PCALLBACKDATACLIENTDISCONNECTED pCallbackData = reinterpret_cast(pvData); - AssertPtr(pCallbackData); - AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbData, VERR_INVALID_PARAMETER); - AssertReturn(CALLBACKDATAMAGIC_CLIENT_DISCONNECTED == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER); - - vrc = onGuestDisconnected(pCallback, pCallbackData); /* Affects all callbacks. */ + vrc = onGuestDisconnected(pCbCtx, pSvcCb); break; } - case GUEST_EXEC_SEND_STATUS: + case GUEST_EXEC_STATUS: { - PCALLBACKDATAEXECSTATUS pCallbackData = reinterpret_cast(pvData); - AssertPtr(pCallbackData); - AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbData, VERR_INVALID_PARAMETER); - AssertReturn(CALLBACKDATAMAGIC_EXEC_STATUS == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER); - - vrc = onProcessStatusChange(pCallback, pCallbackData); + vrc = onProcessStatusChange(pCbCtx, pSvcCb); break; } - case GUEST_EXEC_SEND_OUTPUT: + case GUEST_EXEC_OUTPUT: { - PCALLBACKDATAEXECOUT pCallbackData = reinterpret_cast(pvData); - AssertPtr(pCallbackData); - AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbData, VERR_INVALID_PARAMETER); - AssertReturn(CALLBACKDATAMAGIC_EXEC_OUT == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER); - - vrc = onProcessOutput(pCallback, pCallbackData); + vrc = onProcessOutput(pCbCtx, pSvcCb); break; } - case GUEST_EXEC_SEND_INPUT_STATUS: + case GUEST_EXEC_INPUT_STATUS: { - PCALLBACKDATAEXECINSTATUS pCallbackData = reinterpret_cast(pvData); - AssertPtr(pCallbackData); - AssertReturn(sizeof(CALLBACKDATAEXECINSTATUS) == cbData, VERR_INVALID_PARAMETER); - AssertReturn(CALLBACKDATAMAGIC_EXEC_IN_STATUS == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER); - - vrc = onProcessInputStatus(pCallback, pCallbackData); + vrc = onProcessInputStatus(pCbCtx, pSvcCb); break; } default: /* Silently ignore not implemented functions. */ - vrc = VERR_NOT_IMPLEMENTED; + vrc = VERR_NOT_SUPPORTED; break; } @@ -488,67 +509,38 @@ int GuestProcess::callbackDispatcher(uint32_t uContextID, uint32_t uFunction, vo return vrc; } -inline bool GuestProcess::callbackExists(uint32_t uContextID) -{ - GuestCtrlCallbacks::const_iterator it = - mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)); - return (it == mData.mCallbacks.end()) ? false : true; -} - -inline int GuestProcess::callbackRemove(uint32_t uContextID) -{ - LogFlowThisFunc(("Removing callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n", - VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID), - VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID), - VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID), - uContextID)); - - GuestCtrlCallbacks::iterator it = - mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)); - if (it != mData.mCallbacks.end()) - { - delete it->second; - mData.mCallbacks.erase(it); - - return VINF_SUCCESS; - } - - return VERR_NOT_FOUND; -} - /** * Checks if the current assigned PID matches another PID (from a callback). * * In protocol v1 we don't have the possibility to terminate/kill - * processes so it can happen that a formerly start process A + * processes so it can happen that a formerly started process A * (which has the context ID 0 (session=0, process=0, count=0) will * send a delayed message to the host if this process has already * been discarded there and the same context ID was reused by * a process B. Process B in turn then has a different guest PID. * + * Note: This also can happen when restoring from a saved state which + * had a guest process running. + * * @return IPRT status code. * @param uPID PID to check. */ inline int GuestProcess::checkPID(uint32_t uPID) { + int rc = VINF_SUCCESS; + /* Was there a PID assigned yet? */ if (mData.mPID) { - /* - - */ - if (mData.mParent->getProtocolVersion() < 2) + if (RT_UNLIKELY(mData.mPID != uPID)) { - /* Simply ignore the stale requests. */ - return (mData.mPID == uPID) - ? VINF_SUCCESS : VERR_NOT_FOUND; + LogFlowFunc(("Stale guest process (PID=%RU32) sent data to a newly started process (pProcesS=%p, PID=%RU32, status=%RU32)\n", + uPID, this, mData.mPID, mData.mStatus)); + rc = VERR_NOT_FOUND; } - /* This should never happen! */ - AssertReleaseMsg(mData.mPID == uPID, ("Unterminated guest process (PID %RU32) sent data to a newly started process (PID %RU32)\n", - uPID, mData.mPID)); } - return VINF_SUCCESS; + return rc; } /* static */ @@ -600,7 +592,7 @@ Utf8Str GuestProcess::guestErrorToString(int guestRc) break; case VERR_MAX_PROCS_REACHED: - strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached")); + strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); break; case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */ @@ -612,7 +604,7 @@ Utf8Str GuestProcess::guestErrorToString(int guestRc) break; default: - strError += Utf8StrFmt(tr("%Rrc"), guestRc); + strError += Utf8StrFmt("%Rrc", guestRc); break; } @@ -626,226 +618,205 @@ inline bool GuestProcess::isAlive(void) || mData.mStatus == ProcessStatus_Terminating); } -bool GuestProcess::isReady(void) +inline bool GuestProcess::hasEnded(void) { - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (mData.mStatus == ProcessStatus_Started) - { - Assert(mData.mPID); /* PID must not be 0. */ - return true; - } - - return false; + return ( mData.mStatus == ProcessStatus_TerminatedNormally + || mData.mStatus == ProcessStatus_TerminatedSignal + || mData.mStatus == ProcessStatus_TerminatedAbnormally + || mData.mStatus == ProcessStatus_TimedOutKilled + || mData.mStatus == ProcessStatus_TimedOutAbnormally + || mData.mStatus == ProcessStatus_Down + || mData.mStatus == ProcessStatus_Error); } -int GuestProcess::onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData) +int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { - /* pCallback is optional. */ - AssertPtrReturn(pData, VERR_INVALID_POINTER); - - LogFlowThisFunc(("uPID=%RU32, pCallback=%p, pData=%p\n", mData.mPID, pCallback, pData)); - - mData.mStatus = ProcessStatus_Down; - - /* First, signal callback in every case. */ - if (pCallback) - pCallback->Signal(); + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); - /* Do we need to report a termination? */ - ProcessWaitResult_T waitRes; - if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses) - waitRes = ProcessWaitResult_Status; /* No, just report a status. */ - else - waitRes = ProcessWaitResult_Terminate; - - /* Signal in any case. */ - int vrc = signalWaiters(waitRes); - AssertRC(vrc); + int vrc = setProcessStatus(ProcessStatus_Down, VINF_SUCCESS); LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestProcess::onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData) +int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); /* pCallback is optional. */ - AssertPtrReturn(pData, VERR_INVALID_POINTER); - - LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, cbProcessed=%RU32, pCallback=%p, pData=%p\n", - mData.mPID, pData->u32Status, pData->u32Flags, pData->cbProcessed, pCallback, pData)); - int vrc = checkPID(pData->u32PID); - if (RT_FAILURE(vrc)) - return vrc; + if (pSvcCbData->mParms < 5) + return VERR_INVALID_PARAMETER; - /* First, signal callback in every case (if available). */ - if (pCallback) + CALLBACKDATA_PROC_INPUT dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[4].getUInt32(&dataCb.uProcessed); + AssertRCReturn(vrc, vrc); + + LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n", + dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed)); + + vrc = checkPID(dataCb.uPID); + if (RT_SUCCESS(vrc)) { - vrc = pCallback->SetData(pData, sizeof(CALLBACKDATAEXECINSTATUS)); + ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined; + switch (dataCb.uStatus) + { + case INPUT_STS_WRITTEN: + inputStatus = ProcessInputStatus_Written; + break; + case INPUT_STS_ERROR: + inputStatus = ProcessInputStatus_Broken; + break; + case INPUT_STS_TERMINATED: + inputStatus = ProcessInputStatus_Broken; + break; + case INPUT_STS_OVERFLOW: + inputStatus = ProcessInputStatus_Overflow; + break; + case INPUT_STS_UNDEFINED: + /* Fall through is intentional. */ + default: + AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n")); + break; + } - int rc2 = pCallback->Signal(); - if (RT_SUCCESS(vrc)) - vrc = rc2; - } + if (inputStatus != ProcessInputStatus_Undefined) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Then do the WaitFor signalling stuff. */ - uint32_t uWaitFlags = mData.mWaitEvent - ? mData.mWaitEvent->GetWaitFlags() : 0; - if (uWaitFlags & ProcessWaitForFlag_StdIn) - { - int rc2 = signalWaiters(ProcessWaitResult_StdIn); - if (RT_SUCCESS(vrc)) - vrc = rc2; + /* Copy over necessary data before releasing lock again. */ + uint32_t uPID = mData.mPID; + /** @todo Also handle mSession? */ + + alock.release(); /* Release lock before firing off event. */ + + fireGuestProcessInputNotifyEvent(mEventSource, mSession, this, + uPID, 0 /* StdIn */, dataCb.uProcessed, inputStatus); + } } LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestProcess::onProcessNotifyIO(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData) +int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { - /* pCallback is optional. */ - AssertPtrReturn(pData, VERR_INVALID_POINTER); + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); - return 0; + return VERR_NOT_IMPLEMENTED; } -int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData) +int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { - /* pCallback is optional. */ - AssertPtrReturn(pData, VERR_INVALID_POINTER); - - LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n", - pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData)); + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); - int vrc = checkPID(pData->u32PID); - if (RT_FAILURE(vrc)) - return vrc; - - ProcessStatus_T procStatus = ProcessStatus_Undefined; - int procRc = VINF_SUCCESS; - - bool fSignalWaiters = false; - ProcessWaitResult_T waitRes; + if (pSvcCbData->mParms < 5) + return VERR_INVALID_PARAMETER; - uint32_t uWaitFlags = mData.mWaitEvent - ? mData.mWaitEvent->GetWaitFlags() : 0; - switch (pData->u32Status) + CALLBACKDATA_PROC_STATUS dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData); + AssertRCReturn(vrc, vrc); + + LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n", + dataCb.uPID, dataCb.uStatus, dataCb.uFlags)); + + vrc = checkPID(dataCb.uPID); + if (RT_SUCCESS(vrc)) { - case PROC_STS_STARTED: - { - fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start); - /* If the caller only wants to wait until the process has been started, - * notify in any case. */ - if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) - fSignalWaiters = true; - waitRes = ProcessWaitResult_Start; - - procStatus = ProcessStatus_Started; - mData.mPID = pData->u32PID; /* Set the process PID. */ - break; - } + ProcessStatus_T procStatus = ProcessStatus_Undefined; + int procRc = VINF_SUCCESS; - case PROC_STS_TEN: + switch (dataCb.uStatus) { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Terminate; - - procStatus = ProcessStatus_TerminatedNormally; - mData.mExitCode = pData->u32Flags; /* Contains the exit code. */ - break; - } - - case PROC_STS_TES: - { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Terminate; - - procStatus = ProcessStatus_TerminatedSignal; - mData.mExitCode = pData->u32Flags; /* Contains the signal. */ - break; - } - - case PROC_STS_TEA: - { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Terminate; + case PROC_STS_STARTED: + { + procStatus = ProcessStatus_Started; - procStatus = ProcessStatus_TerminatedAbnormally; - break; - } + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + mData.mPID = dataCb.uPID; /* Set the process PID. */ + break; + } - case PROC_STS_TOK: - { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Timeout; + case PROC_STS_TEN: + { + procStatus = ProcessStatus_TerminatedNormally; - procStatus = ProcessStatus_TimedOutKilled; - break; - } + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */ + break; + } - case PROC_STS_TOA: - { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Timeout; + case PROC_STS_TES: + { + procStatus = ProcessStatus_TerminatedSignal; - procStatus = ProcessStatus_TimedOutAbnormally; - break; - } + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + mData.mExitCode = dataCb.uFlags; /* Contains the signal. */ + break; + } - case PROC_STS_DWN: - { - fSignalWaiters = true; /* Signal in any case. */ - /* Do we need to report termination? */ - if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses) - waitRes = ProcessWaitResult_Status; - else - waitRes = ProcessWaitResult_Terminate; + case PROC_STS_TEA: + { + procStatus = ProcessStatus_TerminatedAbnormally; + break; + } - procStatus = ProcessStatus_Down; - break; - } + case PROC_STS_TOK: + { + procStatus = ProcessStatus_TimedOutKilled; + break; + } - case PROC_STS_ERROR: - { - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Error; + case PROC_STS_TOA: + { + procStatus = ProcessStatus_TimedOutAbnormally; + break; + } - procRc = pData->u32Flags; /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ - procStatus = ProcessStatus_Error; - break; - } + case PROC_STS_DWN: + { + procStatus = ProcessStatus_Down; + break; + } - case PROC_STS_UNDEFINED: - default: - { - /* Silently skip this request. */ - fSignalWaiters = true; /* Signal in any case. */ - waitRes = ProcessWaitResult_Status; + case PROC_STS_ERROR: + { + procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */ + procStatus = ProcessStatus_Error; + break; + } - procStatus = ProcessStatus_Undefined; - break; + case PROC_STS_UNDEFINED: + default: + { + /* Silently skip this request. */ + procStatus = ProcessStatus_Undefined; + break; + } } - } - - LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n", - vrc, waitRes, procStatus, procRc, fSignalWaiters)); - - /* Set the process status. */ - int rc2 = setProcessStatus(procStatus, procRc); - if (RT_SUCCESS(vrc)) - vrc = rc2; - /* - * Now do the signalling stuff. - */ - if (pCallback) - vrc = pCallback->Signal(procRc); + LogFlowThisFunc(("Got rc=%Rrc, procSts=%RU32, procRc=%Rrc\n", + vrc, procStatus, procRc)); - if (fSignalWaiters) - { - rc2 = signalWaiters(waitRes, procRc); + /* Set the process status. */ + int rc2 = setProcessStatus(procStatus, procRc); if (RT_SUCCESS(vrc)) vrc = rc2; } @@ -854,58 +825,64 @@ int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKD return vrc; } -int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData) +int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { - /* pCallback is optional. */ - AssertPtrReturn(pData, VERR_INVALID_POINTER); - - LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n", - mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData)); + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); - int vrc = checkPID(pData->u32PID); - if (RT_FAILURE(vrc)) - return vrc; + if (pSvcCbData->mParms < 5) + return VERR_INVALID_PARAMETER; - /* First, signal callback in every case (if available). */ - if (pCallback) + CALLBACKDATA_PROC_OUTPUT dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uHandle); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData); + AssertRCReturn(vrc, vrc); + + LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n", + dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData)); + + vrc = checkPID(dataCb.uPID); + if (RT_SUCCESS(vrc)) { - vrc = pCallback->SetData(pData, sizeof(CALLBACKDATAEXECOUT)); + com::SafeArray data((size_t)dataCb.cbData); + if (dataCb.cbData) + data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData); - int rc2 = pCallback->Signal(); - if (RT_SUCCESS(vrc)) - vrc = rc2; + fireGuestProcessOutputEvent(mEventSource, mSession, this, + mData.mPID, dataCb.uHandle, dataCb.cbData, ComSafeArrayAsInParam(data)); } - /* Then do the WaitFor signalling stuff. */ - BOOL fSignal = FALSE; - uint32_t uWaitFlags = mData.mWaitEvent - ? mData.mWaitEvent->GetWaitFlags() : 0; + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/** + * Called by IGuestSession right before this process gets + * removed from the public process list. + */ +int GuestProcess::onRemove(void) +{ + LogFlowThisFuncEnter(); - if ( (uWaitFlags & ProcessWaitForFlag_StdOut) - || (uWaitFlags & ProcessWaitForFlag_StdErr)) - { - fSignal = TRUE; - } - else if ( (uWaitFlags & ProcessWaitForFlag_StdOut) - && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT)) - { - fSignal = TRUE; - } - else if ( (uWaitFlags & ProcessWaitForFlag_StdErr) - && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDERR)) - { - fSignal = TRUE; - } + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if (fSignal) + int vrc = VINF_SUCCESS; + + /* + * Note: The event source stuff holds references to this object, + * so make sure that this is cleaned up *before* calling uninit(). + */ + if (!mEventSource.isNull()) { - int rc2; - if (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT) - rc2 = signalWaiters(ProcessWaitResult_StdOut); - else - rc2 = signalWaiters(ProcessWaitResult_StdErr); - if (RT_SUCCESS(vrc)) - vrc = rc2; + mEventSource->UnregisterListener(mLocalListener); + + mLocalListener.setNull(); + unconst(mEventSource).setNull(); } LogFlowFuncLeaveRC(vrc); @@ -913,7 +890,7 @@ int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXE } int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, - void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc) + void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc) { LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n", mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc)); @@ -924,7 +901,15 @@ int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if (mData.mStatus != ProcessStatus_Started) + if ( mData.mStatus != ProcessStatus_Started + /* Skip reading if the process wasn't started with the appropriate + * flags. */ + || ( ( uHandle == OUTPUT_HANDLE_ID_STDOUT + || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED) + && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdOut)) + || ( uHandle == OUTPUT_HANDLE_ID_STDERR + && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdErr)) + ) { if (pcbRead) *pcbRead = 0; @@ -933,138 +918,120 @@ int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS return VINF_SUCCESS; /* Nothing to read anymore. */ } - int vrc = VINF_SUCCESS; + int vrc; - GuestCtrlCallback *pCallbackRead = NULL; + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; try { - pCallbackRead = new GuestCtrlCallback(); + /* + * On Guest Additions < 4.3 there is no guarantee that the process status + * change arrives *after* the output event, e.g. if this was the last output + * block being read and the process will report status "terminate". + * So just skip checking for process status change and only wait for the + * output event. + */ + if (mSession->getProtocolVersion() >= 2) + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestProcessOutput); + + vrc = registerWaitEvent(eventTypes, &pEvent); } - catch(std::bad_alloc &) + catch (std::bad_alloc) { vrc = VERR_NO_MEMORY; } - /* Create callback and add it to the map. */ - uint32_t uContextID = 0; - if (RT_SUCCESS(vrc)) - { - vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT); - if (RT_SUCCESS(vrc)) - vrc = callbackAdd(pCallbackRead, &uContextID); - } - - alock.release(); /* Drop the write lock again. */ + if (RT_FAILURE(vrc)) + return vrc; if (RT_SUCCESS(vrc)) { - VBOXHGCMSVCPARM paParms[5]; - + VBOXHGCMSVCPARM paParms[8]; int i = 0; - paParms[i++].setUInt32(uContextID); + paParms[i++].setUInt32(pEvent->ContextID()); paParms[i++].setUInt32(mData.mPID); paParms[i++].setUInt32(uHandle); paParms[i++].setUInt32(0 /* Flags, none set yet. */); + alock.release(); /* Drop the write lock before sending. */ + vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms); } if (RT_SUCCESS(vrc)) - { - /* - * Let's wait for the process being started. - * Note: Be sure not keeping a AutoRead/WriteLock here. - */ - LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); - vrc = pCallbackRead->Wait(uTimeoutMS); - if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ - { - int guestRc = pCallbackRead->GetResultCode(); - LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize())); - - if (RT_SUCCESS(guestRc)) - { - Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT)); - PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)pCallbackRead->GetDataRaw(); - AssertPtr(pData); - - size_t cbRead = pData->cbData; - if (cbRead) - { - Assert(cbData >= cbRead); - memcpy(pvData, pData->pvData, cbRead); - } - - LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); - - if (pcbRead) - *pcbRead = cbRead; - } - else - vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ - - if (pGuestRc) - *pGuestRc = guestRc; - } - } + vrc = waitForOutput(pEvent, uHandle, uTimeoutMS, + pvData, cbData, pcbRead); - alock.acquire(); - - AssertPtr(pCallbackRead); - int rc2 = callbackRemove(uContextID); - if (RT_SUCCESS(vrc)) - vrc = rc2; + unregisterWaitEvent(pEvent); LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestProcess::sendCommand(uint32_t uFunction, - uint32_t uParms, PVBOXHGCMSVCPARM paParms) +/* Does not do locking; caller is responsible for that! */ +int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc) { LogFlowThisFuncEnter(); - ComObjPtr pConsole = mData.mConsole; - Assert(!pConsole.isNull()); - - /* Forward the information to the VMM device. */ - VMMDev *pVMMDev = pConsole->getVMMDev(); - AssertPtr(pVMMDev); - - LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); - int vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", uFunction, uParms, paParms); - if (RT_FAILURE(vrc)) - { - int rc2 = setProcessStatus(ProcessStatus_Error, vrc); - AssertRC(rc2); - } - - LogFlowFuncLeaveRC(vrc); - return vrc; -} + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); -/* Does not do locking; caller is responsible for that! */ -int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc) -{ - LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n", + LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, procRc=%Rrc\n", mData.mStatus, procStatus, procRc)); -#ifdef DEBUG if (procStatus == ProcessStatus_Error) { AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc)); /* Do not allow overwriting an already set error. If this happens * this means we forgot some error checking/locking somewhere. */ - AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); + AssertMsg(RT_SUCCESS(mData.mLastError), ("Guest rc already set (to %Rrc)\n", mData.mLastError)); } else AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc)); -#endif - mData.mStatus = procStatus; - mData.mRC = procRc; + int rc = VINF_SUCCESS; - return VINF_SUCCESS; + if (mData.mStatus != procStatus) /* Was there a process status change? */ + { + mData.mStatus = procStatus; + mData.mLastError = procRc; + + ComObjPtr errorInfo; + HRESULT hr = errorInfo.createObject(); + ComAssertComRC(hr); + if (RT_FAILURE(mData.mLastError)) + { + hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, mData.mLastError, + COM_IIDOF(IGuestProcess), getComponentName(), + guestErrorToString(mData.mLastError)); + ComAssertComRC(hr); + } + + /* Copy over necessary data before releasing lock again. */ + uint32_t uPID = mData.mPID; + /** @todo Also handle mSession? */ + + alock.release(); /* Release lock before firing off event. */ + + fireGuestProcessStateChangedEvent(mEventSource, mSession, this, + uPID, procStatus, errorInfo); +#if 0 + /* + * On Guest Additions < 4.3 there is no guarantee that outstanding + * requests will be delivered to the host after the process has ended, + * so just cancel all waiting events here to not let clients run + * into timeouts. + */ + if ( mSession->getProtocolVersion() < 2 + && hasEnded()) + { + LogFlowThisFunc(("Process ended, canceling outstanding wait events ...\n")); + rc = cancelWaitEvents(); + } +#endif + } + + return rc; } /* static */ @@ -1076,170 +1043,147 @@ HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc) return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str()); } -int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */) -{ - LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n", - enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent)); - - /* Note: No write locking here -- already done in the caller. */ - - int vrc = VINF_SUCCESS; - if (mData.mWaitEvent) - vrc = mData.mWaitEvent->Signal(enmWaitResult, rc); - LogFlowFuncLeaveRC(vrc); - return vrc; -} - -int GuestProcess::startProcess(int *pGuestRc) +int GuestProcess::startProcess(uint32_t uTimeoutMS, int *pGuestRc) { - LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n", - mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags)); + LogFlowThisFunc(("uTimeoutMS=%RU32, procCmd=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n", + uTimeoutMS, mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags, + mSession->getId())); /* Wait until the caller function (if kicked off by a thread) * has returned and continue operation. */ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - int vrc = VINF_SUCCESS; - uint32_t uContextID = 0; + mData.mStatus = ProcessStatus_Starting; - GuestCtrlCallback *pCallbackStart; + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; try { - pCallbackStart = new GuestCtrlCallback(); + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); + + vrc = registerWaitEvent(eventTypes, &pEvent); } - catch(std::bad_alloc &) + catch (std::bad_alloc) { vrc = VERR_NO_MEMORY; } - if (RT_SUCCESS(vrc)) - { - mData.mStatus = ProcessStatus_Starting; + if (RT_FAILURE(vrc)) + return vrc; - /* Create callback and add it to the map. */ - vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START); - if (RT_SUCCESS(vrc)) - vrc = callbackAdd(pCallbackStart, &uContextID); - } + GuestSession *pSession = mSession; + AssertPtr(pSession); - if (RT_SUCCESS(vrc)) - { - GuestSession *pSession = mData.mParent; - AssertPtr(pSession); + const GuestCredentials &sessionCreds = pSession->getCredentials(); - const GuestCredentials &sessionCreds = pSession->getCredentials(); + /* Prepare arguments. */ + char *pszArgs = NULL; + size_t cArgs = mData.mProcess.mArguments.size(); + if (cArgs >= UINT32_MAX) + vrc = VERR_BUFFER_OVERFLOW; - /* Prepare arguments. */ - char *pszArgs = NULL; - size_t cArgs = mData.mProcess.mArguments.size(); - if (cArgs >= UINT32_MAX) - vrc = VERR_BUFFER_OVERFLOW; + if ( RT_SUCCESS(vrc) + && cArgs) + { + char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*)); + AssertReturn(papszArgv, VERR_NO_MEMORY); - if ( RT_SUCCESS(vrc) - && cArgs) + for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++) { - char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*)); - AssertReturn(papszArgv, VERR_NO_MEMORY); - - for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++) - { - const char *pszCurArg = mData.mProcess.mArguments[i].c_str(); - AssertPtr(pszCurArg); - vrc = RTStrDupEx(&papszArgv[i], pszCurArg); - } - papszArgv[cArgs] = NULL; + const char *pszCurArg = mData.mProcess.mArguments[i].c_str(); + AssertPtr(pszCurArg); + vrc = RTStrDupEx(&papszArgv[i], pszCurArg); + } + papszArgv[cArgs] = NULL; - if (RT_SUCCESS(vrc)) - vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT); + if (RT_SUCCESS(vrc)) + vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT); - if (papszArgv) - { - size_t i = 0; - while (papszArgv[i]) - RTStrFree(papszArgv[i++]); - RTMemFree(papszArgv); - } + if (papszArgv) + { + size_t i = 0; + while (papszArgv[i]) + RTStrFree(papszArgv[i++]); + RTMemFree(papszArgv); } + } - /* Calculate arguments size (in bytes). */ - size_t cbArgs = 0; - if (RT_SUCCESS(vrc)) - cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */ + /* Calculate arguments size (in bytes). */ + size_t cbArgs = 0; + if (RT_SUCCESS(vrc)) + cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */ - /* Prepare environment. */ - void *pvEnv = NULL; - size_t cbEnv = 0; - if (RT_SUCCESS(vrc)) - vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */); + /* Prepare environment. */ + void *pvEnv = NULL; + size_t cbEnv = 0; + if (RT_SUCCESS(vrc)) + vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */); - if (RT_SUCCESS(vrc)) + if (RT_SUCCESS(vrc)) + { + AssertPtr(mSession); + uint32_t uProtocol = mSession->getProtocolVersion(); + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[16]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(), + (ULONG)mData.mProcess.mCommand.length() + 1); + paParms[i++].setUInt32(mData.mProcess.mFlags); + paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size()); + paParms[i++].setPointer((void*)pszArgs, (uint32_t)cbArgs); + paParms[i++].setUInt32((uint32_t)mData.mProcess.mEnvironment.Size()); + paParms[i++].setUInt32((uint32_t)cbEnv); + paParms[i++].setPointer((void*)pvEnv, (uint32_t)cbEnv); + if (uProtocol < 2) { - /* Prepare HGCM call. */ - VBOXHGCMSVCPARM paParms[15]; - int i = 0; - paParms[i++].setUInt32(uContextID); - paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(), - (ULONG)mData.mProcess.mCommand.length() + 1); - paParms[i++].setUInt32(mData.mProcess.mFlags); - paParms[i++].setUInt32(mData.mProcess.mArguments.size()); - paParms[i++].setPointer((void*)pszArgs, cbArgs); - paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size()); - paParms[i++].setUInt32(cbEnv); - paParms[i++].setPointer((void*)pvEnv, cbEnv); + /* In protocol v1 (VBox < 4.3) the credentials were part of the execution + * call. In newer protocols these credentials are part of the opened guest + * session, so not needed anymore here. */ paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1); paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1); - /** @todo New command needs the domain as well! */ - - /* - * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout - * until the process was started - the process itself then gets an infinite timeout for execution. - * This is handy when we want to start a process inside a worker thread within a certain timeout - * but let the started process perform lengthly operations then. - */ - if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) - paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */); - else - paParms[i++].setUInt32(mData.mProcess.mTimeoutMS); - - /* Note: Don't hold the write lock in here, because setErrorInternal */ - vrc = sendCommand(HOST_EXEC_CMD, i, paParms); + } + /* + * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout + * until the process was started - the process itself then gets an infinite timeout for execution. + * This is handy when we want to start a process inside a worker thread within a certain timeout + * but let the started process perform lengthly operations then. + */ + if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) + paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */); + else + paParms[i++].setUInt32(mData.mProcess.mTimeoutMS); + if (uProtocol >= 2) + { + paParms[i++].setUInt32(mData.mProcess.mPriority); + /* CPU affinity: We only support one CPU affinity block at the moment, + * so that makes up to 64 CPUs total. This can be more in the future. */ + paParms[i++].setUInt32(1); + /* The actual CPU affinity blocks. */ + paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity)); } - GuestEnvironment::FreeEnvironmentBlock(pvEnv); - if (pszArgs) - RTStrFree(pszArgs); - - uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS; - - /* Drop the write lock again before waiting. */ - alock.release(); + alock.release(); /* Drop the write lock before sending. */ - if (RT_SUCCESS(vrc)) + vrc = sendCommand(HOST_EXEC_CMD, i, paParms); + if (RT_FAILURE(vrc)) { - /* - * Let's wait for the process being started. - * Note: Be sure not keeping a AutoRead/WriteLock here. - */ - LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); - vrc = pCallbackStart->Wait(uTimeoutMS); - if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ - { - int guestRc = pCallbackStart->GetResultCode(); - if (pGuestRc) - *pGuestRc = guestRc; - LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); - } - else - vrc = VERR_TIMEOUT; + int rc2 = setProcessStatus(ProcessStatus_Error, vrc); + AssertRC(rc2); } + } - AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS); + GuestEnvironment::FreeEnvironmentBlock(pvEnv); + if (pszArgs) + RTStrFree(pszArgs); - AssertPtr(pCallbackStart); - int rc2 = callbackRemove(uContextID); - if (RT_SUCCESS(vrc)) - vrc = rc2; - } + if (RT_SUCCESS(vrc)) + vrc = waitForStatusChange(pEvent, uTimeoutMS, + NULL /* Process status */, pGuestRc); + unregisterWaitEvent(pEvent); LogFlowFuncLeaveRC(vrc); return vrc; @@ -1291,208 +1235,477 @@ DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser AutoCaller autoCaller(pProcess); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */); - /* Nothing to do here anymore. */ + int vrc = pProcess->startProcess(30 * 1000 /* 30s timeout */, + NULL /* Guest rc, ignored */); + /* Nothing to do here anymore. */ + + LogFlowFunc(("pProcess=%p returning rc=%Rrc\n", (GuestProcess *)pProcess, vrc)); + return vrc; +} + +int GuestProcess::terminateProcess(uint32_t uTimeoutMS, int *pGuestRc) +{ + /* pGuestRc is optional. */ + LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc = VINF_SUCCESS; + + if (mData.mStatus != ProcessStatus_Started) + { + LogFlowThisFunc(("Process not in started state (state is %RU32), skipping termination\n", + mData.mStatus)); + } + else + { + AssertPtr(mSession); + /* Note: VBox < 4.3 (aka protocol version 1) does not + * support this, so just skip. */ + if (mSession->getProtocolVersion() < 2) + vrc = VERR_NOT_SUPPORTED; + + if (RT_SUCCESS(vrc)) + { + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); + + vrc = registerWaitEvent(eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mPID); + + alock.release(); /* Drop the write lock before sending. */ + + vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForStatusChange(pEvent, uTimeoutMS, + NULL /* ProcessStatus */, pGuestRc); + unregisterWaitEvent(pEvent); + } + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/* static */ +ProcessWaitResult_T GuestProcess::waitFlagsToResultEx(uint32_t fWaitFlags, + ProcessStatus_T oldStatus, ProcessStatus_T newStatus, + uint32_t uProcFlags, uint32_t uProtocol) +{ + ProcessWaitResult_T waitResult = ProcessWaitResult_None; + + switch (newStatus) + { + case ProcessStatus_TerminatedNormally: + case ProcessStatus_TerminatedSignal: + case ProcessStatus_TerminatedAbnormally: + case ProcessStatus_Down: + /* Nothing to wait for anymore. */ + waitResult = ProcessWaitResult_Terminate; + break; + + case ProcessStatus_TimedOutKilled: + case ProcessStatus_TimedOutAbnormally: + /* Dito. */ + waitResult = ProcessWaitResult_Timeout; + break; - LogFlowFuncLeaveRC(vrc); - return vrc; -} + case ProcessStatus_Started: + switch (oldStatus) + { + case ProcessStatus_Undefined: + case ProcessStatus_Starting: + /* Also wait for process start. */ + if (fWaitFlags & ProcessWaitForFlag_Start) + waitResult = ProcessWaitResult_Start; + else + { + /* + * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the + * caller is not interested in getting further process statuses -- so just don't notify + * anything here anymore and return. + */ + if (uProcFlags & ProcessCreateFlag_WaitForProcessStartOnly) + waitResult = ProcessWaitResult_Start; + } + break; + + case ProcessStatus_Started: + /* Only wait for process start. */ + if (fWaitFlags == ProcessWaitForFlag_Start) + waitResult = ProcessWaitResult_Start; + break; + + default: + AssertMsgFailed(("Unhandled old status %RU32 before new status 'started'\n", + oldStatus)); + waitResult = ProcessWaitResult_Start; + break; + } + break; -int GuestProcess::terminateProcess(void) -{ - LogFlowThisFuncEnter(); + case ProcessStatus_Error: + /* Nothing to wait for anymore. */ + waitResult = ProcessWaitResult_Error; + break; - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + case ProcessStatus_Undefined: + case ProcessStatus_Starting: + /* No result available yet, leave wait + * flags untouched. */ + break; + } - if (mData.mParent->getProtocolVersion() < 2) - return VERR_NOT_SUPPORTED; + if (newStatus == ProcessStatus_Started) + { + /* Filter out waits which are *not* supported using + * older guest control Guest Additions. + * + ** @todo ProcessWaitForFlag_Std* flags are not implemented yet. + */ + if (uProtocol < 99) /* See @todo above. */ + { + if ( waitResult == ProcessWaitResult_None + /* We don't support waiting for stdin, out + err, + * just skip waiting then. */ + && ( (fWaitFlags & ProcessWaitForFlag_StdIn) + || (fWaitFlags & ProcessWaitForFlag_StdOut) + || (fWaitFlags & ProcessWaitForFlag_StdErr) + ) + ) + { + /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */ + waitResult = ProcessWaitResult_WaitFlagNotSupported; + } + } + } - LogFlowThisFuncLeave(); - return VERR_NOT_IMPLEMENTED; +#ifdef DEBUG + LogFlowFunc(("oldStatus=%RU32, newStatus=%RU32, fWaitFlags=0x%x, waitResult=%RU32\n", + oldStatus, newStatus, fWaitFlags, waitResult)); +#endif + return waitResult; } -int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc) +ProcessWaitResult_T GuestProcess::waitFlagsToResult(uint32_t fWaitFlags) { - LogFlowThisFuncEnter(); + AssertPtr(mSession); + return GuestProcess::waitFlagsToResultEx(fWaitFlags, + mData.mStatus /* curStatus */, mData.mStatus /* newStatus */, + mData.mProcess.mFlags, mSession->getProtocolVersion()); +} +int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, + ProcessWaitResult_T &waitResult, int *pGuestRc) +{ AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); - LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", - fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, procStatus=%RU32, procRc=%Rrc, pGuestRc=%p\n", + fWaitFlags, uTimeoutMS, mData.mStatus, mData.mLastError, pGuestRc)); /* Did some error occur before? Then skip waiting and return. */ - if (mData.mStatus == ProcessStatus_Error) + ProcessStatus_T curStatus = mData.mStatus; + if (curStatus == ProcessStatus_Error) { waitResult = ProcessWaitResult_Error; - AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC)); + AssertMsg(RT_FAILURE(mData.mLastError), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mLastError)); if (pGuestRc) - *pGuestRc = mData.mRC; /* Return last set error. */ - return VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ + *pGuestRc = mData.mLastError; /* Return last set error. */ + LogFlowThisFunc(("Process is in error state (guestRc=%Rrc)\n", mData.mLastError)); + return VERR_GSTCTL_GUEST_ERROR; } - waitResult = ProcessWaitResult_None; - if ( (fWaitFlags & ProcessWaitForFlag_Terminate) - || (fWaitFlags & ProcessWaitForFlag_StdIn) - || (fWaitFlags & ProcessWaitForFlag_StdOut) - || (fWaitFlags & ProcessWaitForFlag_StdErr)) - { - switch (mData.mStatus) - { - case ProcessStatus_TerminatedNormally: - case ProcessStatus_TerminatedSignal: - case ProcessStatus_TerminatedAbnormally: - case ProcessStatus_Down: - waitResult = ProcessWaitResult_Terminate; - break; + waitResult = waitFlagsToResult(fWaitFlags); - case ProcessStatus_TimedOutKilled: - case ProcessStatus_TimedOutAbnormally: - waitResult = ProcessWaitResult_Timeout; - break; + /* No waiting needed? Return immediately using the last set error. */ + if (waitResult != ProcessWaitResult_None) + { + if (pGuestRc) + *pGuestRc = mData.mLastError; /* Return last set error (if any). */ + LogFlowThisFunc(("Nothing to wait for (guestRc=%Rrc)\n", mData.mLastError)); + return RT_SUCCESS(mData.mLastError) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR; + } - case ProcessStatus_Error: - /* Handled above. */ - break; + /* Adjust timeout. Passing 0 means RT_INDEFINITE_WAIT. */ + if (!uTimeoutMS) + uTimeoutMS = RT_INDEFINITE_WAIT; - case ProcessStatus_Started: - { - /* - * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the - * caller is not interested in getting further process statuses -- so just don't notify - * anything here anymore and return. - */ - if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) - waitResult = ProcessWaitResult_Start; - break; - } + int vrc; - case ProcessStatus_Undefined: - case ProcessStatus_Starting: - /* Do the waiting below. */ - break; + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); - default: - AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus)); - return VERR_NOT_IMPLEMENTED; - } + vrc = registerWaitEvent(eventTypes, &pEvent); } - else if (fWaitFlags & ProcessWaitForFlag_Start) + catch (std::bad_alloc) { - switch (mData.mStatus) - { - case ProcessStatus_Started: - case ProcessStatus_Paused: - case ProcessStatus_Terminating: - case ProcessStatus_TerminatedNormally: - case ProcessStatus_TerminatedSignal: - case ProcessStatus_TerminatedAbnormally: - case ProcessStatus_Down: - waitResult = ProcessWaitResult_Start; - break; + vrc = VERR_NO_MEMORY; + } - case ProcessStatus_Error: - waitResult = ProcessWaitResult_Error; - break; + if (RT_FAILURE(vrc)) + return vrc; - case ProcessStatus_TimedOutKilled: - case ProcessStatus_TimedOutAbnormally: - waitResult = ProcessWaitResult_Timeout; - break; + alock.release(); /* Release lock before waiting. */ - case ProcessStatus_Undefined: - case ProcessStatus_Starting: - /* Do the waiting below. */ - break; + /* + * Do the actual waiting. + */ + ProcessStatus_T newStatus = ProcessStatus_Undefined; + uint64_t u64StartMS = RTTimeMilliTS(); + for (;;) + { + uint64_t u64ElapsedMS = RTTimeMilliTS() - u64StartMS; + if ( uTimeoutMS != RT_INDEFINITE_WAIT + && u64ElapsedMS >= uTimeoutMS) + { + vrc = VERR_TIMEOUT; + break; + } - default: - AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus)); - return VERR_NOT_IMPLEMENTED; + vrc = waitForStatusChange(pEvent, + uTimeoutMS == RT_INDEFINITE_WAIT + ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS, + &newStatus, pGuestRc); + if (RT_SUCCESS(vrc)) + { + alock.acquire(); + + waitResult = waitFlagsToResultEx(fWaitFlags, curStatus, newStatus, + mData.mProcess.mFlags, mSession->getProtocolVersion()); +#ifdef DEBUG + LogFlowThisFunc(("Got new status change: fWaitFlags=0x%x, newStatus=%RU32, waitResult=%RU32\n", + fWaitFlags, newStatus, waitResult)); +#endif + if (ProcessWaitResult_None != waitResult) /* We got a waiting result. */ + break; } + else /* Waiting failed, bail out. */ + break; + + alock.release(); /* Don't hold lock in next waiting round. */ } - /* Filter out waits which are *not* supported using - * older guest control Guest Additions. */ - if (mData.mParent->getProtocolVersion() < 2) + unregisterWaitEvent(pEvent); + + LogFlowThisFunc(("Returned waitResult=%RU32, newStatus=%RU32, rc=%Rrc\n", + waitResult, newStatus, vrc)); + return vrc; +} + +int GuestProcess::waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, + ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) { - if ( waitResult == ProcessWaitResult_None - /* We don't support waiting for stdin, out + err, - * just skip waiting then. */ - && ( (fWaitFlags & ProcessWaitForFlag_StdIn) - || (fWaitFlags & ProcessWaitForFlag_StdOut) - || (fWaitFlags & ProcessWaitForFlag_StdErr) - ) - ) + if (evtType == VBoxEventType_OnGuestProcessInputNotify) { - /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */ - waitResult = ProcessWaitResult_WaitFlagNotSupported; + ComPtr pProcessEvent = pIEvent; + Assert(!pProcessEvent.isNull()); + + if (pInputStatus) + { + HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus); + ComAssertComRC(hr2); + } + if (pcbProcessed) + { + HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed); + ComAssertComRC(hr2); + } } + else + vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; } - LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n", - mData.mStatus, mData.mRC, waitResult)); + LogFlowThisFunc(("Returning pEvent=%p, uHandle=%RU32, rc=%Rrc\n", + pEvent, uHandle, vrc)); + return vrc; +} - /* No waiting needed? Return immediately using the last set error. */ - if (waitResult != ProcessWaitResult_None) - { - if (pGuestRc) - *pGuestRc = mData.mRC; /* Return last set error (if any). */ - return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ - } +int GuestProcess::waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, + void *pvData, size_t cbData, uint32_t *pcbRead) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + /* pvData is optional. */ + /* cbData is optional. */ + /* pcbRead is optional. */ - if (mData.mWaitCount > 0) - return VERR_ALREADY_EXISTS; - mData.mWaitCount++; + LogFlowThisFunc(("cEventTypes=%zu, pEvent=%p, uHandle=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu, pcbRead=%p\n", + pEvent->TypeCount(), pEvent, uHandle, uTimeoutMS, pvData, cbData, pcbRead)); - int vrc = VINF_SUCCESS; - try + int vrc; + + VBoxEventType_T evtType; + ComPtr pIEvent; + do { - Assert(mData.mWaitEvent == NULL); - mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags); - } - catch(std::bad_alloc &) + vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + if (evtType == VBoxEventType_OnGuestProcessOutput) + { + ComPtr pProcessEvent = pIEvent; + Assert(!pProcessEvent.isNull()); + + ULONG uHandleEvent; + HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent); + if ( SUCCEEDED(hr) + && uHandleEvent == uHandle) + { + if (pvData) + { + com::SafeArray data; + hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data)); + ComAssertComRC(hr); + size_t cbRead = data.size(); + if (cbRead) + { + if (cbRead <= cbData) + { + /* Copy data from event into our buffer. */ + memcpy(pvData, data.raw(), data.size()); + } + else + vrc = VERR_BUFFER_OVERFLOW; + + LogFlowThisFunc(("Read %zu bytes (uHandle=%RU32), rc=%Rrc\n", + cbRead, uHandleEvent, vrc)); + } + } + + if ( RT_SUCCESS(vrc) + && pcbRead) + { + ULONG cbRead; + hr = pProcessEvent->COMGETTER(Processed)(&cbRead); + ComAssertComRC(hr); + *pcbRead = (uint32_t)cbRead; + } + + break; + } + else if (FAILED(hr)) + vrc = VERR_COM_UNEXPECTED; + } + else + vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; + } + + } while (vrc == VINF_SUCCESS); + + if ( vrc != VINF_SUCCESS + && pcbRead) { - vrc = VERR_NO_MEMORY; + *pcbRead = 0; } + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestProcess::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, + ProcessStatus_T *pProcessStatus, int *pGuestRc) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + /* pProcessStatus is optional. */ + /* pGuestRc is optional. */ + + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); if (RT_SUCCESS(vrc)) { - GuestProcessWaitEvent *pEvent = mData.mWaitEvent; - AssertPtr(pEvent); - - alock.release(); /* Release lock before waiting. */ + Assert(evtType == VBoxEventType_OnGuestProcessStateChanged); + ComPtr pProcessEvent = pIEvent; + Assert(!pProcessEvent.isNull()); - vrc = pEvent->Wait(uTimeoutMS); - LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc)); - if (RT_SUCCESS(vrc)) - { - waitResult = pEvent->GetWaitResult(); - int waitRc = pEvent->GetWaitRc(); + ProcessStatus_T procStatus; + HRESULT hr = pProcessEvent->COMGETTER(Status)(&procStatus); + ComAssertComRC(hr); + if (pProcessStatus) + *pProcessStatus = procStatus; - LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", waitRc)); + ComPtr errorInfo; + hr = pProcessEvent->COMGETTER(Error)(errorInfo.asOutParam()); + ComAssertComRC(hr); - if (pGuestRc) - *pGuestRc = waitRc; + LONG lGuestRc; + hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc); + ComAssertComRC(hr); - vrc = RT_SUCCESS(waitRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ - } + LogFlowThisFunc(("Got procStatus=%RU32, guestRc=%RI32 (%Rrc)\n", + procStatus, lGuestRc, lGuestRc)); - alock.acquire(); /* Get the lock again. */ + if (RT_FAILURE((int)lGuestRc)) + vrc = VERR_GSTCTL_GUEST_ERROR; - /* Note: The caller always is responsible of deleting the - * stuff it created before. See close() for more information. */ - delete mData.mWaitEvent; - mData.mWaitEvent = NULL; + if (pGuestRc) + *pGuestRc = (int)lGuestRc; } - Assert(mData.mWaitCount); - mData.mWaitCount--; - LogFlowFuncLeaveRC(vrc); return vrc; } +/* static */ +bool GuestProcess::waitResultImpliesEx(ProcessWaitResult_T waitResult, + ProcessStatus_T procStatus, uint32_t uProcFlags, + uint32_t uProtocol) +{ + bool fImplies; + + switch (waitResult) + { + case ProcessWaitResult_Start: + fImplies = procStatus == ProcessStatus_Started; + break; + + case ProcessWaitResult_Terminate: + fImplies = ( procStatus == ProcessStatus_TerminatedNormally + || procStatus == ProcessStatus_TerminatedSignal + || procStatus == ProcessStatus_TerminatedAbnormally + || procStatus == ProcessStatus_TimedOutKilled + || procStatus == ProcessStatus_TimedOutAbnormally + || procStatus == ProcessStatus_Down + || procStatus == ProcessStatus_Error); + break; + + default: + fImplies = false; + break; + } + + return fImplies; +} + int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc) { @@ -1511,107 +1724,64 @@ int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags, return VINF_SUCCESS; /* Not available for writing (anymore). */ } - int vrc = VINF_SUCCESS; + int vrc; - GuestCtrlCallback *pCallbackWrite = NULL; + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; try { - pCallbackWrite = new GuestCtrlCallback(); + /* + * On Guest Additions < 4.3 there is no guarantee that the process status + * change arrives *after* the input event, e.g. if this was the last input + * block being written and the process will report status "terminate". + * So just skip checking for process status change and only wait for the + * input event. + */ + if (mSession->getProtocolVersion() >= 2) + eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); + eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify); + + vrc = registerWaitEvent(eventTypes, &pEvent); } - catch(std::bad_alloc &) + catch (std::bad_alloc) { vrc = VERR_NO_MEMORY; } - /* Create callback and add it to the map. */ - uint32_t uContextID = 0; - if (RT_SUCCESS(vrc)) - { - vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS); - if (RT_SUCCESS(vrc)) - vrc = callbackAdd(pCallbackWrite, &uContextID); - } - - alock.release(); /* Drop the write lock again. */ - - if (RT_SUCCESS(vrc)) - { - VBOXHGCMSVCPARM paParms[5]; + if (RT_FAILURE(vrc)) + return vrc; - int i = 0; - paParms[i++].setUInt32(uContextID); - paParms[i++].setUInt32(mData.mPID); - paParms[i++].setUInt32(uFlags); - paParms[i++].setPointer(pvData, cbData); - paParms[i++].setUInt32(cbData); + VBOXHGCMSVCPARM paParms[5]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mPID); + paParms[i++].setUInt32(uFlags); + paParms[i++].setPointer(pvData, (uint32_t)cbData); + paParms[i++].setUInt32((uint32_t)cbData); - vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms); - } + alock.release(); /* Drop the write lock before sending. */ + uint32_t cbProcessed = 0; + vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms); if (RT_SUCCESS(vrc)) { - /* - * Let's wait for the process being started. - * Note: Be sure not keeping a AutoRead/WriteLock here. - */ - LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); - vrc = pCallbackWrite->Wait(uTimeoutMS); - if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ + ProcessInputStatus_T inputStatus; + vrc = waitForInputNotify(pEvent, uHandle, uTimeoutMS, + &inputStatus, &cbProcessed); + if (RT_SUCCESS(vrc)) { - int guestRc = pCallbackWrite->GetResultCode(); - LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackWrite->GetDataSize())); - - if (RT_SUCCESS(guestRc)) - { - Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS)); - PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)pCallbackWrite->GetDataRaw(); - AssertPtr(pData); - - uint32_t cbWritten = 0; - switch (pData->u32Status) - { - case INPUT_STS_WRITTEN: - cbWritten = pData->cbProcessed; - break; - - case INPUT_STS_ERROR: - vrc = pData->u32Flags; /** @todo Fix int vs. uint32_t! */ - break; - - case INPUT_STS_TERMINATED: - vrc = VERR_CANCELLED; - break; - - case INPUT_STS_OVERFLOW: - vrc = VERR_BUFFER_OVERFLOW; - break; - - default: - /* Silently skip unknown errors. */ - break; - } + /** @todo Set guestRc. */ - LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); - - if (pGuestRc) - *pGuestRc = guestRc; - - if (puWritten) - *puWritten = cbWritten; - - if (RT_FAILURE(guestRc)) - vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ - } + if (puWritten) + *puWritten = cbProcessed; } + /** @todo Error handling. */ } - alock.acquire(); + unregisterWaitEvent(pEvent); - int rc2 = callbackRemove(uContextID); - if (RT_SUCCESS(vrc)) - vrc = rc2; - - LogFlowFuncLeaveRC(vrc); + LogFlowThisFunc(("Returning cbProcessed=%RU32, rc=%Rrc\n", + cbProcessed, vrc)); return vrc; } @@ -1623,6 +1793,8 @@ STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else + LogFlowThisFuncEnter(); + if (aToRead == 0) return setError(E_INVALIDARG, tr("The size to read is zero")); CheckComArgOutSafeArrayPointerValid(aData); @@ -1635,7 +1807,7 @@ STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, HRESULT hr = S_OK; - size_t cbRead; int guestRc; + uint32_t cbRead; int guestRc; int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc); if (RT_SUCCESS(vrc)) { @@ -1647,7 +1819,7 @@ STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1659,7 +1831,7 @@ STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, } } - LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead)); + LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32\n", vrc, cbRead)); LogFlowFuncLeaveRC(vrc); return hr; @@ -1678,14 +1850,16 @@ STDMETHODIMP GuestProcess::Terminate(void) HRESULT hr = S_OK; - int vrc = terminateProcess(); + int guestRc; + int vrc = terminateProcess(30 * 1000 /* Timeout in ms */, + &guestRc); if (RT_FAILURE(vrc)) { switch (vrc) { - case VERR_NOT_IMPLEMENTED: - ReturnComNotImplemented(); - break; /* Never reached. */ + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestProcess::setErrorExternal(this, guestRc); + break; case VERR_NOT_SUPPORTED: hr = setError(VBOX_E_IPRT_ERROR, @@ -1701,15 +1875,12 @@ STDMETHODIMP GuestProcess::Terminate(void) } } - AssertPtr(mData.mParent); - mData.mParent->processRemoveFromList(this); - - /* - * Release autocaller before calling uninit. - */ - autoCaller.release(); - - uninit(); + /* Remove process from guest session list. Now only API clients + * still can hold references to it. */ + AssertPtr(mSession); + int rc2 = mSession->processRemoveFromList(this); + if (RT_SUCCESS(vrc)) + vrc = rc2; LogFlowFuncLeaveRC(vrc); return hr; @@ -1743,7 +1914,7 @@ STDMETHODIMP GuestProcess::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWa { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1796,22 +1967,23 @@ STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags, #else LogFlowThisFuncEnter(); + CheckComArgSafeArrayNotNull(aData); CheckComArgOutPointerValid(aWritten); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + com::SafeArray data(ComSafeArrayInArg(aData)); HRESULT hr = S_OK; - com::SafeArray data(ComSafeArrayInArg(aData)); int guestRc; - int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc); + uint32_t cbWritten; int guestRc; + int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, &cbWritten, &guestRc); if (RT_FAILURE(vrc)) { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1823,7 +1995,9 @@ STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags, } } - LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten)); + LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, cbWritten)); + + *aWritten = (ULONG)cbWritten; LogFlowFuncLeaveRC(vrc); return hr; @@ -1838,6 +2012,7 @@ STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInput #else LogFlowThisFuncEnter(); + CheckComArgSafeArrayNotNull(aData); CheckComArgOutPointerValid(aWritten); AutoCaller autoCaller(this); @@ -1858,13 +2033,14 @@ STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInput /////////////////////////////////////////////////////////////////////////////// GuestProcessTool::GuestProcessTool(void) - : pSession(NULL) + : pSession(NULL), + pProcess(NULL) { } GuestProcessTool::~GuestProcessTool(void) { - Terminate(); + Terminate(30 * 1000, NULL /* pGuestRc */); } int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, @@ -1875,7 +2051,7 @@ int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartu AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER); - pSession = pGuestSession; + pSession = pGuestSession; mStartupInfo = startupInfo; /* Make sure the process is hidden. */ @@ -1883,15 +2059,18 @@ int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartu int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess); if (RT_SUCCESS(vrc)) - vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc); + vrc = fAsync + ? pProcess->startProcessAsync() + : pProcess->startProcess(30 * 1000 /* 30s timeout */, pGuestRc); - if ( !fAsync + if ( RT_SUCCESS(vrc) + && !fAsync && ( pGuestRc && RT_FAILURE(*pGuestRc) ) ) { - vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ + vrc = VERR_GSTCTL_GUEST_ERROR; } LogFlowFuncLeaveRC(vrc); @@ -1925,20 +2104,78 @@ int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock bool GuestProcessTool::IsRunning(void) { - AssertReturn(!pProcess.isNull(), true); + AssertReturn(!pProcess.isNull(), false); ProcessStatus_T procStatus = ProcessStatus_Undefined; HRESULT hr = pProcess->COMGETTER(Status(&procStatus)); Assert(SUCCEEDED(hr)); - if ( procStatus != ProcessStatus_Started - && procStatus != ProcessStatus_Paused - && procStatus != ProcessStatus_Terminating) + if ( procStatus == ProcessStatus_Started + || procStatus == ProcessStatus_Paused + || procStatus == ProcessStatus_Terminating) + { + return true; + } + + return false; +} + +/* static */ +int GuestProcessTool::Run( GuestSession *pGuestSession, + const GuestProcessStartupInfo &startupInfo, + int *pGuestRc) +{ + return RunEx(pGuestSession, startupInfo, + NULL /* pStrmOutObjects */, 0 /* cStrmOutObjects */, + pGuestRc); +} + +/* static */ +int GuestProcessTool::RunEx( GuestSession *pGuestSession, + const GuestProcessStartupInfo &startupInfo, + GuestCtrlStreamObjects *pStrmOutObjects, + uint32_t cStrmOutObjects, + int *pGuestRc) +{ + GuestProcessTool procTool; int guestRc; + int vrc = procTool.Init(pGuestSession, startupInfo, false /* Async */, &guestRc); + if (RT_SUCCESS(vrc)) + { + while (cStrmOutObjects--) + { + try + { + GuestProcessStreamBlock strmBlk; + vrc = procTool.WaitEx( pStrmOutObjects + ? GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK + : GUESTPROCESSTOOL_FLAG_NONE, &strmBlk, &guestRc); + if (pStrmOutObjects) + pStrmOutObjects->push_back(strmBlk); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + } + } + + if (RT_SUCCESS(vrc)) { - return false; + /* Make sure the process runs until completion. */ + vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); + if (RT_SUCCESS(vrc)) + { + guestRc = procTool.TerminatedOk(NULL /* Exit code */); + if (RT_FAILURE(guestRc)) + vrc = VERR_GSTCTL_GUEST_ERROR; + } } - return true; + if (pGuestRc) + *pGuestRc = guestRc; + + LogFlowFunc(("Returned rc=%Rrc, guestRc=%Rrc\n", vrc, guestRc)); + return vrc; } int GuestProcessTool::TerminatedOk(LONG *pExitCode) @@ -1946,6 +2183,7 @@ int GuestProcessTool::TerminatedOk(LONG *pExitCode) Assert(!pProcess.isNull()); /* pExitCode is optional. */ + int vrc; if (!IsRunning()) { LONG exitCode; @@ -1955,36 +2193,36 @@ int GuestProcessTool::TerminatedOk(LONG *pExitCode) if (pExitCode) *pExitCode = exitCode; - if (exitCode != 0) - return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */ - return VINF_SUCCESS; + vrc = (exitCode != 0) + /** @todo Special guest control rc needed! */ + ? VERR_NOT_EQUAL : VINF_SUCCESS; } + else + vrc = VERR_INVALID_STATE; /** @todo Special guest control rc needed! */ - return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */ + LogFlowFuncLeaveRC(vrc); + return vrc; } int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc) { - return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc); + return WaitEx(fFlags, NULL /* pStrmBlkOut */, pGuestRc); } -int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc) +int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStrmBlkOut, int *pGuestRc) { - LogFlowThisFunc(("pSession=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n", - pSession, fFlags, pStreamBlock, pGuestRc)); - - AssertPtrReturn(pSession, VERR_INVALID_POINTER); - Assert(!pProcess.isNull()); - /* Other parameters are optional. */ + LogFlowThisFunc(("fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n", + fFlags, pStrmBlkOut, pGuestRc)); /* Can we parse the next block without waiting? */ int vrc; if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK) { - AssertPtr(pStreamBlock); - vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock); + AssertPtr(pStrmBlkOut); + vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut); if (RT_SUCCESS(vrc)) return vrc; + /* else do the the waiting below. */ } /* Do the waiting. */ @@ -1994,25 +2232,47 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr) fWaitFlags |= ProcessWaitForFlag_StdErr; - LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags)); - - /** @todo Decrease timeout. */ + /** @todo Decrease timeout while running. */ + uint64_t u64StartMS = RTTimeMilliTS(); uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS; int guestRc; bool fDone = false; BYTE byBuf[_64K]; - size_t cbRead; + uint32_t cbRead; bool fHandleStdOut = false; bool fHandleStdErr = false; + /** + * Updates the elapsed time and checks if a + * timeout happened, then breaking out of the loop. + */ +#define UPDATE_AND_CHECK_ELAPSED_TIME() \ + u64ElapsedMS = RTTimeMilliTS() - u64StartMS; \ + if ( uTimeoutMS != RT_INDEFINITE_WAIT \ + && u64ElapsedMS >= uTimeoutMS) \ + { \ + vrc = VERR_TIMEOUT; \ + break; \ + } + + /** + * Returns the remaining time (in ms). + */ +#define GET_REMAINING_TIME \ + uTimeoutMS == RT_INDEFINITE_WAIT \ + ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS \ + ProcessWaitResult_T waitRes; do { - vrc = pProcess->waitFor(fWaitFlags, - uTimeoutMS, waitRes, &guestRc); + uint64_t u64ElapsedMS; + UPDATE_AND_CHECK_ELAPSED_TIME(); + + vrc = pProcess->waitFor(fWaitFlags, GET_REMAINING_TIME, + waitRes, &guestRc); if (RT_FAILURE(vrc)) break; @@ -2041,7 +2301,7 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl break; case ProcessWaitResult_Error: - vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ + vrc = VERR_GSTCTL_GUEST_ERROR; break; case ProcessWaitResult_Terminate: @@ -2058,28 +2318,39 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl break; default: - AssertReleaseMsgFailed(("Unhandled process wait result %ld\n", waitRes)); + AssertMsgFailed(("Unhandled process wait result %RU32\n", waitRes)); break; } + if (RT_FAILURE(vrc)) + break; + if (fHandleStdOut) { + UPDATE_AND_CHECK_ELAPSED_TIME(); + + cbRead = 0; vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), - uTimeoutMS, byBuf, sizeof(byBuf), + GET_REMAINING_TIME, + byBuf, sizeof(byBuf), &cbRead, &guestRc); - if (RT_FAILURE(vrc)) + if ( RT_FAILURE(vrc) + || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED) break; if (cbRead) { - LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead)); + LogFlowThisFunc(("Received %RU32 bytes from stdout\n", cbRead)); vrc = mStdOut.AddData(byBuf, cbRead); if ( RT_SUCCESS(vrc) && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)) { - AssertPtr(pStreamBlock); - vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock); + AssertPtr(pStrmBlkOut); + vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut); + + /* When successful, break out of the loop because we're done + * with reading the first stream block. */ if (RT_SUCCESS(vrc)) fDone = true; } @@ -2090,15 +2361,20 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl if (fHandleStdErr) { + UPDATE_AND_CHECK_ELAPSED_TIME(); + + cbRead = 0; vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf), - uTimeoutMS, byBuf, sizeof(byBuf), + GET_REMAINING_TIME, + byBuf, sizeof(byBuf), &cbRead, &guestRc); - if (RT_FAILURE(vrc)) + if ( RT_FAILURE(vrc) + || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED) break; if (cbRead) { - LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead)); + LogFlowThisFunc(("Received %RU32 bytes from stderr\n", cbRead)); vrc = mStdErr.AddData(byBuf, cbRead); } @@ -2107,7 +2383,13 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl } while (!fDone && RT_SUCCESS(vrc)); - LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n", +#undef UPDATE_AND_CHECK_ELAPSED_TIME +#undef GET_REMAINING_TIME + + if (RT_FAILURE(guestRc)) + vrc = VERR_GSTCTL_GUEST_ERROR; + + LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%RU32\n", vrc, guestRc, waitRes)); if (pGuestRc) *pGuestRc = guestRc; @@ -2116,21 +2398,20 @@ int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBl return vrc; } -void GuestProcessTool::Terminate(void) +int GuestProcessTool::Terminate(uint32_t uTimeoutMS, int *pGuestRc) { LogFlowThisFuncEnter(); + int rc = VINF_SUCCESS; if (!pProcess.isNull()) { - /** @todo Add pProcess.Terminate() here as soon as it's implemented. */ - - Assert(pSession); - int rc2 = pSession->processRemoveFromList(pProcess); - AssertRC(rc2); - + rc = pProcess->terminateProcess(uTimeoutMS, pGuestRc); pProcess.setNull(); } + else + rc = VERR_NOT_FOUND; - LogFlowThisFuncLeave(); + LogFlowFuncLeaveRC(rc); + return rc; } diff --git a/src/VBox/Main/src-client/GuestSessionImpl.cpp b/src/VBox/Main/src-client/GuestSessionImpl.cpp index f24337c6..433ac056 100644 --- a/src/VBox/Main/src-client/GuestSessionImpl.cpp +++ b/src/VBox/Main/src-client/GuestSessionImpl.cpp @@ -1,11 +1,10 @@ - /* $Id: GuestSessionImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest session handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,17 +22,22 @@ #include "GuestImpl.h" #include "GuestSessionImpl.h" #include "GuestCtrlImplPrivate.h" +#include "VirtualBoxErrorInfoImpl.h" #include "Global.h" #include "AutoCaller.h" #include "ProgressImpl.h" +#include "VBoxEvents.h" +#include "VMMDev.h" #include /* For auto_ptr. */ +#include /* For unconst(). */ #include #include /* For CopyTo/From. */ #include +#include #include #ifdef LOG_GROUP @@ -43,6 +47,96 @@ #include +/** + * Base class representing an internal + * asynchronous session task. + */ +class GuestSessionTaskInternal +{ +public: + + GuestSessionTaskInternal(GuestSession *pSession) + : mSession(pSession), + mRC(VINF_SUCCESS) { } + + virtual ~GuestSessionTaskInternal(void) { } + + int rc(void) const { return mRC; } + bool isOk(void) const { return RT_SUCCESS(mRC); } + const ComObjPtr &Session(void) const { return mSession; } + +protected: + + const ComObjPtr mSession; + int mRC; +}; + +/** + * Class for asynchronously opening a guest session. + */ +class GuestSessionTaskInternalOpen : public GuestSessionTaskInternal +{ +public: + + GuestSessionTaskInternalOpen(GuestSession *pSession) + : GuestSessionTaskInternal(pSession) { } +}; + +/** + * Internal listener class to serve events in an + * active manner, e.g. without polling delays. + */ +class GuestSessionListener +{ +public: + + GuestSessionListener(void) + { + } + + HRESULT init(GuestSession *pSession) + { + AssertPtrReturn(pSession, E_POINTER); + mSession = pSession; + return S_OK; + } + + void uninit(void) + { + mSession = NULL; + } + + STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent) + { + switch (aType) + { + case VBoxEventType_OnGuestSessionStateChanged: + { + AssertPtrReturn(mSession, E_POINTER); + int rc2 = mSession->signalWaitEvent(aType, aEvent); +#ifdef DEBUG_andy + LogFlowFunc(("Signalling events of type=%RU32, session=%p resulted in rc=%Rrc\n", + aType, mSession, rc2)); +#endif + break; + } + + default: + AssertMsgFailed(("Unhandled event %RU32\n", aType)); + break; + } + + return S_OK; + } + +private: + + GuestSession *mSession; +}; +typedef ListenerImpl GuestSessionListenerImpl; + +VBOX_LISTENER_DECLARE(GuestSessionListenerImpl) + // constructor / destructor ///////////////////////////////////////////////////////////////////////////// @@ -50,7 +144,7 @@ DEFINE_EMPTY_CTOR_DTOR(GuestSession) HRESULT GuestSession::FinalConstruct(void) { - LogFlowThisFunc(("\n")); + LogFlowThisFuncEnter(); return BaseFinalConstruct(); } @@ -65,32 +159,112 @@ void GuestSession::FinalRelease(void) // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// -int GuestSession::init(Guest *aGuest, ULONG aSessionID, - Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName) +/** + * Initializes a guest session but does *not* open in on the guest side + * yet. This needs to be done via the openSession() / openSessionAsync calls. + * + * @return IPRT status code. + ** @todo Docs! + */ +int GuestSession::init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo, + const GuestCredentials &guestCreds) { - LogFlowThisFuncEnter(); - - AssertPtrReturn(aGuest, VERR_INVALID_POINTER); + LogFlowThisFunc(("pGuest=%p, ssInfo=%p, guestCreds=%p\n", + pGuest, &ssInfo, &guestCreds)); /* Enclose the state transition NotReady->InInit->Ready. */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); - mData.mTimeout = 30 * 60 * 1000; /* Session timeout is 30 mins by default. */ - mData.mParent = aGuest; - mData.mId = aSessionID; +#ifndef VBOX_WITH_GUEST_CONTROL + autoInitSpan.setSucceeded(); + return VINF_SUCCESS; +#else + AssertPtrReturn(pGuest, VERR_INVALID_POINTER); + + mParent = pGuest; + + /* Copy over startup info. */ + /** @todo Use an overloaded copy operator. Later. */ + mData.mSession.mID = ssInfo.mID; + mData.mSession.mIsInternal = ssInfo.mIsInternal; + mData.mSession.mName = ssInfo.mName; + mData.mSession.mOpenFlags = ssInfo.mOpenFlags; + mData.mSession.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS; + + /** @todo Use an overloaded copy operator. Later. */ + mData.mCredentials.mUser = guestCreds.mUser; + mData.mCredentials.mPassword = guestCreds.mPassword; + mData.mCredentials.mDomain = guestCreds.mDomain; - mData.mCredentials.mUser = aUser; - mData.mCredentials.mPassword = aPassword; - mData.mCredentials.mDomain = aDomain; - mData.mName = aName; + mData.mRC = VINF_SUCCESS; + mData.mStatus = GuestSessionStatus_Undefined; mData.mNumObjects = 0; - /* Confirm a successful initialization when it's the case. */ - autoInitSpan.setSucceeded(); + HRESULT hr; - LogFlowFuncLeaveRC(VINF_SUCCESS); - return VINF_SUCCESS; + int rc = queryInfo(); + if (RT_SUCCESS(rc)) + { + hr = unconst(mEventSource).createObject(); + if (FAILED(hr)) + rc = VERR_NO_MEMORY; + else + { + hr = mEventSource->init(); + if (FAILED(hr)) + rc = VERR_COM_UNEXPECTED; + } + } + + if (RT_SUCCESS(rc)) + { + try + { + GuestSessionListener *pListener = new GuestSessionListener(); + ComObjPtr thisListener; + hr = thisListener.createObject(); + if (SUCCEEDED(hr)) + hr = thisListener->init(pListener, this); + + if (SUCCEEDED(hr)) + { + com::SafeArray eventTypes; + eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); + hr = mEventSource->RegisterListener(thisListener, + ComSafeArrayAsInParam(eventTypes), + TRUE /* Active listener */); + if (SUCCEEDED(hr)) + { + mLocalListener = thisListener; + + rc = RTCritSectInit(&mWaitEventCritSect); + AssertRC(rc); + } + else + rc = VERR_COM_UNEXPECTED; + } + else + rc = VERR_COM_UNEXPECTED; + } + catch(std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(rc)) + { + /* Confirm a successful initialization when it's the case. */ + autoInitSpan.setSucceeded(); + } + else + autoInitSpan.setFailed(); + + LogFlowThisFunc(("mName=%s, mID=%RU32, mIsInternal=%RTbool, rc=%Rrc\n", + mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc)); + return rc; +#endif /* VBOX_WITH_GUEST_CONTROL */ } /** @@ -99,60 +273,59 @@ int GuestSession::init(Guest *aGuest, ULONG aSessionID, */ void GuestSession::uninit(void) { - LogFlowThisFuncEnter(); - /* Enclose the state transition Ready->InUninit->NotReady. */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; + LogFlowThisFuncEnter(); + int rc = VINF_SUCCESS; -#ifndef VBOX_WITH_GUEST_CONTROL - LogFlowThisFunc(("Closing directories (%RU64 total)\n", +#ifdef VBOX_WITH_GUEST_CONTROL + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + LogFlowThisFunc(("Closing directories (%zu total)\n", mData.mDirectories.size())); for (SessionDirectories::iterator itDirs = mData.mDirectories.begin(); itDirs != mData.mDirectories.end(); ++itDirs) { -#ifdef DEBUG - ULONG cRefs = (*itDirs)->AddRef(); - LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs)); - (*itDirs)->Release(); -#endif - (*itDirs)->uninit(); + Assert(mData.mNumObjects); + mData.mNumObjects--; + itDirs->second->onRemove(); + itDirs->second->uninit(); } mData.mDirectories.clear(); - LogFlowThisFunc(("Closing files (%RU64 total)\n", + LogFlowThisFunc(("Closing files (%zu total)\n", mData.mFiles.size())); for (SessionFiles::iterator itFiles = mData.mFiles.begin(); itFiles != mData.mFiles.end(); ++itFiles) { -#ifdef DEBUG - ULONG cRefs = (*itFiles)->AddRef(); - LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs)); - (*itFiles)->Release(); -#endif - (*itFiles)->uninit(); + Assert(mData.mNumObjects); + mData.mNumObjects--; + itFiles->second->onRemove(); + itFiles->second->uninit(); } mData.mFiles.clear(); - LogFlowThisFunc(("Closing processes (%RU64 total)\n", + LogFlowThisFunc(("Closing processes (%zu total)\n", mData.mProcesses.size())); for (SessionProcesses::iterator itProcs = mData.mProcesses.begin(); itProcs != mData.mProcesses.end(); ++itProcs) { -#ifdef DEBUG - ULONG cRefs = itProcs->second->AddRef(); - LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs)); - itProcs->second->Release(); -#endif + Assert(mData.mNumObjects); + mData.mNumObjects--; + itProcs->second->onRemove(); itProcs->second->uninit(); } mData.mProcesses.clear(); - LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects)); -#endif + AssertMsg(mData.mNumObjects == 0, + ("mNumObjects=%RU32 when it should be 0\n", mData.mNumObjects)); + + baseUninit(); +#endif /* VBOX_WITH_GUEST_CONTROL */ LogFlowFuncLeaveRC(rc); } @@ -175,7 +348,7 @@ STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser) mData.mCredentials.mUser.cloneTo(aUser); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -196,7 +369,7 @@ STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain) mData.mCredentials.mDomain.cloneTo(aDomain); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -215,9 +388,9 @@ STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mName.cloneTo(aName); + mData.mSession.mName.cloneTo(aName); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -236,9 +409,30 @@ STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aId = mData.mId; + *aId = mData.mSession.mID; + + LogFlowThisFuncLeave(); + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestSession::COMGETTER(Status)(GuestSessionStatus_T *aStatus) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aStatus); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aStatus = mData.mStatus; - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -259,7 +453,7 @@ STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout) *aTimeout = mData.mTimeout; - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -278,7 +472,28 @@ STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout) mData.mTimeout = aTimeout; - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestSession::COMGETTER(ProtocolVersion)(ULONG *aVersion) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aVersion); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aVersion = mData.mProtocolVersion; + + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -298,7 +513,8 @@ STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnviron AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); size_t cEnvVars = mData.mEnvironment.Size(); - LogFlowThisFunc(("%s cEnvVars=%RU32\n", mData.mName.c_str(), cEnvVars)); + LogFlowThisFunc(("[%s]: cEnvVars=%RU32\n", + mData.mSession.mName.c_str(), cEnvVars)); com::SafeArray environment(cEnvVars); for (size_t i = 0; i < cEnvVars; i++) @@ -308,7 +524,7 @@ STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnviron } environment.detachTo(ComSafeArrayOutArg(aEnvironment)); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -358,7 +574,7 @@ STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, SafeIfaceArray collection(mData.mProcesses); collection.detachTo(ComSafeArrayOutArg(aProcesses)); - LogFlowFuncLeaveRC(S_OK); + LogFlowFunc(("mProcesses=%zu\n", collection.size())); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -380,7 +596,7 @@ STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirector SafeIfaceArray collection(mData.mDirectories); collection.detachTo(ComSafeArrayOutArg(aDirectories)); - LogFlowFuncLeaveRC(S_OK); + LogFlowFunc(("mDirectories=%zu\n", collection.size())); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -402,92 +618,156 @@ STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles SafeIfaceArray collection(mData.mFiles); collection.detachTo(ComSafeArrayOutArg(aFiles)); - LogFlowFuncLeaveRC(S_OK); + LogFlowFunc(("mFiles=%zu\n", collection.size())); + return S_OK; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aEventSource); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + // no need to lock - lifetime constant + mEventSource.queryInterfaceTo(aEventSource); + + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } // private methods -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -int GuestSession::directoryRemoveFromList(GuestDirectory *pDirectory) +int GuestSession::closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc) { + LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS)); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - for (SessionDirectories::iterator itDirs = mData.mDirectories.begin(); - itDirs != mData.mDirectories.end(); ++itDirs) + /* Guest Additions < 4.3 don't support closing dedicated + guest sessions, skip. */ + if (mData.mProtocolVersion < 2) { - if (pDirectory == (*itDirs)) - { - Bstr strName; - HRESULT hr = (*itDirs)->COMGETTER(DirectoryName)(strName.asOutParam()); - ComAssertComRC(hr); + LogFlowThisFunc(("Installed Guest Additions don't support closing dedicated sessions, skipping\n")); + return VINF_SUCCESS; + } - Assert(mData.mDirectories.size()); - LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n", - Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1)); + /** @todo uFlags validation. */ - mData.mDirectories.erase(itDirs); - return VINF_SUCCESS; - } + if (mData.mStatus != GuestSessionStatus_Started) + { + LogFlowThisFunc(("Session ID=%RU32 not started (anymore), status now is: %RU32\n", + mData.mSession.mID, mData.mStatus)); + return VINF_SUCCESS; } - return VERR_NOT_FOUND; + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); + + vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */, + eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n", + mData.mSession.mID, uFlags)); + + VBOXHGCMSVCPARM paParms[4]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(uFlags); + + alock.release(); /* Drop the write lock before waiting. */ + + vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms); + if (RT_SUCCESS(vrc)) + vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS, + NULL /* Session status */, pGuestRc); + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; } -int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc) +int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, + uint32_t uFlags, int *pGuestRc) { LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n", strPath.c_str(), uMode, uFlags)); + int vrc = VINF_SUCCESS; + GuestProcessStartupInfo procInfo; procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR); procInfo.mFlags = ProcessCreateFlag_Hidden; - int vrc = VINF_SUCCESS; - - /* Construct arguments. */ - if (uFlags & DirectoryCreateFlag_Parents) - procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */ - if (uMode) + try { - procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */ - - char szMode[16]; - if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode)) + /* Construct arguments. */ + if (uFlags) { - procInfo.mArguments.push_back(Utf8Str(szMode)); + if (uFlags & DirectoryCreateFlag_Parents) + procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */ + else + vrc = VERR_INVALID_PARAMETER; } - else - vrc = VERR_BUFFER_OVERFLOW; - } - procInfo.mArguments.push_back(strPath); /* The directory we want to create. */ - int guestRc; - if (RT_SUCCESS(vrc)) - { - GuestProcessTool procTool; - vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); - if (RT_SUCCESS(vrc)) + if (uMode) { - if (RT_SUCCESS(guestRc)) - vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); - } + procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */ - if (RT_SUCCESS(vrc)) - { - if (RT_SUCCESS(guestRc)) - guestRc = procTool.TerminatedOk(NULL /* Exit code */); + char szMode[16]; + if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode)) + { + procInfo.mArguments.push_back(Utf8Str(szMode)); + } + else + vrc = VERR_BUFFER_OVERFLOW; } - - if (pGuestRc) - *pGuestRc = guestRc; + procInfo.mArguments.push_back(strPath); /* The directory we want to create. */ } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_SUCCESS(vrc)) + vrc = GuestProcessTool::Run(this, procInfo, pGuestRc); LogFlowFuncLeaveRC(vrc); - if (RT_FAILURE(vrc)) - return vrc; - return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ + return vrc; +} + +inline bool GuestSession::directoryExists(uint32_t uDirID, ComObjPtr *pDir) +{ + SessionDirectories::const_iterator it = mData.mDirectories.find(uDirID); + if (it != mData.mDirectories.end()) + { + if (pDir) + *pDir = it->second; + return true; + } + return false; } int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) @@ -505,81 +785,366 @@ int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjD return vrc; } -int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, - bool fDirectory, const Utf8Str &strName, int *pGuestRc) +int GuestSession::directoryRemoveFromList(GuestDirectory *pDirectory) { - GuestProcessStartupInfo procInfo; - procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP); - procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; - procInfo.mArguments.push_back(Utf8Str("--machinereadable")); - if (fDirectory) - procInfo.mArguments.push_back(Utf8Str("-d")); - if (strPath.length()) /* Otherwise use /tmp or equivalent. */ - { - procInfo.mArguments.push_back(Utf8Str("-t")); - procInfo.mArguments.push_back(strPath); - } - procInfo.mArguments.push_back(strTemplate); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - GuestProcessTool procTool; int guestRc; - int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); - if (RT_SUCCESS(vrc)) - { - if (RT_SUCCESS(guestRc)) - vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); - } + int rc = VERR_NOT_FOUND; - if (RT_SUCCESS(vrc)) + SessionDirectories::iterator itDirs = mData.mDirectories.begin(); + while (itDirs != mData.mDirectories.end()) { - if (RT_SUCCESS(guestRc)) - guestRc = procTool.TerminatedOk(NULL /* Exit code */); - } + if (pDirectory == itDirs->second) + { + /* Make sure to consume the pointer before the one of the + * iterator gets released. */ + ComObjPtr pDir = pDirectory; - if (pGuestRc) - *pGuestRc = guestRc; + Bstr strName; + HRESULT hr = itDirs->second->COMGETTER(DirectoryName)(strName.asOutParam()); + ComAssertComRC(hr); - if (RT_FAILURE(vrc)) - return vrc; - return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ -} + Assert(mData.mDirectories.size()); + Assert(mData.mNumObjects); + LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %zu processes, %RU32 objects)\n", + Utf8Str(strName).c_str(), mData.mSession.mID, mData.mDirectories.size() - 1, mData.mNumObjects - 1)); -int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter, - uint32_t uFlags, ComObjPtr &pDirectory) -{ + rc = pDirectory->onRemove(); + mData.mDirectories.erase(itDirs); + mData.mNumObjects--; + + pDir.setNull(); + break; + } + + itDirs++; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestSession::directoryRemoveInternal(const Utf8Str &strPath, uint32_t uFlags, + int *pGuestRc) +{ + AssertReturn(!(uFlags & ~DIRREMOVE_FLAG_VALID_MASK), VERR_INVALID_PARAMETER); + + LogFlowThisFunc(("strPath=%s, uFlags=0x%x\n", strPath.c_str(), uFlags)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + GuestWaitEvent *pEvent = NULL; + int vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */, + &pEvent); + if (RT_FAILURE(vrc)) + return vrc; + + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[8]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setPointer((void*)strPath.c_str(), + (ULONG)strPath.length() + 1); + paParms[i++].setUInt32(uFlags); + + alock.release(); /* Drop write lock before sending. */ + + vrc = sendCommand(HOST_DIR_REMOVE, i, paParms); + if (RT_SUCCESS(vrc)) + { + vrc = pEvent->Wait(30 * 1000); + if ( vrc == VERR_GSTCTL_GUEST_ERROR + && pGuestRc) + *pGuestRc = pEvent->GuestResult(); + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, + bool fDirectory, Utf8Str &strName, int *pGuestRc) +{ + LogFlowThisFunc(("strTemplate=%s, strPath=%s, fDirectory=%RTbool\n", + strTemplate.c_str(), strPath.c_str(), fDirectory)); + + int vrc = VINF_SUCCESS; + + GuestProcessStartupInfo procInfo; + procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP); + procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; + + try + { + procInfo.mArguments.push_back(Utf8Str("--machinereadable")); + if (fDirectory) + procInfo.mArguments.push_back(Utf8Str("-d")); + if (strPath.length()) /* Otherwise use /tmp or equivalent. */ + { + procInfo.mArguments.push_back(Utf8Str("-t")); + procInfo.mArguments.push_back(strPath); + } + procInfo.mArguments.push_back(strTemplate); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + /** @todo Use an internal HGCM command for this operation, since + * we now can run in a user-dedicated session. */ + int guestRc; GuestCtrlStreamObjects stdOut; + if (RT_SUCCESS(vrc)) + vrc = GuestProcessTool::RunEx(this, procInfo, + &stdOut, 1 /* cStrmOutObjects */, + &guestRc); + if ( RT_SUCCESS(vrc) + && RT_SUCCESS(guestRc)) + { + GuestFsObjData objData; + if (!stdOut.empty()) + { + vrc = objData.FromMkTemp(stdOut.at(0)); + if (RT_FAILURE(vrc)) + { + guestRc = vrc; + vrc = VERR_GSTCTL_GUEST_ERROR; + } + } + else + vrc = VERR_NO_DATA; + + if (RT_SUCCESS(vrc)) + strName = objData.mName; + } + + if (pGuestRc) + *pGuestRc = guestRc; + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::directoryOpenInternal(const GuestDirectoryOpenInfo &openInfo, + ComObjPtr &pDirectory, int *pGuestRc) +{ LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n", - strPath.c_str(), strFilter.c_str(), uFlags)); + openInfo.mPath.c_str(), openInfo.mFilter.c_str(), openInfo.mFlags)); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + int rc = VERR_MAX_PROCS_REACHED; + if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS) + return rc; + + /* Create a new (host-based) directory ID and assign it. */ + uint32_t uNewDirID = 0; + ULONG uTries = 0; + + for (;;) + { + /* Is the directory ID already used? */ + if (!directoryExists(uNewDirID, NULL /* pDirectory */)) + { + /* Callback with context ID was not found. This means + * we can use this context ID for our new callback we want + * to add below. */ + rc = VINF_SUCCESS; + break; + } + uNewDirID++; + if (uNewDirID == VBOX_GUESTCTRL_MAX_OBJECTS) + uNewDirID = 0; + + if (++uTries == UINT32_MAX) + break; /* Don't try too hard. */ + } + + if (RT_FAILURE(rc)) + return rc; + /* Create the directory object. */ HRESULT hr = pDirectory.createObject(); if (FAILED(hr)) return VERR_COM_UNEXPECTED; - int vrc = pDirectory->init(this /* Parent */, - strPath, strFilter, uFlags); + Console *pConsole = mParent->getConsole(); + AssertPtr(pConsole); + + int vrc = pDirectory->init(pConsole, this /* Parent */, + uNewDirID, openInfo); if (RT_FAILURE(vrc)) return vrc; - /* Add the created directory to our vector. */ - mData.mDirectories.push_back(pDirectory); + /* + * Since this is a synchronous guest call we have to + * register the file object first, releasing the session's + * lock and then proceed with the actual opening command + * -- otherwise the file's opening callback would hang + * because the session's lock still is in place. + */ + try + { + /* Add the created directory to our map. */ + mData.mDirectories[uNewDirID] = pDirectory; + mData.mNumObjects++; + Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); + + LogFlowFunc(("Added new guest directory \"%s\" (Session: %RU32) (now total %zu dirs, %RU32 objects)\n", + openInfo.mPath.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects)); + + alock.release(); /* Release lock before firing off event. */ + + /** @todo Fire off a VBoxEventType_OnGuestDirectoryRegistered event? */ + } + catch (std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } - LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n", - strPath.c_str(), mData.mId)); + if (RT_SUCCESS(rc)) + { + /* Nothing further to do here yet. */ + if (pGuestRc) + *pGuestRc = VINF_SUCCESS; + } LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData) +int GuestSession::dispatchToDirectory(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) { - LogFlowFuncEnter(); + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + if (pSvcCb->mParms < 3) + return VERR_INVALID_PARAMETER; AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID); + uint32_t uDirID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID); #ifdef DEBUG - LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n", + LogFlowFunc(("uDirID=%RU32 (%zu total)\n", + uDirID, mData.mFiles.size())); +#endif + int rc; + SessionDirectories::const_iterator itDir + = mData.mDirectories.find(uDirID); + if (itDir != mData.mDirectories.end()) + { + ComObjPtr pDirectory(itDir->second); + Assert(!pDirectory.isNull()); + + alock.release(); + + rc = pDirectory->callbackDispatcher(pCtxCb, pSvcCb); + } + else + rc = VERR_NOT_FOUND; + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestSession::dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + uint32_t uFileID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID); +#ifdef DEBUG + LogFlowFunc(("uFileID=%RU32 (%zu total)\n", + uFileID, mData.mFiles.size())); +#endif + int rc; + SessionFiles::const_iterator itFile + = mData.mFiles.find(uFileID); + if (itFile != mData.mFiles.end()) + { + ComObjPtr pFile(itFile->second); + Assert(!pFile.isNull()); + + alock.release(); + + rc = pFile->callbackDispatcher(pCtxCb, pSvcCb); + } + else + rc = VERR_NOT_FOUND; + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestSession::dispatchToObject(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + int rc; + uint32_t uObjectID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* Since we don't know which type the object is, we need to through all + * all objects. */ + /** @todo Speed this up by adding an object type to the callback context! */ + SessionProcesses::const_iterator itProc = mData.mProcesses.find(uObjectID); + if (itProc == mData.mProcesses.end()) + { + SessionFiles::const_iterator itFile = mData.mFiles.find(uObjectID); + if (itFile != mData.mFiles.end()) + { + alock.release(); + + rc = dispatchToFile(pCtxCb, pSvcCb); + } + else + { + SessionDirectories::const_iterator itDir = mData.mDirectories.find(uObjectID); + if (itDir != mData.mDirectories.end()) + { + alock.release(); + + rc = dispatchToDirectory(pCtxCb, pSvcCb); + } + else + rc = VERR_NOT_FOUND; + } + } + else + { + alock.release(); + + rc = dispatchToProcess(pCtxCb, pSvcCb); + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestSession::dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID); +#ifdef DEBUG + LogFlowFunc(("uProcessID=%RU32 (%zu total)\n", uProcessID, mData.mProcesses.size())); #endif int rc; @@ -587,11 +1152,21 @@ int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, voi = mData.mProcesses.find(uProcessID); if (itProc != mData.mProcesses.end()) { +#ifdef DEBUG_andy + ULONG cRefs = itProc->second->AddRef(); + Assert(cRefs >= 2); + LogFlowFunc(("pProcess=%p, cRefs=%RU32\n", &itProc->second, cRefs - 1)); + itProc->second->Release(); +#endif ComObjPtr pProcess(itProc->second); Assert(!pProcess.isNull()); + /* Set protocol version so that pSvcCb can + * be interpreted right. */ + pCtxCb->uProtocol = mData.mProtocolVersion; + alock.release(); - rc = pProcess->callbackDispatcher(uContextID, uFunction, pvData, cbData); + rc = pProcess->callbackDispatcher(pCtxCb, pSvcCb); } else rc = VERR_NOT_FOUND; @@ -600,178 +1175,671 @@ int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, voi return rc; } +int GuestSession::dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + +#ifdef DEBUG + LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n", + mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); +#endif + + int rc; + switch (pCbCtx->uFunction) + { + case GUEST_DISCONNECTED: + /** @todo Handle closing all guest objects. */ + rc = VERR_INTERNAL_ERROR; + break; + + case GUEST_SESSION_NOTIFY: /* Guest Additions >= 4.3.0. */ + { + rc = onSessionStatusChange(pCbCtx, pSvcCb); + break; + } + + default: + /* Silently skip unknown callbacks. */ + rc = VERR_NOT_SUPPORTED; + break; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +inline bool GuestSession::fileExists(uint32_t uFileID, ComObjPtr *pFile) +{ + SessionFiles::const_iterator it = mData.mFiles.find(uFileID); + if (it != mData.mFiles.end()) + { + if (pFile) + *pFile = it->second; + return true; + } + return false; +} + int GuestSession::fileRemoveFromList(GuestFile *pFile) { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - for (SessionFiles::iterator itFiles = mData.mFiles.begin(); - itFiles != mData.mFiles.end(); ++itFiles) + int rc = VERR_NOT_FOUND; + + SessionFiles::iterator itFiles = mData.mFiles.begin(); + while (itFiles != mData.mFiles.end()) { - if (pFile == (*itFiles)) + if (pFile == itFiles->second) { + /* Make sure to consume the pointer before the one of thfe + * iterator gets released. */ + ComObjPtr pCurFile = pFile; + Bstr strName; - HRESULT hr = (*itFiles)->COMGETTER(FileName)(strName.asOutParam()); + HRESULT hr = pCurFile->COMGETTER(FileName)(strName.asOutParam()); ComAssertComRC(hr); Assert(mData.mNumObjects); - LogFlowThisFunc(("Removing file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n", - Utf8Str(strName).c_str(), mData.mId, mData.mFiles.size() - 1, mData.mNumObjects - 1)); -#ifdef DEBUG - ULONG cRefs = pFile->AddRef(); - LogFlowThisFunc(("pObject=%p, cRefs=%RU32\n", pFile, cRefs)); - pFile->Release(); -#endif + LogFlowThisFunc(("Removing guest file \"%s\" (Session: %RU32) (now total %zu files, %RU32 objects)\n", + Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1)); + + rc = pFile->onRemove(); mData.mFiles.erase(itFiles); mData.mNumObjects--; - return VINF_SUCCESS; + + alock.release(); /* Release lock before firing off event. */ + + fireGuestFileRegisteredEvent(mEventSource, this, pCurFile, + false /* Unregistered */); + pCurFile.setNull(); + break; } + + itFiles++; } - return VERR_NOT_FOUND; + LogFlowFuncLeaveRC(rc); + return rc; } int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc) { + LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); + + int vrc = VINF_SUCCESS; + GuestProcessStartupInfo procInfo; GuestProcessStream streamOut; procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM); procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; - procInfo.mArguments.push_back(Utf8Str("--machinereadable")); - procInfo.mArguments.push_back(strPath); /* The file we want to remove. */ - - GuestProcessTool procTool; int guestRc; - int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); - if (RT_SUCCESS(vrc)) - vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); - if (RT_SUCCESS(vrc)) + try + { + procInfo.mArguments.push_back(Utf8Str("--machinereadable")); + procInfo.mArguments.push_back(strPath); /* The file we want to remove. */ + } + catch (std::bad_alloc) { - if (RT_SUCCESS(guestRc)) - guestRc = procTool.TerminatedOk(NULL /* Exit code */); + vrc = VERR_NO_MEMORY; } - if (pGuestRc) - *pGuestRc = guestRc; + if (RT_SUCCESS(vrc)) + vrc = GuestProcessTool::Run(this, procInfo, pGuestRc); - if (RT_FAILURE(vrc)) - return vrc; - return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ + LogFlowFuncLeaveRC(vrc); + return vrc; } -int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, - uint32_t uCreationMode, int64_t iOffset, ComObjPtr &pFile, int *pGuestRc) +int GuestSession::fileOpenInternal(const GuestFileOpenInfo &openInfo, + ComObjPtr &pFile, int *pGuestRc) { - LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n", - strPath.c_str(), strOpenMode.c_str(), strDisposition.c_str(), uCreationMode, iOffset)); + LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, uOffset=%RU64\n", + openInfo.mFileName.c_str(), openInfo.mOpenMode.c_str(), openInfo.mDisposition.c_str(), + openInfo.mCreationMode, openInfo.mInitialOffset)); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* Guest Additions < 4.3 don't support handling + guest files, skip. */ + if (mData.mProtocolVersion < 2) + { + LogFlowThisFunc(("Installed Guest Additions don't support handling guest files, skipping\n")); + return VERR_NOT_SUPPORTED; + } + + int rc = VERR_MAX_PROCS_REACHED; + if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS) + return rc; + + /* Create a new (host-based) file ID and assign it. */ + uint32_t uNewFileID = 0; + ULONG uTries = 0; + + for (;;) + { + /* Is the file ID already used? */ + if (!fileExists(uNewFileID, NULL /* pFile */)) + { + /* Callback with context ID was not found. This means + * we can use this context ID for our new callback we want + * to add below. */ + rc = VINF_SUCCESS; + break; + } + uNewFileID++; + if (uNewFileID == VBOX_GUESTCTRL_MAX_OBJECTS) + uNewFileID = 0; + + if (++uTries == UINT32_MAX) + break; /* Don't try too hard. */ + } + + if (RT_FAILURE(rc)) + return rc; /* Create the directory object. */ HRESULT hr = pFile.createObject(); if (FAILED(hr)) return VERR_COM_UNEXPECTED; - int vrc = pFile->init(this /* Parent */, - strPath, strOpenMode, strDisposition, uCreationMode, iOffset, pGuestRc); + Console *pConsole = mParent->getConsole(); + AssertPtr(pConsole); + + rc = pFile->init(pConsole, this /* GuestSession */, + uNewFileID, openInfo); + if (RT_FAILURE(rc)) + return rc; + + /* + * Since this is a synchronous guest call we have to + * register the file object first, releasing the session's + * lock and then proceed with the actual opening command + * -- otherwise the file's opening callback would hang + * because the session's lock still is in place. + */ + try + { + /* Add the created file to our vector. */ + mData.mFiles[uNewFileID] = pFile; + mData.mNumObjects++; + Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); + + LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %zu files, %RU32 objects)\n", + openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects)); + + alock.release(); /* Release lock before firing off event. */ + + fireGuestFileRegisteredEvent(mEventSource, this, pFile, + true /* Registered */); + } + catch (std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } + + if (RT_SUCCESS(rc)) + { + int guestRc; + rc = pFile->openFile(30 * 1000 /* 30s timeout */, &guestRc); + if ( rc == VERR_GSTCTL_GUEST_ERROR + && pGuestRc) + { + *pGuestRc = guestRc; + } + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) +{ + LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); + + int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc); + if (RT_SUCCESS(vrc)) + { + vrc = objData.mType == FsObjType_File + ? VINF_SUCCESS : VERR_NOT_A_FILE; + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc) +{ + AssertPtrReturn(pllSize, VERR_INVALID_POINTER); + + GuestFsObjData objData; + int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc); + if (RT_SUCCESS(vrc)) + *pllSize = objData.mObjectSize; + + return vrc; +} + +int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) +{ + LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); + + int vrc = VINF_SUCCESS; + + /** @todo Merge this with IGuestFile::queryInfo(). */ + GuestProcessStartupInfo procInfo; + procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT); + procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; + + try + { + /* Construct arguments. */ + procInfo.mArguments.push_back(Utf8Str("--machinereadable")); + procInfo.mArguments.push_back(strPath); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + int guestRc; GuestCtrlStreamObjects stdOut; + if (RT_SUCCESS(vrc)) + vrc = GuestProcessTool::RunEx(this, procInfo, + &stdOut, 1 /* cStrmOutObjects */, + &guestRc); + if ( RT_SUCCESS(vrc) + && RT_SUCCESS(guestRc)) + { + if (!stdOut.empty()) + vrc = objData.FromStat(stdOut.at(0)); + else + vrc = VERR_NO_DATA; + } + + if ( vrc == VERR_GSTCTL_GUEST_ERROR + && pGuestRc) + *pGuestRc = guestRc; + + LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n", + vrc, guestRc)); + return vrc; +} + +const GuestCredentials& GuestSession::getCredentials(void) +{ + return mData.mCredentials; +} + +const GuestEnvironment& GuestSession::getEnvironment(void) +{ + return mData.mEnvironment; +} + +Utf8Str GuestSession::getName(void) +{ + return mData.mSession.mName; +} + +/* static */ +Utf8Str GuestSession::guestErrorToString(int guestRc) +{ + Utf8Str strError; + + /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ + switch (guestRc) + { + case VERR_INVALID_VM_HANDLE: + strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)")); + break; + + case VERR_HGCM_SERVICE_NOT_FOUND: + strError += Utf8StrFmt(tr("The guest execution service is not available")); + break; + + case VERR_AUTHENTICATION_FAILURE: + strError += Utf8StrFmt(tr("The specified user was not able to logon on guest")); + break; + + case VERR_TIMEOUT: + strError += Utf8StrFmt(tr("The guest did not respond within time")); + break; + + case VERR_CANCELLED: + strError += Utf8StrFmt(tr("The session operation was canceled")); + break; + + case VERR_PERMISSION_DENIED: + strError += Utf8StrFmt(tr("Invalid user/password credentials")); + break; + + case VERR_MAX_PROCS_REACHED: + strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); + break; + + case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */ + strError += Utf8StrFmt(tr("Unable to retrieve requested information")); + break; + + case VERR_NOT_FOUND: + strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)")); + break; + + default: + strError += Utf8StrFmt("%Rrc", guestRc); + break; + } + + return strError; +} + +/** + * Checks if this session is ready state where it can handle + * all session-bound actions (like guest processes, guest files). + * Only used by official API methods. Will set an external + * error when not ready. + */ +HRESULT GuestSession::isReadyExternal(void) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + /** @todo Be a bit more informative. */ + if (mData.mStatus != GuestSessionStatus_Started) + return setError(E_UNEXPECTED, tr("Session is not in started state")); + + return S_OK; +} + +/** + * Called by IGuest right before this session gets removed from + * the public session list. + */ +int GuestSession::onRemove(void) +{ + LogFlowThisFuncEnter(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + int vrc = VINF_SUCCESS; + + /* + * Note: The event source stuff holds references to this object, + * so make sure that this is cleaned up *before* calling uninit. + */ + if (!mEventSource.isNull()) + { + mEventSource->UnregisterListener(mLocalListener); + + mLocalListener.setNull(); + unconst(mEventSource).setNull(); + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/** No locking! */ +int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + /* pCallback is optional. */ + AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); + + if (pSvcCbData->mParms < 3) + return VERR_INVALID_PARAMETER; + + CALLBACKDATA_SESSION_NOTIFY dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uType); + AssertRCReturn(vrc, vrc); + vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult); + AssertRCReturn(vrc, vrc); + + LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n", + mData.mSession.mID, dataCb.uType, dataCb.uResult)); + + GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined; + + int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */ + switch (dataCb.uType) + { + case GUEST_SESSION_NOTIFYTYPE_ERROR: + sessionStatus = GuestSessionStatus_Error; + break; + + case GUEST_SESSION_NOTIFYTYPE_STARTED: + sessionStatus = GuestSessionStatus_Started; + break; + + case GUEST_SESSION_NOTIFYTYPE_TEN: + case GUEST_SESSION_NOTIFYTYPE_TES: + case GUEST_SESSION_NOTIFYTYPE_TEA: + sessionStatus = GuestSessionStatus_Terminated; + break; + + case GUEST_SESSION_NOTIFYTYPE_TOK: + sessionStatus = GuestSessionStatus_TimedOutKilled; + break; + + case GUEST_SESSION_NOTIFYTYPE_TOA: + sessionStatus = GuestSessionStatus_TimedOutAbnormally; + break; + + case GUEST_SESSION_NOTIFYTYPE_DWN: + sessionStatus = GuestSessionStatus_Down; + break; + + case GUEST_SESSION_NOTIFYTYPE_UNDEFINED: + default: + vrc = VERR_NOT_SUPPORTED; + break; + } + + if (RT_SUCCESS(vrc)) + { + if (RT_FAILURE(guestRc)) + sessionStatus = GuestSessionStatus_Error; + } + + /* Set the session status. */ + if (RT_SUCCESS(vrc)) + vrc = setSessionStatus(sessionStatus, guestRc); + + LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc)); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::startSessionInternal(int *pGuestRc) +{ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n", + mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion, + mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS)); + + /* Guest Additions < 4.3 don't support opening dedicated + guest sessions. Simply return success here. */ + if (mData.mProtocolVersion < 2) + { + mData.mStatus = GuestSessionStatus_Started; + + LogFlowThisFunc(("Installed Guest Additions don't support opening dedicated sessions, skipping\n")); + return VINF_SUCCESS; + } + + if (mData.mStatus != GuestSessionStatus_Undefined) + return VINF_SUCCESS; + + /** @todo mData.mSession.uFlags validation. */ + + /* Set current session status. */ + mData.mStatus = GuestSessionStatus_Starting; + mData.mRC = VINF_SUCCESS; /* Clear previous error, if any. */ + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); + + vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */, + eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + if (RT_FAILURE(vrc)) return vrc; - /** @todo Handle guestRc. */ - /* Add the created directory to our vector. */ - mData.mFiles.push_back(pFile); - mData.mNumObjects++; - Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); + VBOXHGCMSVCPARM paParms[8]; + + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setUInt32(mData.mProtocolVersion); + paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(), + (ULONG)mData.mCredentials.mUser.length() + 1); + paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(), + (ULONG)mData.mCredentials.mPassword.length() + 1); + paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(), + (ULONG)mData.mCredentials.mDomain.length() + 1); + paParms[i++].setUInt32(mData.mSession.mOpenFlags); + + alock.release(); /* Drop write lock before sending. */ + + vrc = sendCommand(HOST_SESSION_CREATE, i, paParms); + if (RT_SUCCESS(vrc)) + { + vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start, + 30 * 1000 /* 30s timeout */, + NULL /* Session status */, pGuestRc); + } + else + { + /* + * Unable to start guest session - update its current state. + * Since there is no (official API) way to recover a failed guest session + * this also marks the end state. Internally just calling this + * same function again will work though. + */ + mData.mStatus = GuestSessionStatus_Error; + mData.mRC = vrc; + } - LogFlowFunc(("Added new file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n", - strPath.c_str(), mData.mId, mData.mProcesses.size(), mData.mNumObjects)); + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::startSessionAsync(void) +{ + LogFlowThisFuncEnter(); + + int vrc; + + try + { + /* Asynchronously open the session on the guest by kicking off a + * worker thread. */ + std::auto_ptr pTask(new GuestSessionTaskInternalOpen(this)); + AssertReturn(pTask->isOk(), pTask->rc()); + + vrc = RTThreadCreate(NULL, GuestSession::startSessionThread, + (void *)pTask.get(), 0, + RTTHREADTYPE_MAIN_WORKER, 0, + "gctlSesStart"); + if (RT_SUCCESS(vrc)) + { + /* pTask is now owned by openSessionThread(), so release it. */ + pTask.release(); + } + } + catch(std::bad_alloc &) + { + vrc = VERR_NO_MEMORY; + } LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) +/* static */ +DECLCALLBACK(int) GuestSession::startSessionThread(RTTHREAD Thread, void *pvUser) { - LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); + LogFlowFunc(("pvUser=%p\n", pvUser)); - int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc); - if (RT_SUCCESS(vrc)) - { - vrc = objData.mType == FsObjType_File - ? VINF_SUCCESS : VERR_NOT_A_FILE; - } + std::auto_ptr pTask(static_cast(pvUser)); + AssertPtr(pTask.get()); + + const ComObjPtr pSession(pTask->Session()); + Assert(!pSession.isNull()); + + AutoCaller autoCaller(pSession); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + int vrc = pSession->startSessionInternal(NULL /* Guest rc, ignored */); + /* Nothing to do here anymore. */ LogFlowFuncLeaveRC(vrc); return vrc; } -int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc) +int GuestSession::pathRenameInternal(const Utf8Str &strSource, const Utf8Str &strDest, + uint32_t uFlags, int *pGuestRc) { - AssertPtrReturn(pllSize, VERR_INVALID_POINTER); + AssertReturn(!(uFlags & ~PATHRENAME_FLAG_VALID_MASK), VERR_INVALID_PARAMETER); - GuestFsObjData objData; - int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc); - if (RT_SUCCESS(vrc)) - *pllSize = objData.mObjectSize; + LogFlowThisFunc(("strSource=%s, strDest=%s, uFlags=0x%x\n", + strSource.c_str(), strDest.c_str(), uFlags)); - return vrc; -} + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); -int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) -{ - LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); + GuestWaitEvent *pEvent = NULL; + int vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */, + &pEvent); + if (RT_FAILURE(vrc)) + return vrc; - /** @todo Merge this with IGuestFile::queryInfo(). */ - GuestProcessStartupInfo procInfo; - procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT); - procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; + /* Prepare HGCM call. */ + VBOXHGCMSVCPARM paParms[8]; + int i = 0; + paParms[i++].setUInt32(pEvent->ContextID()); + paParms[i++].setPointer((void*)strSource.c_str(), + (ULONG)strSource.length() + 1); + paParms[i++].setPointer((void*)strDest.c_str(), + (ULONG)strDest.length() + 1); + paParms[i++].setUInt32(uFlags); - /* Construct arguments. */ - procInfo.mArguments.push_back(Utf8Str("--machinereadable")); - procInfo.mArguments.push_back(strPath); + alock.release(); /* Drop write lock before sending. */ - GuestProcessTool procTool; int guestRc; - int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); - if (RT_SUCCESS(vrc)) - vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); + vrc = sendCommand(HOST_PATH_RENAME, i, paParms); if (RT_SUCCESS(vrc)) { - guestRc = procTool.TerminatedOk(NULL /* Exit code */); - if (RT_SUCCESS(guestRc)) - { - GuestProcessStreamBlock curBlock; - vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, curBlock); - /** @todo Check for more / validate blocks! */ - if (RT_SUCCESS(vrc)) - vrc = objData.FromStat(curBlock); - } + vrc = pEvent->Wait(30 * 1000); + if ( vrc == VERR_GSTCTL_GUEST_ERROR + && pGuestRc) + *pGuestRc = pEvent->GuestResult(); } - if (pGuestRc) - *pGuestRc = guestRc; + unregisterWaitEvent(pEvent); LogFlowFuncLeaveRC(vrc); - if (RT_FAILURE(vrc)) - return vrc; - return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ -} - -const GuestCredentials& GuestSession::getCredentials(void) -{ - return mData.mCredentials; -} - -const GuestEnvironment& GuestSession::getEnvironment(void) -{ - return mData.mEnvironment; -} - -Utf8Str GuestSession::getName(void) -{ - return mData.mName; + return vrc; } int GuestSession::processRemoveFromList(GuestProcess *pProcess) { - LogFlowThisFuncEnter(); + AssertPtrReturn(pProcess, VERR_INVALID_POINTER); + + LogFlowThisFunc(("pProcess=%p\n", pProcess)); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -779,30 +1847,46 @@ int GuestSession::processRemoveFromList(GuestProcess *pProcess) ULONG uPID; HRESULT hr = pProcess->COMGETTER(PID)(&uPID); + ComAssertComRC(hr); - LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID)); + LogFlowFunc(("Removing process (PID=%RU32) ...\n", uPID)); - for (SessionProcesses::iterator itProcs = mData.mProcesses.begin(); - itProcs != mData.mProcesses.end(); ++itProcs) + SessionProcesses::iterator itProcs = mData.mProcesses.begin(); + while (itProcs != mData.mProcesses.end()) { if (pProcess == itProcs->second) { - GuestProcess *pCurProc = itProcs->second; - AssertPtr(pCurProc); +#ifdef DEBUG_andy + ULONG cRefs = pProcess->AddRef(); + Assert(cRefs >= 2); + LogFlowFunc(("pProcess=%p, cRefs=%RU32\n", pProcess, cRefs - 1)); + pProcess->Release(); +#endif + /* Make sure to consume the pointer before the one of the + * iterator gets released. */ + ComObjPtr pProc = pProcess; - hr = pCurProc->COMGETTER(PID)(&uPID); + hr = pProc->COMGETTER(PID)(&uPID); ComAssertComRC(hr); + Assert(mData.mProcesses.size()); Assert(mData.mNumObjects); - LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n", - mData.mId, pCurProc->getProcessID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); + LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %zu processes, %RU32 objects)\n", + pProcess->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); + rc = pProcess->onRemove(); mData.mProcesses.erase(itProcs); mData.mNumObjects--; - rc = VINF_SUCCESS; + alock.release(); /* Release lock before firing off event. */ + + fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProc, + uPID, false /* Process unregistered */); + pProc.setNull(); break; } + + itProcs++; } LogFlowFuncLeaveRC(rc); @@ -849,6 +1933,15 @@ int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComO } } + if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) + && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut) + || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr) + ) + ) + { + return VERR_INVALID_PARAMETER; + } + /* Adjust timeout. If set to 0, we define * an infinite timeout. */ if (procInfo.mTimeoutMS == 0) @@ -869,7 +1962,7 @@ int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComO for (;;) { /* Is the context ID already used? */ - if (!processExists(uNewProcessID, NULL /* pProgress */)) + if (!processExists(uNewProcessID, NULL /* pProcess */)) { /* Callback with context ID was not found. This means * we can use this context ID for our new callback we want @@ -881,7 +1974,7 @@ int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComO if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS) uNewProcessID = 0; - if (++uTries == UINT32_MAX) + if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS) break; /* Don't try too hard. */ } @@ -893,18 +1986,30 @@ int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComO if (FAILED(hr)) return VERR_COM_UNEXPECTED; - rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */, + rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */, uNewProcessID, procInfo); if (RT_FAILURE(rc)) return rc; /* Add the created process to our map. */ - mData.mProcesses[uNewProcessID] = pProcess; - mData.mNumObjects++; - Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); + try + { + mData.mProcesses[uNewProcessID] = pProcess; + mData.mNumObjects++; + Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); + + LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %zu processes, %RU32 objects)\n", + mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects)); - LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n", - mData.mId, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects)); + alock.release(); /* Release lock before firing off event. */ + + fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess, + 0 /* PID */, true /* Process registered */); + } + catch (std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } return rc; } @@ -946,75 +2051,380 @@ inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr *pP } } - return VERR_NOT_FOUND; + return VERR_NOT_FOUND; +} + +int GuestSession::sendCommand(uint32_t uFunction, + uint32_t uParms, PVBOXHGCMSVCPARM paParms) +{ + LogFlowThisFuncEnter(); + +#ifndef VBOX_GUESTCTRL_TEST_CASE + ComObjPtr pConsole = mParent->getConsole(); + Assert(!pConsole.isNull()); + + /* Forward the information to the VMM device. */ + VMMDev *pVMMDev = pConsole->getVMMDev(); + AssertPtr(pVMMDev); + + LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); + int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms); + if (RT_FAILURE(vrc)) + { + /** @todo What to do here? */ + } +#else + /* Not needed within testcases. */ + int vrc = VINF_SUCCESS; +#endif + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/* static */ +HRESULT GuestSession::setErrorExternal(VirtualBoxBase *pInterface, int guestRc) +{ + AssertPtr(pInterface); + AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n")); + + return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str()); +} + +/* Does not do locking; caller is responsible for that! */ +int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc) +{ + LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, sessionRc=%Rrc\n", + mData.mStatus, sessionStatus, sessionRc)); + + if (sessionStatus == GuestSessionStatus_Error) + { + AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc)); + /* Do not allow overwriting an already set error. If this happens + * this means we forgot some error checking/locking somewhere. */ + AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); + } + else + AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc)); + + if (mData.mStatus != sessionStatus) + { + mData.mStatus = sessionStatus; + mData.mRC = sessionRc; + + ComObjPtr errorInfo; + HRESULT hr = errorInfo.createObject(); + ComAssertComRC(hr); + int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, sessionRc, + COM_IIDOF(IGuestSession), getComponentName(), + guestErrorToString(sessionRc)); + AssertRC(rc2); + + fireGuestSessionStateChangedEvent(mEventSource, this, + mData.mSession.mID, sessionStatus, errorInfo); + } + + return VINF_SUCCESS; +} + +int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */) +{ + /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n", + enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/ + + /* Note: No write locking here -- already done in the caller. */ + + int vrc = VINF_SUCCESS; + /*if (mData.mWaitEvent) + vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/ + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc, + GuestSessionTask *pTask, ComObjPtr &pProgress) +{ + LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask)); + + AssertPtrReturn(pTask, VERR_INVALID_POINTER); + + /* Create the progress object. */ + HRESULT hr = pProgress.createObject(); + if (FAILED(hr)) + return VERR_COM_UNEXPECTED; + + hr = pProgress->init(static_cast(this), + Bstr(strTaskDesc).raw(), + TRUE /* aCancelable */); + if (FAILED(hr)) + return VERR_COM_UNEXPECTED; + + /* Initialize our worker task. */ + std::auto_ptr task(pTask); + + int rc = task->RunAsync(strTaskDesc, pProgress); + if (RT_FAILURE(rc)) + return rc; + + /* Don't destruct on success. */ + task.release(); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +/** + * Queries/collects information prior to establishing a guest session. + * This is necessary to know which guest control protocol version to use, + * among other things (later). + * + * @return IPRT status code. + */ +int GuestSession::queryInfo(void) +{ + /* + * Try querying the guest control protocol version running on the guest. + * This is done using the Guest Additions version + */ + ComObjPtr pGuest = mParent; + Assert(!pGuest.isNull()); + + uint32_t uVerAdditions = pGuest->getAdditionsVersion(); + uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions); + uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions); + +#ifdef DEBUG_andy + /* Hardcode the to-used protocol version; nice for testing side effects. */ + mData.mProtocolVersion = 2; +#else + mData.mProtocolVersion = ( + /* VBox 5.0 and up. */ + uVBoxMajor >= 5 + /* VBox 4.3 and up. */ + || (uVBoxMajor == 4 && uVBoxMinor >= 3)) + ? 2 /* Guest control 2.0. */ + : 1; /* Legacy guest control (VBox < 4.3). */ + /* Build revision is ignored. */ +#endif + + LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32), mProtocolVersion=%RU32\n", + uVerAdditions, uVBoxMajor, uVBoxMinor, mData.mProtocolVersion)); + + /* Tell the user but don't bitch too often. */ + static short s_gctrlLegacyWarning = 0; + if ( mData.mProtocolVersion < 2 + && s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */ + LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"), + uVBoxMajor, uVBoxMinor, mData.mProtocolVersion)); + + return VINF_SUCCESS; +} + +int GuestSession::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc) +{ + LogFlowThisFuncEnter(); + + AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); + + /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", + fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/ + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* Did some error occur before? Then skip waiting and return. */ + if (mData.mStatus == GuestSessionStatus_Error) + { + waitResult = GuestSessionWaitResult_Error; + AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest session indicated an error\n", mData.mRC)); + if (pGuestRc) + *pGuestRc = mData.mRC; /* Return last set error. */ + return VERR_GSTCTL_GUEST_ERROR; + } + + /* Guest Additions < 4.3 don't support session handling, skip. */ + if (mData.mProtocolVersion < 2) + { + waitResult = GuestSessionWaitResult_WaitFlagNotSupported; + + LogFlowThisFunc(("Installed Guest Additions don't support waiting for dedicated sessions, skipping\n")); + return VINF_SUCCESS; + } + + waitResult = GuestSessionWaitResult_None; + if (fWaitFlags & GuestSessionWaitForFlag_Terminate) + { + switch (mData.mStatus) + { + case GuestSessionStatus_Terminated: + case GuestSessionStatus_Down: + waitResult = GuestSessionWaitResult_Terminate; + break; + + case GuestSessionStatus_TimedOutKilled: + case GuestSessionStatus_TimedOutAbnormally: + waitResult = GuestSessionWaitResult_Timeout; + break; + + case GuestSessionStatus_Error: + /* Handled above. */ + break; + + case GuestSessionStatus_Started: + waitResult = GuestSessionWaitResult_Start; + break; + + case GuestSessionStatus_Undefined: + case GuestSessionStatus_Starting: + /* Do the waiting below. */ + break; + + default: + AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus)); + return VERR_NOT_IMPLEMENTED; + } + } + else if (fWaitFlags & GuestSessionWaitForFlag_Start) + { + switch (mData.mStatus) + { + case GuestSessionStatus_Started: + case GuestSessionStatus_Terminating: + case GuestSessionStatus_Terminated: + case GuestSessionStatus_Down: + waitResult = GuestSessionWaitResult_Start; + break; + + case GuestSessionStatus_Error: + waitResult = GuestSessionWaitResult_Error; + break; + + case GuestSessionStatus_TimedOutKilled: + case GuestSessionStatus_TimedOutAbnormally: + waitResult = GuestSessionWaitResult_Timeout; + break; + + case GuestSessionStatus_Undefined: + case GuestSessionStatus_Starting: + /* Do the waiting below. */ + break; + + default: + AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus)); + return VERR_NOT_IMPLEMENTED; + } + } + + LogFlowThisFunc(("sessionStatus=%RU32, sessionRc=%Rrc, waitResult=%RU32\n", + mData.mStatus, mData.mRC, waitResult)); + + /* No waiting needed? Return immediately using the last set error. */ + if (waitResult != GuestSessionWaitResult_None) + { + if (pGuestRc) + *pGuestRc = mData.mRC; /* Return last set error (if any). */ + return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR; + } + + int vrc; + + GuestWaitEvent *pEvent = NULL; + GuestEventTypes eventTypes; + try + { + eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); + + vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */, + eventTypes, &pEvent); + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + + if (RT_FAILURE(vrc)) + return vrc; + + alock.release(); /* Release lock before waiting. */ + + GuestSessionStatus_T sessionStatus; + vrc = waitForStatusChange(pEvent, fWaitFlags, + uTimeoutMS, &sessionStatus, pGuestRc); + if (RT_SUCCESS(vrc)) + { + switch (sessionStatus) + { + case GuestSessionStatus_Started: + waitResult = GuestSessionWaitResult_Start; + break; + + case GuestSessionStatus_Terminated: + waitResult = GuestSessionWaitResult_Terminate; + break; + + case GuestSessionStatus_TimedOutKilled: + case GuestSessionStatus_TimedOutAbnormally: + waitResult = GuestSessionWaitResult_Timeout; + break; + + case GuestSessionStatus_Down: + waitResult = GuestSessionWaitResult_Terminate; + break; + + case GuestSessionStatus_Error: + waitResult = GuestSessionWaitResult_Error; + break; + + default: + waitResult = GuestSessionWaitResult_Status; + break; + } + } + + unregisterWaitEvent(pEvent); + + LogFlowFuncLeaveRC(vrc); + return vrc; } -int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc, - GuestSessionTask *pTask, ComObjPtr &pProgress) +int GuestSession::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, + GuestSessionStatus_T *pSessionStatus, int *pGuestRc) { - LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask)); - - AssertPtrReturn(pTask, VERR_INVALID_POINTER); - - /* Create the progress object. */ - HRESULT hr = pProgress.createObject(); - if (FAILED(hr)) - return VERR_COM_UNEXPECTED; - - hr = pProgress->init(static_cast(this), - Bstr(strTaskDesc).raw(), - TRUE /* aCancelable */); - if (FAILED(hr)) - return VERR_COM_UNEXPECTED; + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); - /* Initialize our worker task. */ - std::auto_ptr task(pTask); + VBoxEventType_T evtType; + ComPtr pIEvent; + int vrc = waitForEvent(pEvent, uTimeoutMS, + &evtType, pIEvent.asOutParam()); + if (RT_SUCCESS(vrc)) + { + Assert(evtType == VBoxEventType_OnGuestSessionStateChanged); - int rc = task->RunAsync(strTaskDesc, pProgress); - if (RT_FAILURE(rc)) - return rc; + ComPtr pChangedEvent = pIEvent; + Assert(!pChangedEvent.isNull()); - /* Don't destruct on success. */ - task.release(); + GuestSessionStatus_T sessionStatus; + pChangedEvent->COMGETTER(Status)(&sessionStatus); + if (pSessionStatus) + *pSessionStatus = sessionStatus; - LogFlowFuncLeaveRC(rc); - return rc; -} + ComPtr errorInfo; + HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam()); + ComAssertComRC(hr); -/** - * Queries/collects information prior to establishing a guest session. - * This is necessary to know which guest control protocol version to use, - * among other things (later). - * - * @return IPRT status code. - */ -int GuestSession::queryInfo(void) -{ -#if 1 - /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */ - mData.mProtocolVersion = 1; -#else - /* - * Try querying the guest control protocol version running on the guest. - * This is done using the Guest Additions version - */ - ComObjPtr pGuest = mData.mParent; - Assert(!pGuest.isNull()); + LONG lGuestRc; + hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc); + ComAssertComRC(hr); + if (RT_FAILURE((int)lGuestRc)) + vrc = VERR_GSTCTL_GUEST_ERROR; + if (pGuestRc) + *pGuestRc = (int)lGuestRc; - uint32_t uVerAdditions = pGuest->getAdditionsVersion(); - mData.mProtocolVersion = ( VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4 - && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */ - ? 2 /* Guest control 2.0. */ - : 1; /* Legacy guest control (VBox < 4.2). */ - /* Build revision is ignored. */ + LogFlowThisFunc(("Status changed event for session ID=%RU32, new status is: %RU32 (%Rrc)\n", + mData.mSession.mID, sessionStatus, + RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc)); + } - /* Tell the user but don't bitch too often. */ - static short s_gctrlLegacyWarning = 0; - if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */ - LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"), - VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion)); -#endif - return VINF_SUCCESS; + LogFlowFuncLeaveRC(vrc); + return vrc; } // implementation of public methods @@ -1030,17 +2440,32 @@ STDMETHODIMP GuestSession::Close(void) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); + /* Close session on guest. */ + int guestRc = VINF_SUCCESS; + int rc = closeSession(0 /* Flags */, 30 * 1000 /* Timeout */, + &guestRc); + /* On failure don't return here, instead do all the cleanup + * work first and then return an error. */ + /* Remove ourselves from the session list. */ - mData.mParent->sessionRemove(this); + int rc2 = mParent->sessionRemove(this); + if (rc2 == VERR_NOT_FOUND) /* Not finding the session anymore isn't critical. */ + rc2 = VINF_SUCCESS; - /* - * Release autocaller before calling uninit. - */ - autoCaller.release(); + if (RT_SUCCESS(rc)) + rc = rc2; - uninit(); + LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n", + rc, guestRc)); + if (RT_FAILURE(rc)) + { + if (rc == VERR_GSTCTL_GUEST_ERROR) + return GuestSession::setErrorExternal(this, guestRc); + + return setError(VBOX_E_IPRT_ERROR, + tr("Closing guest session failed with %Rrc"), rc); + } - LogFlowFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1137,7 +2562,7 @@ STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn ComObjPtr pProgress; SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */, Utf8Str(aSource), Utf8Str(aDest), fFlags); - AssertPtrReturn(pTask, VERR_NO_MEMORY); + AssertPtrReturn(pTask, E_OUTOFMEMORY); int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest), pTask, pProgress); if (RT_SUCCESS(rc)) @@ -1194,8 +2619,9 @@ STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode, { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ - hr = GuestProcess::setErrorExternal(this, guestRc); + case VERR_GSTCTL_GUEST_ERROR: + /** @todo Handle VERR_NOT_EQUAL (meaning process exit code <> 0). */ + hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory")); break; case VERR_INVALID_PARAMETER: @@ -1206,10 +2632,6 @@ STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode, hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted")); break; - case VERR_CANT_CREATE: - hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory")); - break; - default: hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc); break; @@ -1250,7 +2672,7 @@ STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, I { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1291,7 +2713,7 @@ STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1335,8 +2757,13 @@ STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafe HRESULT hr = S_OK; - ComObjPtr pDirectory; - int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory); + GuestDirectoryOpenInfo openInfo; + openInfo.mPath = Utf8Str(aPath); + openInfo.mFilter = Utf8Str(aFilter); + openInfo.mFlags = fFlags; + + ComObjPtr pDirectory; int guestRc; + int rc = directoryOpenInternal(openInfo, pDirectory, &guestRc); if (RT_SUCCESS(rc)) { /* Return directory object to the caller. */ @@ -1351,6 +2778,10 @@ STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafe Utf8Str(aPath).c_str())); break; + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestDirectory::setErrorExternal(this, guestRc); + break; + default: hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"), Utf8Str(aPath).c_str(),rc); @@ -1401,7 +2832,7 @@ STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **a { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1428,10 +2859,42 @@ STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath) #else LogFlowThisFuncEnter(); + if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0')) + return setError(E_INVALIDARG, tr("No directory to remove specified")); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; + + /* No flags; only remove the directory when empty. */ + uint32_t uFlags = 0; + + int guestRc; + int vrc = directoryRemoveInternal(Utf8Str(aPath), uFlags, &guestRc); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + case VERR_NOT_SUPPORTED: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Handling removing guest directories not supported by installed Guest Additions")); + break; + + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestDirectory::setErrorExternal(this, guestRc); + break; + + default: + hr = setError(VBOX_E_IPRT_ERROR, tr("Removing guest directory \"%s\" failed: %Rrc"), + Utf8Str(aPath).c_str(), vrc); + break; + } + } + + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1442,10 +2905,63 @@ STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayI #else LogFlowThisFuncEnter(); + if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0')) + return setError(E_INVALIDARG, tr("No directory to remove recursively specified")); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; + + ComObjPtr pProgress; + hr = pProgress.createObject(); + if (SUCCEEDED(hr)) + hr = pProgress->init(static_cast(this), + Bstr(tr("Removing guest directory")).raw(), + TRUE /*aCancelable*/); + if (FAILED(hr)) + return hr; + + /* Note: At the moment we don't supply progress information while + * deleting a guest directory recursively. So just complete + * the progress object right now. */ + /** @todo Implement progress reporting on guest directory deletion! */ + hr = pProgress->notifyComplete(S_OK); + if (FAILED(hr)) + return hr; + + /* Remove the directory + all its contents. */ + uint32_t uFlags = DIRREMOVE_FLAG_RECURSIVE + | DIRREMOVE_FLAG_CONTENT_AND_DIR; + int guestRc; + int vrc = directoryRemoveInternal(Utf8Str(aPath), uFlags, &guestRc); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + case VERR_NOT_SUPPORTED: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Handling removing guest directories recursively not supported by installed Guest Additions")); + break; + + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestFile::setErrorExternal(this, guestRc); + break; + + default: + hr = setError(VBOX_E_IPRT_ERROR, tr("Recursively removing guest directory \"%s\" failed: %Rrc"), + Utf8Str(aPath).c_str(), vrc); + break; + } + } + else + { + pProgress.queryInterfaceTo(aProgress); + } + + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1456,10 +2972,46 @@ STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSa #else LogFlowThisFuncEnter(); + if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0')) + return setError(E_INVALIDARG, tr("No source directory to rename specified")); + + if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0')) + return setError(E_INVALIDARG, tr("No destination directory to rename the source to specified")); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; + + /* No flags; only remove the directory when empty. */ + uint32_t uFlags = 0; + + int guestRc; + int vrc = pathRenameInternal(Utf8Str(aSource), Utf8Str(aDest), uFlags, &guestRc); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + case VERR_NOT_SUPPORTED: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Handling renaming guest directories not supported by installed Guest Additions")); + break; + + case VERR_GSTCTL_GUEST_ERROR: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Renaming guest directory failed: %Rrc"), guestRc); + break; + + default: + hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest directory \"%s\" failed: %Rrc"), + Utf8Str(aSource).c_str(), vrc); + break; + } + } + + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1491,7 +3043,7 @@ STDMETHODIMP GuestSession::EnvironmentClear(void) mData.mEnvironment.Clear(); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1516,7 +3068,7 @@ STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue) Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName))); strValue.cloneTo(aValue); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1558,7 +3110,7 @@ STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName) mData.mEnvironment.Unset(Utf8Str(aName)); - LogFlowFuncLeaveRC(S_OK); + LogFlowThisFuncLeave(); return S_OK; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1603,7 +3155,7 @@ STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists) switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1642,7 +3194,7 @@ STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath) { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1657,7 +3209,22 @@ STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath) #endif /* VBOX_WITH_GUEST_CONTROL */ } -STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile) +STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, IGuestFile **aFile) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + Bstr strSharingMode = ""; /* Sharing mode is ignored. */ + + return FileOpenEx(aPath, aOpenMode, aDisposition, strSharingMode.raw(), aCreationMode, + 0 /* aOffset */, aFile); +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestSession::FileOpenEx(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, IN_BSTR aSharingMode, + ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); @@ -1670,23 +3237,38 @@ STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aD return setError(E_INVALIDARG, tr("No open mode specified")); if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0')) return setError(E_INVALIDARG, tr("No disposition mode specified")); + /* aSharingMode is optional. */ CheckComArgOutPointerValid(aFile); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /** @todo Validate open mode. */ - /** @todo Validate disposition mode. */ + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; /** @todo Validate creation mode. */ uint32_t uCreationMode = 0; - HRESULT hr = S_OK; + GuestFileOpenInfo openInfo; + openInfo.mFileName = Utf8Str(aPath); + openInfo.mOpenMode = Utf8Str(aOpenMode); + openInfo.mDisposition = Utf8Str(aDisposition); + openInfo.mSharingMode = Utf8Str(aSharingMode); + openInfo.mCreationMode = aCreationMode; + openInfo.mInitialOffset = aOffset; + + uint64_t uFlagsIgnored; + int vrc = RTFileModeToFlagsEx(openInfo.mOpenMode.c_str(), + openInfo.mDisposition.c_str(), + openInfo.mSharingMode.c_str(), + &uFlagsIgnored); + if (RT_FAILURE(vrc)) + return setError(E_INVALIDARG, tr("Invalid open mode / disposition / sharing mode specified")); ComObjPtr pFile; int guestRc; - int vrc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition), - aCreationMode, aOffset, pFile, &guestRc); + vrc = fileOpenInternal(openInfo, pFile, &guestRc); if (RT_SUCCESS(vrc)) { /* Return directory object to the caller. */ @@ -1696,12 +3278,17 @@ STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aD { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ - hr = GuestProcess::setErrorExternal(this, guestRc); + case VERR_NOT_SUPPORTED: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Handling guest files not supported by installed Guest Additions")); + break; + + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestFile::setErrorExternal(this, guestRc); break; default: - hr = setError(VBOX_E_IPRT_ERROR, tr("Opening file \"%s\" failed: %Rrc"), + hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"), Utf8Str(aPath).c_str(), vrc); break; } @@ -1747,7 +3334,7 @@ STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo) { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1791,7 +3378,7 @@ STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize) { switch (vrc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; @@ -1812,10 +3399,47 @@ STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArr #else LogFlowThisFuncEnter(); + if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0')) + return setError(E_INVALIDARG, tr("No source file to rename specified")); + + if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0')) + return setError(E_INVALIDARG, tr("No destination file to rename the source to specified")); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ReturnComNotImplemented(); + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; + + /* No flags; only remove the directory when empty. */ + uint32_t uFlags = 0; + + int guestRc; + int vrc = pathRenameInternal(Utf8Str(aSource), Utf8Str(aDest), uFlags, &guestRc); + if (RT_FAILURE(vrc)) + { + switch (vrc) + { + case VERR_NOT_SUPPORTED: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Handling renaming guest files not supported by installed Guest Additions")); + break; + + case VERR_GSTCTL_GUEST_ERROR: + /** @todo Proper guestRc to text translation needed. */ + hr = setError(VBOX_E_IPRT_ERROR, + tr("Renaming guest file failed: %Rrc"), guestRc); + break; + + default: + hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest file \"%s\" failed: %Rrc"), + Utf8Str(aSource).c_str(), vrc); + break; + } + } + + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1841,10 +3465,10 @@ STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BST #else LogFlowThisFuncEnter(); - com::SafeArray affinity; + com::SafeArray affinityIgnored; return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment), - ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess); + ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinityIgnored), aProcess); #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -1865,6 +3489,10 @@ STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_B AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); + HRESULT hr = isReadyExternal(); + if (FAILED(hr)) + return hr; + GuestProcessStartupInfo procInfo; procInfo.mCommand = Utf8Str(aCommand); @@ -1892,8 +3520,6 @@ STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_B rc = procInfo.mEnvironment.Set(Utf8Str(environment[i])); } - HRESULT hr = S_OK; - if (RT_SUCCESS(rc)) { if (aFlags) @@ -1909,7 +3535,10 @@ STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_B { com::SafeArray affinity(ComSafeArrayInArg(aAffinity)); for (size_t i = 0; i < affinity.size(); i++) - procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */ + { + if (affinity[i]) + procInfo.mAffinity |= (uint64_t)1 << i; + } } procInfo.mPriority = aPriority; @@ -1933,7 +3562,7 @@ STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_B switch (rc) { case VERR_MAX_PROCS_REACHED: - hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest objects per session (%ld) reached"), + hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"), VBOX_GUESTCTRL_MAX_OBJECTS); break; @@ -1955,7 +3584,7 @@ STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess) #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else - LogFlowThisFunc(("aPID=%RU32\n", aPID)); + LogFlowThisFunc(("PID=%RU32\n", aPID)); CheckComArgOutPointerValid(aProcess); if (aPID == 0) @@ -2053,3 +3682,78 @@ STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile) #endif /* VBOX_WITH_GUEST_CONTROL */ } +STDMETHODIMP GuestSession::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aReason); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* + * Note: Do not hold any locks here while waiting! + */ + HRESULT hr = S_OK; + + int guestRc; GuestSessionWaitResult_T waitResult; + int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc); + if (RT_SUCCESS(vrc)) + { + *aReason = waitResult; + } + else + { + switch (vrc) + { + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestSession::setErrorExternal(this, guestRc); + break; + + case VERR_TIMEOUT: + *aReason = GuestSessionWaitResult_Timeout; + break; + + default: + { + const char *pszSessionName = mData.mSession.mName.c_str(); + hr = setError(VBOX_E_IPRT_ERROR, + tr("Waiting for guest session \"%s\" failed: %Rrc"), + pszSessionName ? pszSessionName : tr("Unnamed"), vrc); + break; + } + } + } + + LogFlowFuncLeaveRC(vrc); + return hr; +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + +STDMETHODIMP GuestSession::WaitForArray(ComSafeArrayIn(GuestSessionWaitForFlag_T, aFlags), ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason) +{ +#ifndef VBOX_WITH_GUEST_CONTROL + ReturnComNotImplemented(); +#else + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aReason); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* + * Note: Do not hold any locks here while waiting! + */ + uint32_t fWaitFor = GuestSessionWaitForFlag_None; + com::SafeArray flags(ComSafeArrayInArg(aFlags)); + for (size_t i = 0; i < flags.size(); i++) + fWaitFor |= flags[i]; + + return WaitFor(fWaitFor, aTimeoutMS, aReason); +#endif /* VBOX_WITH_GUEST_CONTROL */ +} + diff --git a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp index 84866b30..759020d9 100644 --- a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp +++ b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp @@ -1,11 +1,10 @@ - /* $Id: GuestSessionImplTasks.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest session tasks. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -138,6 +137,9 @@ int GuestSessionTask::setProgressSuccess(void) HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg) { + LogFlowFunc(("hr=%Rhrc, strMsg=%s\n", + hr, strMsg.c_str())); + if (mProgress.isNull()) /* Progress is optional. */ return hr; /* Return original rc. */ @@ -158,6 +160,62 @@ HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg) return hr; /* Return original rc. */ } +SessionTaskOpen::SessionTaskOpen(GuestSession *pSession, + uint32_t uFlags, + uint32_t uTimeoutMS) + : GuestSessionTask(pSession), + mFlags(uFlags), + mTimeoutMS(uTimeoutMS) +{ + +} + +SessionTaskOpen::~SessionTaskOpen(void) +{ + +} + +int SessionTaskOpen::Run(int *pGuestRc) +{ + LogFlowThisFuncEnter(); + + ComObjPtr pSession = mSession; + Assert(!pSession.isNull()); + + AutoCaller autoCaller(pSession); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + int vrc = pSession->startSessionInternal(pGuestRc); + /* Nothing to do here anymore. */ + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int SessionTaskOpen::RunAsync(const Utf8Str &strDesc, ComObjPtr &pProgress) +{ + LogFlowThisFunc(("strDesc=%s\n", strDesc.c_str())); + + mDesc = strDesc; + mProgress = pProgress; + + int rc = RTThreadCreate(NULL, SessionTaskOpen::taskThread, this, + 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0, + "gctlSesOpen"); + LogFlowFuncLeaveRC(rc); + return rc; +} + +/* static */ +int SessionTaskOpen::taskThread(RTTHREAD Thread, void *pvUser) +{ + std::auto_ptr task(static_cast(pvUser)); + AssertReturn(task.get(), VERR_GENERAL_FAILURE); + + LogFlowFunc(("pTask=%p\n", task.get())); + return task->Run(NULL /* guestRc */); +} + SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) : GuestSessionTask(pSession), @@ -245,6 +303,7 @@ int SessionTaskCopyTo::Run(void) } else { + rc = VINF_SUCCESS; pFile = mSourceFile; /* Size + offset are optional. */ } @@ -258,14 +317,20 @@ int SessionTaskCopyTo::Run(void) /* Startup process. */ ComObjPtr pProcess; int guestRc; - rc = pSession->processCreateExInteral(procInfo, pProcess); if (RT_SUCCESS(rc)) - rc = pProcess->startProcess(&guestRc); + rc = pSession->processCreateExInteral(procInfo, pProcess); + if (RT_SUCCESS(rc)) + { + Assert(!pProcess.isNull()); + rc = pProcess->startProcess(30 * 1000 /* 30s timeout */, + &guestRc); + } + if (RT_FAILURE(rc)) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -301,7 +366,7 @@ int SessionTaskCopyTo::Run(void) /* If the guest does not support waiting for stdin, we now yield in * order to reduce the CPU load due to busy waiting. */ if (waitRes == ProcessWaitResult_WaitFlagNotSupported) - RTThreadSleep(1); /* Optional, don't check rc. */ + RTThreadYield(); /* Optional, don't check rc. */ size_t cbRead = 0; if (mSourceSize) /* If we have nothing to write, take a shortcut. */ @@ -312,7 +377,7 @@ int SessionTaskCopyTo::Run(void) if (RT_SUCCESS(rc)) { rc = RTFileRead(*pFile, (uint8_t*)byBuf, - RT_MIN(cbToRead, sizeof(byBuf)), &cbRead); + RT_MIN((size_t)cbToRead, sizeof(byBuf)), &cbRead); /* * Some other error occured? There might be a chance that RTFileRead * could not resolve/map the native error code to an IPRT code, so just @@ -360,7 +425,7 @@ int SessionTaskCopyTo::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -403,7 +468,8 @@ int SessionTaskCopyTo::Run(void) break; } /* for */ - LogFlowThisFunc(("Copy loop ended with rc=%Rrc\n" ,rc)); + LogFlowThisFunc(("Copy loop ended with rc=%Rrc, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", + rc, cbToRead, cbWrittenTotal, mSourceSize)); if ( !fCanceled || RT_SUCCESS(rc)) @@ -471,9 +537,6 @@ int SessionTaskCopyTo::Run(void) rc = setProgressSuccess(); } } - - if (!pProcess.isNull()) - pProcess->uninit(); } /* processCreateExInteral */ if (!mSourceFile) /* Only close locally opened files. */ @@ -536,7 +599,7 @@ int SessionTaskCopyFrom::Run(void) * Note: There will be races between querying file size + reading the guest file's * content because we currently *do not* lock down the guest file when doing the * actual operations. - ** @todo Implement guest file locking! + ** @todo Use the IGuestFile API for locking down the file on the guest! */ GuestFsObjData objData; int guestRc; int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData, &guestRc); @@ -567,8 +630,8 @@ int SessionTaskCopyFrom::Run(void) else { GuestProcessStartupInfo procInfo; - procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), - mSource.c_str(), mDest.c_str(), objData.mObjectSize); + procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), + mSource.c_str(), mDest.c_str(), objData.mObjectSize); procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT); procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut; @@ -579,12 +642,13 @@ int SessionTaskCopyFrom::Run(void) ComObjPtr pProcess; rc = pSession->processCreateExInteral(procInfo, pProcess); if (RT_SUCCESS(rc)) - rc = pProcess->startProcess(&guestRc); + rc = pProcess->startProcess(30 * 1000 /* 30s timeout */, + &guestRc); if (RT_FAILURE(rc)) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -613,7 +677,7 @@ int SessionTaskCopyFrom::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -634,9 +698,9 @@ int SessionTaskCopyFrom::Run(void) /* If the guest does not support waiting for stdin, we now yield in * order to reduce the CPU load due to busy waiting. */ if (waitRes == ProcessWaitResult_WaitFlagNotSupported) - RTThreadSleep(1); /* Optional, don't check rc. */ + RTThreadYield(); /* Optional, don't check rc. */ - size_t cbRead; + uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */ rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), &cbRead, &guestRc); @@ -644,7 +708,7 @@ int SessionTaskCopyFrom::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -711,7 +775,7 @@ int SessionTaskCopyFrom::Run(void) /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write * to the destination -> access denied. */ setProgressErrorMsg(VBOX_E_IPRT_ERROR, - Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""), + Utf8StrFmt(GuestSession::tr("Unable to write \"%s\" to \"%s\": Access denied"), mSource.c_str(), mDest.c_str())); rc = VERR_GENERAL_FAILURE; /* Fudge. */ } @@ -742,9 +806,6 @@ int SessionTaskCopyFrom::Run(void) rc = setProgressSuccess(); } } - - if (!pProcess.isNull()) - pProcess->uninit(); } RTFileClose(fileDest); @@ -781,10 +842,13 @@ int SessionTaskCopyFrom::taskThread(RTTHREAD Thread, void *pvUser) } SessionTaskUpdateAdditions::SessionTaskUpdateAdditions(GuestSession *pSession, - const Utf8Str &strSource, uint32_t uFlags) + const Utf8Str &strSource, + const ProcessArguments &aArguments, + uint32_t uFlags) : GuestSessionTask(pSession) { mSource = strSource; + mArguments = aArguments; mFlags = uFlags; } @@ -793,6 +857,45 @@ SessionTaskUpdateAdditions::~SessionTaskUpdateAdditions(void) } +int SessionTaskUpdateAdditions::addProcessArguments(ProcessArguments &aArgumentsDest, + const ProcessArguments &aArgumentsSource) +{ + int rc = VINF_SUCCESS; + + try + { + /* Filter out arguments which already are in the destination to + * not end up having them specified twice. Not the fastest method on the + * planet but does the job. */ + ProcessArguments::const_iterator itSource = aArgumentsSource.begin(); + while (itSource != aArgumentsSource.end()) + { + bool fFound = false; + ProcessArguments::iterator itDest = aArgumentsDest.begin(); + while (itDest != aArgumentsDest.end()) + { + if ((*itDest).equalsIgnoreCase((*itSource))) + { + fFound = true; + break; + } + itDest++; + } + + if (!fFound) + aArgumentsDest.push_back((*itSource)); + + itSource++; + } + } + catch(std::bad_alloc &) + { + return VERR_NO_MEMORY; + } + + return rc; +} + int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize) @@ -820,8 +923,8 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS /* Copy over the Guest Additions file to the guest. */ if (RT_SUCCESS(rc)) { - LogFlowThisFunc(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n", - strFileSource.c_str(), strFileDest.c_str())); + LogRel(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n", + strFileSource.c_str(), strFileDest.c_str())); if (RT_SUCCESS(rc)) { @@ -858,8 +961,8 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS /* Determine where the installer image ended up and if it has the correct size. */ if (RT_SUCCESS(rc)) { - LogFlowThisFunc(("Verifying Guest Additions installer file \"%s\" ...\n", - strFileDest.c_str())); + LogRel(("Verifying Guest Additions installer file \"%s\" ...\n", + strFileDest.c_str())); GuestFsObjData objData; int64_t cbSizeOnGuest; int guestRc; @@ -874,15 +977,15 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS { if (RT_SUCCESS(rc)) /* Size does not match. */ { - LogFlowThisFunc(("Size of Guest Additions installer file \"%s\" does not match: %RI64bytes copied, %RU64bytes expected\n", - strFileDest.c_str(), cbSizeOnGuest, cbSize)); + LogRel(("Size of Guest Additions installer file \"%s\" does not match: %RI64 bytes copied, %RU64 bytes expected\n", + strFileDest.c_str(), cbSizeOnGuest, cbSize)); rc = VERR_BROKEN_PIPE; /** @todo Find a better error. */ } else { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -899,7 +1002,7 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS if (RT_SUCCESS(rc)) { if (pcbSize) - *pcbSize = cbSizeOnGuest; + *pcbSize = (uint32_t)cbSizeOnGuest; } } @@ -933,7 +1036,7 @@ int SessionTaskUpdateAdditions::runFileOnGuest(GuestSession *pSession, GuestProc procInfo.mCommand.c_str(), exitCode)); break; - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -1036,7 +1139,7 @@ int SessionTaskUpdateAdditions::Run(void) } Utf8Str strOSVer; - eOSType osType; + eOSType osType = eOSType_Unknown; if (RT_SUCCESS(rc)) { /* @@ -1066,21 +1169,30 @@ int SessionTaskUpdateAdditions::Run(void) * can't do automated updates here. */ /* Windows XP 64-bit (5.2) is a Windows 2003 Server actually, so skip this here. */ if ( RT_SUCCESS(rc) - && ( strOSVer.startsWith("5.0") /* Exclude the build number. */ - || strOSVer.startsWith("5.1")) /* Exclude the build number. */ - ) + && RTStrVersionCompare(strOSVer.c_str(), "5.0") >= 0) { - /* If we don't have AdditionsUpdateFlag_WaitForUpdateStartOnly set we can't continue - * because the Windows Guest Additions installer will fail because of WHQL popups. If the - * flag is set this update routine ends successfully as soon as the installer was started - * (and the user has to deal with it in the guest). */ - if (!(mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)) + if ( strOSVer.startsWith("5.0") /* Exclude the build number. */ + || strOSVer.startsWith("5.1") /* Exclude the build number. */) { - hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, - Utf8StrFmt(GuestSession::tr("Windows 2000 and XP are not supported for automatic updating due to WHQL interaction, please update manually"))); - rc = VERR_NOT_SUPPORTED; + /* If we don't have AdditionsUpdateFlag_WaitForUpdateStartOnly set we can't continue + * because the Windows Guest Additions installer will fail because of WHQL popups. If the + * flag is set this update routine ends successfully as soon as the installer was started + * (and the user has to deal with it in the guest). */ + if (!(mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)) + { + hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, + Utf8StrFmt(GuestSession::tr("Windows 2000 and XP are not supported for automatic updating due to WHQL interaction, please update manually"))); + rc = VERR_NOT_SUPPORTED; + } } } + else + { + hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, + Utf8StrFmt(GuestSession::tr("%s (%s) not supported for automatic updating, please update manually"), + strOSType.c_str(), strOSVer.c_str())); + rc = VERR_NOT_SUPPORTED; + } } else if (strOSType.contains("Solaris", Utf8Str::CaseInsensitive)) { @@ -1090,7 +1202,8 @@ int SessionTaskUpdateAdditions::Run(void) osType = eOSType_Linux; #if 1 /* Only Windows is supported (and tested) at the moment. */ - if (osType != eOSType_Windows) + if ( RT_SUCCESS(rc) + && osType != eOSType_Windows) { hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"), @@ -1172,15 +1285,15 @@ int SessionTaskUpdateAdditions::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ - setProgressErrorMsg(VBOX_E_IPRT_ERROR, - GuestProcess::guestErrorToString(guestRc)); + case VERR_GSTCTL_GUEST_ERROR: + hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR, + GuestProcess::guestErrorToString(guestRc)); break; default: - setProgressErrorMsg(VBOX_E_IPRT_ERROR, - Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), - strUpdateDir.c_str(), rc)); + hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR, + Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), + strUpdateDir.c_str(), rc)); break; } } @@ -1262,6 +1375,10 @@ int SessionTaskUpdateAdditions::Run(void) * using a running VBoxTray instance via balloon messages in the * Windows taskbar. */ siInstaller.mArguments.push_back(Utf8Str("/post_installstatus")); + /* Add optional installer command line arguments from the API to the + * installer's startup info. */ + rc = addProcessArguments(siInstaller.mArguments, mArguments); + AssertRC(rc); /* If the caller does not want to wait for out guest update process to end, * complete the progress object now so that the caller can do other work. */ if (mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly) @@ -1373,25 +1490,23 @@ int SessionTaskUpdateAdditions::Run(void) Utf8Str strError = Utf8StrFmt("No further error information available (%Rrc)", rc); if (!mProgress.isNull()) /* Progress object is optional. */ { - ComPtr pError; - hr = mProgress->COMGETTER(ErrorInfo)(pError.asOutParam()); - Assert(!pError.isNull()); - if (SUCCEEDED(hr)) + com::ProgressErrorInfo errorInfo(mProgress); + if ( errorInfo.isFullAvailable() + || errorInfo.isBasicAvailable()) { - Bstr strVal; - hr = pError->COMGETTER(Text)(strVal.asOutParam()); - if ( SUCCEEDED(hr) - && strVal.isNotEmpty()) - strError = strVal; + strError = errorInfo.getText(); } } - LogRel(("Automatic update of Guest Additions failed: %s\n", strError.c_str())); + LogRel(("Automatic update of Guest Additions failed: %s (%Rhrc)\n", + strError.c_str(), hr)); } LogRel(("Please install Guest Additions manually\n")); } + /** @todo Clean up copied / left over installation files. */ + LogFlowFuncLeaveRC(rc); return rc; } diff --git a/src/VBox/Main/src-client/HGCM.cpp b/src/VBox/Main/src-client/HGCM.cpp index abc74a27..722333ff 100644 --- a/src/VBox/Main/src-client/HGCM.cpp +++ b/src/VBox/Main/src-client/HGCM.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -242,7 +242,7 @@ HGCMService::HGCMService () #endif m_hExtension (NULL) { - memset (&m_fntable, 0, sizeof (m_fntable)); + RT_ZERO(m_fntable); } @@ -254,7 +254,7 @@ static bool g_fSaveState = false; * * @return VBox code */ -int HGCMService::loadServiceDLL (void) +int HGCMService::loadServiceDLL(void) { LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary)); @@ -264,9 +264,14 @@ int HGCMService::loadServiceDLL (void) } RTERRINFOSTATIC ErrInfo; - RTErrInfoInitStatic (&ErrInfo); + RTErrInfoInitStatic(&ErrInfo); - int rc = SUPR3HardenedLdrLoadAppPriv (m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core); + int rc; + + if (RTPathHasPath(m_pszSvcLibrary)) + rc = SUPR3HardenedLdrLoadPlugIn(m_pszSvcLibrary, &m_hLdrMod, &ErrInfo.Core); + else + rc = SUPR3HardenedLdrLoadAppPriv(m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core); if (RT_SUCCESS(rc)) { @@ -274,7 +279,7 @@ int HGCMService::loadServiceDLL (void) m_pfnLoad = NULL; - rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad); + rc = RTLdrGetSymbol(m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad); if (RT_FAILURE(rc) || !m_pfnLoad) { @@ -289,13 +294,13 @@ int HGCMService::loadServiceDLL (void) if (RT_SUCCESS(rc)) { - memset (&m_fntable, 0, sizeof (m_fntable)); + RT_ZERO(m_fntable); - m_fntable.cbSize = sizeof (m_fntable); + m_fntable.cbSize = sizeof(m_fntable); m_fntable.u32Version = VBOX_HGCM_SVC_VERSION; m_fntable.pHelpers = &m_svcHelpers; - rc = m_pfnLoad (&m_fntable); + rc = m_pfnLoad(&m_fntable); LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc)); @@ -313,7 +318,7 @@ int HGCMService::loadServiceDLL (void) if (m_fntable.pfnUnload) { - m_fntable.pfnUnload (m_fntable.pvService); + m_fntable.pfnUnload(m_fntable.pvService); } } } @@ -328,7 +333,7 @@ int HGCMService::loadServiceDLL (void) if (RT_FAILURE(rc)) { - unloadServiceDLL (); + unloadServiceDLL(); } return rc; @@ -338,14 +343,14 @@ int HGCMService::loadServiceDLL (void) * * @return VBox code */ -void HGCMService::unloadServiceDLL (void) +void HGCMService::unloadServiceDLL(void) { if (m_hLdrMod) { - RTLdrClose (m_hLdrMod); + RTLdrClose(m_hLdrMod); } - memset (&m_fntable, 0, sizeof (m_fntable)); + RT_ZERO(m_fntable); m_pfnLoad = NULL; m_hLdrMod = NIL_RTLDRMOD; } @@ -790,9 +795,9 @@ int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszS /* The maximum length of the thread name, allowed by the RT is 15. */ char szThreadName[16]; - if (!strncmp (pszServiceName, "VBoxShared", 10)) + if (!strncmp (pszServiceName, RT_STR_TUPLE("VBoxShared"))) RTStrPrintf (szThreadName, sizeof (szThreadName), "Sh%s", pszServiceName + 10); - else if (!strncmp (pszServiceName, "VBox", 4)) + else if (!strncmp (pszServiceName, RT_STR_TUPLE("VBox"))) RTStrCopy (szThreadName, sizeof (szThreadName), pszServiceName + 4); else RTStrCopy (szThreadName, sizeof (szThreadName), pszServiceName); diff --git a/src/VBox/Main/src-client/HGCMThread.cpp b/src/VBox/Main/src-client/HGCMThread.cpp index 49c3db18..d0e046a4 100644 --- a/src/VBox/Main/src-client/HGCMThread.cpp +++ b/src/VBox/Main/src-client/HGCMThread.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -220,7 +220,7 @@ HGCMThread::HGCMThread () m_pFreeTail (NULL), m_handle (0) { - memset (&m_critsect, 0, sizeof (m_critsect)); + RT_ZERO(m_critsect); } HGCMThread::~HGCMThread () @@ -306,7 +306,7 @@ int HGCMThread::Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, else { Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n")); - memset (&m_critsect, 0, sizeof (m_critsect)); + RT_ZERO(m_critsect); } } else diff --git a/src/VBox/Main/src-client/KeyboardImpl.cpp b/src/VBox/Main/src-client/KeyboardImpl.cpp index 43c2776c..74154dac 100644 --- a/src/VBox/Main/src-client/KeyboardImpl.cpp +++ b/src/VBox/Main/src-client/KeyboardImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -112,7 +112,7 @@ HRESULT Keyboard::init(Console *aParent) unconst(mParent) = aParent; unconst(mEventSource).createObject(); - HRESULT rc = mEventSource->init(static_cast(this)); + HRESULT rc = mEventSource->init(); AssertComRCReturnRC(rc); /* Confirm a successful initialization */ @@ -271,6 +271,27 @@ STDMETHODIMP Keyboard::COMGETTER(EventSource)(IEventSource ** aEventSource) // private methods // +DECLCALLBACK(void) Keyboard::keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds) +{ + PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface); + pDrv->pKeyboard->getParent()->onKeyboardLedsChange(RT_BOOL(enmLeds & PDMKEYBLEDS_NUMLOCK), + RT_BOOL(enmLeds & PDMKEYBLEDS_CAPSLOCK), + RT_BOOL(enmLeds & PDMKEYBLEDS_SCROLLLOCK)); +} + +/** + * @interface_method_impl{PDMIKEYBOARDCONNECTOR,pfnSetActive} + */ +DECLCALLBACK(void) Keyboard::keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive) +{ + PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface); + if (fActive) + pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED; + else + pDrv->u32DevCaps &= ~KEYBOARD_DEVCAP_ENABLED; +} + + /** * @interface_method_impl{PDMIBASE,pfnQueryInterface} */ @@ -293,55 +314,33 @@ DECLCALLBACK(void *) Keyboard::drvQueryInterface(PPDMIBASE pInterface, const cha */ DECLCALLBACK(void) Keyboard::drvDestruct(PPDMDRVINS pDrvIns) { - PDRVMAINKEYBOARD pData = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD); - LogFlow(("Keyboard::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD); + LogFlow(("Keyboard::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); - if (pData->pKeyboard) + if (pThis->pKeyboard) { - AutoWriteLock kbdLock(pData->pKeyboard COMMA_LOCKVAL_SRC_POS); + AutoWriteLock kbdLock(pThis->pKeyboard COMMA_LOCKVAL_SRC_POS); for (unsigned cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev) - if (pData->pKeyboard->mpDrv[cDev] == pData) + if (pThis->pKeyboard->mpDrv[cDev] == pThis) { - pData->pKeyboard->mpDrv[cDev] = NULL; + pThis->pKeyboard->mpDrv[cDev] = NULL; break; } - pData->pKeyboard->mpVMMDev = NULL; + pThis->pKeyboard->mpVMMDev = NULL; } } -DECLCALLBACK(void) keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, - PDMKEYBLEDS enmLeds) -{ - PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface); - pDrv->pKeyboard->getParent()->onKeyboardLedsChange(!!(enmLeds & PDMKEYBLEDS_NUMLOCK), - !!(enmLeds & PDMKEYBLEDS_CAPSLOCK), - !!(enmLeds & PDMKEYBLEDS_SCROLLLOCK)); -} - -/** - * @interface_method_impl{PDMIKEYBOARDCONNECTOR,pfnSetActive} - */ -DECLCALLBACK(void) Keyboard::keyboardSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive) -{ - PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface); - if (fActive) - pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED; - else - pDrv->u32DevCaps &= ~KEYBOARD_DEVCAP_ENABLED; -} - /** * Construct a keyboard driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ -DECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, - uint32_t fFlags) +DECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { - PDRVMAINKEYBOARD pData = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD); - LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINKEYBOARD pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINKEYBOARD); + LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. @@ -357,14 +356,14 @@ DECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, */ pDrvIns->IBase.pfnQueryInterface = Keyboard::drvQueryInterface; - pData->IConnector.pfnLedStatusChange = keyboardLedStatusChange; - pData->IConnector.pfnSetActive = keyboardSetActive; + pThis->IConnector.pfnLedStatusChange = keyboardLedStatusChange; + pThis->IConnector.pfnSetActive = Keyboard::keyboardSetActive; /* * Get the IKeyboardPort interface of the above driver/device. */ - pData->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT); - if (!pData->pUpPort) + pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT); + if (!pThis->pUpPort) { AssertMsgFailed(("Configuration error: No keyboard port interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; @@ -380,12 +379,12 @@ DECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc)); return rc; } - pData->pKeyboard = (Keyboard *)pv; /** @todo Check this cast! */ + pThis->pKeyboard = (Keyboard *)pv; /** @todo Check this cast! */ unsigned cDev; for (cDev = 0; cDev < KEYBOARD_MAX_DEVICES; ++cDev) - if (!pData->pKeyboard->mpDrv[cDev]) + if (!pThis->pKeyboard->mpDrv[cDev]) { - pData->pKeyboard->mpDrv[cDev] = pData; + pThis->pKeyboard->mpDrv[cDev] = pThis; break; } if (cDev == KEYBOARD_MAX_DEVICES) diff --git a/src/VBox/Main/src-client/MachineDebuggerImpl.cpp b/src/VBox/Main/src-client/MachineDebuggerImpl.cpp index 11dd820a..1520bb55 100644 --- a/src/VBox/Main/src-client/MachineDebuggerImpl.cpp +++ b/src/VBox/Main/src-client/MachineDebuggerImpl.cpp @@ -1,10 +1,10 @@ /* $Id: MachineDebuggerImpl.cpp $ */ /** @file - * VBox IMachineDebugger COM class implementation. + * VBox IMachineDebugger COM class implementation (VBoxC). */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -15,6 +15,9 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ +/******************************************************************************* +* Header Files * +*******************************************************************************/ #include "MachineDebuggerImpl.h" #include "Global.h" @@ -26,19 +29,12 @@ #include #include #include -#include +#include #include -#include +#include #include #include -// defines -///////////////////////////////////////////////////////////////////////////// - - -// globals -///////////////////////////////////////////////////////////////////////////// - // constructor / destructor ///////////////////////////////////////////////////////////////////////////// @@ -85,6 +81,8 @@ HRESULT MachineDebugger::init (Console *aParent) unconst(mParent) = aParent; + for (unsigned i = 0; i < RT_ELEMENTS(maiQueuedEmExecPolicyParams); i++) + maiQueuedEmExecPolicyParams[i] = UINT8_MAX; mSingleStepQueued = ~0; mRecompileUserQueued = ~0; mRecompileSupervisorQueued = ~0; @@ -171,54 +169,59 @@ STDMETHODIMP MachineDebugger::COMSETTER(SingleStep)(BOOL a_fEnable) } /** - * Returns the current recompile user mode code flag. + * Internal worker for getting an EM executable policy setting. * - * @returns COM status code - * @param a_fEnabled address of result variable + * @returns COM status code. + * @param enmPolicy Which EM policy. + * @param pfEnforced Where to return the policy setting. */ -STDMETHODIMP MachineDebugger::COMGETTER(RecompileUser) (BOOL *aEnabled) +HRESULT MachineDebugger::getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced) { - CheckComArgOutPointerValid(aEnabled); + CheckComArgOutPointerValid(pfEnforced); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - Console::SafeVMPtrQuiet pVM (mParent); - - if (pVM.isOk()) - *aEnabled = !EMIsRawRing3Enabled (pVM.raw()); - else - *aEnabled = false; - - return S_OK; + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (queueSettings()) + *pfEnforced = maiQueuedEmExecPolicyParams[enmPolicy] == 1; + else + { + bool fEnforced = false; + Console::SafeVMPtrQuiet ptrVM(mParent); + hrc = ptrVM.rc(); + if (SUCCEEDED(hrc)) + EMR3QueryExecutionPolicy(ptrVM.rawUVM(), enmPolicy, &fEnforced); + *pfEnforced = fEnforced; + } + } + return hrc; } /** - * Sets the recompile user mode code flag. + * Internal worker for setting an EM executable policy. * - * @returns COM status - * @param aEnable new user mode code recompile flag. + * @returns COM status code. + * @param enmPolicy Which policy to change. + * @param fEnforce Whether to enforce the policy or not. */ -STDMETHODIMP MachineDebugger::COMSETTER(RecompileUser)(BOOL aEnable) +HRESULT MachineDebugger::setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce) { - LogFlowThisFunc(("enable=%d\n", aEnable)); - AutoCaller autoCaller(this); HRESULT hrc = autoCaller.rc(); if (SUCCEEDED(hrc)) { - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); if (queueSettings()) - mRecompileUserQueued = aEnable; // queue the request + maiQueuedEmExecPolicyParams[enmPolicy] = fEnforce ? 1 : 0; else { - Console::SafeVMPtr ptrVM(mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = EMR3SetExecutionPolicy(ptrVM.raw(), EMEXECPOLICY_RECOMPILE_RING3, RT_BOOL(aEnable)); + int vrc = EMR3SetExecutionPolicy(ptrVM.rawUVM(), enmPolicy, fEnforce != FALSE); if (RT_FAILURE(vrc)) hrc = setError(VBOX_E_VM_ERROR, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc); } @@ -227,6 +230,29 @@ STDMETHODIMP MachineDebugger::COMSETTER(RecompileUser)(BOOL aEnable) return hrc; } +/** + * Returns the current recompile user mode code flag. + * + * @returns COM status code + * @param a_fEnabled address of result variable + */ +STDMETHODIMP MachineDebugger::COMGETTER(RecompileUser) (BOOL *aEnabled) +{ + return getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aEnabled); +} + +/** + * Sets the recompile user mode code flag. + * + * @returns COM status + * @param aEnable new user mode code recompile flag. + */ +STDMETHODIMP MachineDebugger::COMSETTER(RecompileUser)(BOOL aEnable) +{ + LogFlowThisFunc(("enable=%d\n", aEnable)); + return setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aEnable); +} + /** * Returns the current recompile supervisor code flag. * @@ -235,21 +261,7 @@ STDMETHODIMP MachineDebugger::COMSETTER(RecompileUser)(BOOL aEnable) */ STDMETHODIMP MachineDebugger::COMGETTER(RecompileSupervisor) (BOOL *aEnabled) { - CheckComArgOutPointerValid(aEnabled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - Console::SafeVMPtrQuiet pVM (mParent); - - if (pVM.isOk()) - *aEnabled = !EMIsRawRing0Enabled (pVM.raw()); - else - *aEnabled = false; - - return S_OK; + return getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aEnabled); } /** @@ -261,27 +273,30 @@ STDMETHODIMP MachineDebugger::COMGETTER(RecompileSupervisor) (BOOL *aEnabled) STDMETHODIMP MachineDebugger::COMSETTER(RecompileSupervisor)(BOOL aEnable) { LogFlowThisFunc(("enable=%d\n", aEnable)); + return setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aEnable); +} - AutoCaller autoCaller(this); - HRESULT hrc = autoCaller.rc(); - if (SUCCEEDED(hrc)) - { - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if (queueSettings()) - mRecompileSupervisorQueued = aEnable; // queue the request - else - { - Console::SafeVMPtr ptrVM(mParent); - hrc = ptrVM.rc(); - if (SUCCEEDED(hrc)) - { - int vrc = EMR3SetExecutionPolicy(ptrVM.raw(), EMEXECPOLICY_RECOMPILE_RING0, RT_BOOL(aEnable)); - if (RT_FAILURE(vrc)) - hrc = setError(VBOX_E_VM_ERROR, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc); - } - } - } - return hrc; +/** + * Returns the current execute-all-in-IEM setting. + * + * @returns COM status code + * @param aEnabled Address of result variable. + */ +STDMETHODIMP MachineDebugger::COMGETTER(ExecuteAllInIEM) (BOOL *aEnabled) +{ + return getEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aEnabled); +} + +/** + * Changes the execute-all-in-IEM setting. + * + * @returns COM status code + * @param aEnable New setting. + */ +STDMETHODIMP MachineDebugger::COMSETTER(ExecuteAllInIEM)(BOOL aEnable) +{ + LogFlowThisFunc(("enable=%d\n", aEnable)); + return setEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aEnable); } /** @@ -295,15 +310,17 @@ STDMETHODIMP MachineDebugger::COMGETTER(PATMEnabled) (BOOL *aEnabled) CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); +#ifdef VBOX_WITH_RAW_MODE AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); - - if (pVM.isOk()) - *aEnabled = PATMIsEnabled (pVM.raw()); + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) + *aEnabled = PATMR3IsEnabled (ptrVM.rawUVM()); else +#endif *aEnabled = false; return S_OK; @@ -322,6 +339,7 @@ STDMETHODIMP MachineDebugger::COMSETTER(PATMEnabled) (BOOL aEnable) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); +#ifdef VBOX_WITH_RAW_MODE AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (queueSettings()) @@ -331,11 +349,18 @@ STDMETHODIMP MachineDebugger::COMSETTER(PATMEnabled) (BOOL aEnable) return S_OK; } - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (FAILED(ptrVM.rc())) + return ptrVM.rc(); - PATMR3AllowPatching (pVM, aEnable); + int vrc = PATMR3AllowPatching(ptrVM.rawUVM(), RT_BOOL(aEnable)); + if (RT_FAILURE(vrc)) + return setError(VBOX_E_VM_ERROR, tr("PATMR3AllowPatching returned %Rrc"), vrc); +#else /* !VBOX_WITH_RAW_MODE */ + if (aEnable) + return setError(VBOX_E_VM_ERROR, tr("PATM not present"), VERR_NOT_SUPPORTED); +#endif /* !VBOX_WITH_RAW_MODE */ return S_OK; } @@ -352,13 +377,15 @@ STDMETHODIMP MachineDebugger::COMGETTER(CSAMEnabled) (BOOL *aEnabled) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); +#ifdef VBOX_WITH_RAW_MODE AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (pVM.isOk()) - *aEnabled = CSAMIsEnabled (pVM.raw()); + if (ptrVM.isOk()) + *aEnabled = CSAMR3IsEnabled(ptrVM.rawUVM()); else +#endif /* VBOX_WITH_RAW_MODE */ *aEnabled = false; return S_OK; @@ -377,6 +404,7 @@ STDMETHODIMP MachineDebugger::COMSETTER(CSAMEnabled) (BOOL aEnable) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); +#ifdef VBOX_WITH_RAW_MODE AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (queueSettings()) @@ -386,20 +414,18 @@ STDMETHODIMP MachineDebugger::COMSETTER(CSAMEnabled) (BOOL aEnable) return S_OK; } - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); - - int vrc; - if (aEnable) - vrc = CSAMEnableScanning (pVM); - else - vrc = CSAMDisableScanning (pVM); + Console::SafeVMPtr ptrVM(mParent); + if (FAILED(ptrVM.rc())) + return ptrVM.rc(); + int vrc = CSAMR3SetScanningEnabled(ptrVM.rawUVM(), aEnable != FALSE); if (RT_FAILURE(vrc)) - { - /** @todo handle error case */ - } + return setError(VBOX_E_VM_ERROR, tr("CSAMR3SetScanningEnabled returned %Rrc"), vrc); +#else /* !VBOX_WITH_RAW_MODE */ + if (aEnable) + return setError(VBOX_E_VM_ERROR, tr("CASM not present"), VERR_NOT_SUPPORTED); +#endif /* !VBOX_WITH_RAW_MODE */ return S_OK; } @@ -450,11 +476,11 @@ STDMETHODIMP MachineDebugger::COMSETTER(LogEnabled) (BOOL aEnabled) return S_OK; } - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (FAILED(ptrVM.rc())) return ptrVM.rc(); #ifdef LOG_ENABLED - int vrc = DBGFR3LogModifyFlags (pVM, aEnabled ? "enabled" : "disabled"); + int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aEnabled ? "enabled" : "disabled"); if (RT_FAILURE(vrc)) { /** @todo handle error code. */ @@ -603,10 +629,10 @@ STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExEnabled) (BOOL *aEnabled) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (pVM.isOk()) - *aEnabled = HWACCMIsEnabled (pVM.raw()); + if (ptrVM.isOk()) + *aEnabled = HMR3IsEnabled(ptrVM.rawUVM()); else *aEnabled = false; @@ -619,19 +645,20 @@ STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExEnabled) (BOOL *aEnabled) * @returns COM status code * @param aEnabled address of result variable */ -STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExNestedPagingEnabled) (BOOL *aEnabled) +STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExNestedPagingEnabled)(BOOL *aEnabled) { CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (pVM.isOk()) - *aEnabled = HWACCMR3IsNestedPagingActive (pVM.raw()); + if (ptrVM.isOk()) + *aEnabled = HMR3IsNestedPagingActive(ptrVM.rawUVM()); else *aEnabled = false; @@ -649,14 +676,41 @@ STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExVPIDEnabled) (BOOL *aEnabled) CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (pVM.isOk()) - *aEnabled = HWACCMR3IsVPIDActive (pVM.raw()); + if (ptrVM.isOk()) + *aEnabled = HMR3IsVpidActive(ptrVM.rawUVM()); + else + *aEnabled = false; + + return S_OK; +} + +/** + * Returns the current unrestricted execution setting. + * + * @returns COM status code + * @param aEnabled address of result variable + */ +STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExUXEnabled) (BOOL *aEnabled) +{ + CheckComArgOutPointerValid(aEnabled); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + Console::SafeVMPtrQuiet ptrVM(mParent); + + if (ptrVM.isOk()) + *aEnabled = HMR3IsUXActive(ptrVM.rawUVM()); else *aEnabled = false; @@ -680,7 +734,7 @@ STDMETHODIMP MachineDebugger::COMGETTER(OSName)(BSTR *a_pbstrName) * Do the job and try convert the name. */ char szName[64]; - int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.raw(), szName, sizeof(szName), NULL, 0); + int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0); if (RT_SUCCESS(vrc)) { try @@ -717,7 +771,7 @@ STDMETHODIMP MachineDebugger::COMGETTER(OSVersion)(BSTR *a_pbstrVersion) * Do the job and try convert the name. */ char szVersion[256]; - int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.raw(), NULL, 0, szVersion, sizeof(szVersion)); + int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion)); if (RT_SUCCESS(vrc)) { try @@ -752,12 +806,13 @@ STDMETHODIMP MachineDebugger::COMGETTER(PAEEnabled) (BOOL *aEnabled) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (pVM.isOk()) + if (ptrVM.isOk()) { - uint64_t cr4 = CPUMGetGuestCR4 (VMMGetCpu0(pVM.raw())); - *aEnabled = !!(cr4 & X86_CR4_PAE); + uint32_t cr4; + int rc = DBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc); + *aEnabled = RT_BOOL(cr4 & X86_CR4_PAE); } else *aEnabled = false; @@ -784,7 +839,7 @@ STDMETHODIMP MachineDebugger::COMGETTER(VirtualTimeRate)(ULONG *a_puPct) Console::SafeVMPtr ptrVM(mParent); hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) - *a_puPct = TMGetWarpDrive(ptrVM.raw()); + *a_puPct = TMR3GetWarpDrive(ptrVM.rawUVM()); } return hrc; @@ -814,7 +869,7 @@ STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG a_uPct) hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = TMR3SetWarpDrive(ptrVM.raw(), a_uPct); + int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), a_uPct); if (RT_FAILURE(vrc)) hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), a_uPct, vrc); } @@ -825,7 +880,7 @@ STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG a_uPct) } /** - * Hack for getting the VM handle. + * Hack for getting the user mode VM handle (UVM). * * This is only temporary (promise) while prototyping the debugger. * @@ -833,10 +888,12 @@ STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG a_uPct) * @param a_u64Vm Where to store the vm handle. Since there is no * uintptr_t in COM, we're using the max integer. * (No, ULONG is not pointer sized!) + * @remarks The returned handle must be passed to VMR3ReleaseUVM()! + * @remarks Prior to 4.3 this returned PVM. */ -STDMETHODIMP MachineDebugger::COMGETTER(VM)(LONG64 *a_u64Vm) +STDMETHODIMP MachineDebugger::COMGETTER(VM)(LONG64 *a_i64Vm) { - CheckComArgOutPointerValid(a_u64Vm); + CheckComArgOutPointerValid(a_i64Vm); AutoCaller autoCaller(this); HRESULT hrc = autoCaller.rc(); @@ -847,10 +904,13 @@ STDMETHODIMP MachineDebugger::COMGETTER(VM)(LONG64 *a_u64Vm) Console::SafeVMPtr ptrVM(mParent); hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) - *a_u64Vm = (intptr_t)ptrVM.raw(); + { + VMR3RetainUVM(ptrVM.rawUVM()); + *a_i64Vm = (intptr_t)ptrVM.rawUVM(); + } /* - * Note! pVM protection provided by SafeVMPtr is no long effective + * Note! ptrVM protection provided by SafeVMPtr is no long effective * after we return from this method. */ } @@ -877,7 +937,7 @@ STDMETHODIMP MachineDebugger::DumpGuestCore(IN_BSTR a_bstrFilename, IN_BSTR a_bs hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = DBGFR3CoreWrite(ptrVM, strFilename.c_str(), false /*fReplaceFile*/); + int vrc = DBGFR3CoreWrite(ptrVM.rawUVM(), strFilename.c_str(), false /*fReplaceFile*/); if (RT_SUCCESS(vrc)) hrc = S_OK; else @@ -1037,7 +1097,7 @@ STDMETHODIMP MachineDebugger::Info(IN_BSTR a_bstrName, IN_BSTR a_bstrArgs, BSTR */ MACHINEDEBUGGERINOFHLP Hlp; MachineDebuggerInfoInit(&Hlp); - int vrc = DBGFR3Info(ptrVM.raw(), strName.c_str(), strArgs.c_str(), &Hlp.Core); + int vrc = DBGFR3Info(ptrVM.rawUVM(), strName.c_str(), strArgs.c_str(), &Hlp.Core); if (RT_SUCCESS(vrc)) { if (!Hlp.fOutOfMemory) @@ -1079,11 +1139,11 @@ STDMETHODIMP MachineDebugger::InjectNMI() hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = HWACCMR3InjectNMI(ptrVM); + int vrc = DBGFR3InjectNMI(ptrVM.rawUVM(), 0); if (RT_SUCCESS(vrc)) hrc = S_OK; else - hrc = setError(E_FAIL, tr("HWACCMR3InjectNMI failed with %Rrc"), vrc); + hrc = setError(E_FAIL, tr("DBGFR3InjectNMI failed with %Rrc"), vrc); } } return hrc; @@ -1104,7 +1164,7 @@ STDMETHODIMP MachineDebugger::ModifyLogFlags(IN_BSTR a_bstrSettings) hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = DBGFR3LogModifyFlags(ptrVM, strSettings.c_str()); + int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), strSettings.c_str()); if (RT_SUCCESS(vrc)) hrc = S_OK; else @@ -1129,7 +1189,7 @@ STDMETHODIMP MachineDebugger::ModifyLogGroups(IN_BSTR a_bstrSettings) hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = DBGFR3LogModifyGroups(ptrVM, strSettings.c_str()); + int vrc = DBGFR3LogModifyGroups(ptrVM.rawUVM(), strSettings.c_str()); if (RT_SUCCESS(vrc)) hrc = S_OK; else @@ -1154,7 +1214,7 @@ STDMETHODIMP MachineDebugger::ModifyLogDestinations(IN_BSTR a_bstrSettings) hrc = ptrVM.rc(); if (SUCCEEDED(hrc)) { - int vrc = DBGFR3LogModifyDestinations(ptrVM, strSettings.c_str()); + int vrc = DBGFR3LogModifyDestinations(ptrVM.rawUVM(), strSettings.c_str()); if (RT_SUCCESS(vrc)) hrc = S_OK; else @@ -1206,7 +1266,7 @@ STDMETHODIMP MachineDebugger::DetectOS(BSTR *a_pbstrName) */ /** @todo automatically load the DBGC plugins or this is a waste of time. */ char szName[64]; - int vrc = DBGFR3OSDetect(ptrVM.raw(), szName, sizeof(szName)); + int vrc = DBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName)); if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED) { try @@ -1281,7 +1341,7 @@ STDMETHODIMP MachineDebugger::GetRegister(ULONG a_idCpu, IN_BSTR a_bstrName, BST */ DBGFREGVAL Value; DBGFREGVALTYPE enmType; - int vrc = DBGFR3RegNmQuery(ptrVM.raw(), a_idCpu, strName.c_str(), &Value, &enmType); + int vrc = DBGFR3RegNmQuery(ptrVM.rawUVM(), a_idCpu, strName.c_str(), &Value, &enmType); if (RT_SUCCESS(vrc)) { try @@ -1329,13 +1389,13 @@ STDMETHODIMP MachineDebugger::GetRegisters(ULONG a_idCpu, ComSafeArrayOut(BSTR, * Real work. */ size_t cRegs; - int vrc = DBGFR3RegNmQueryAllCount(ptrVM.raw(), &cRegs); + int vrc = DBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs); if (RT_SUCCESS(vrc)) { PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs); if (paRegs) { - vrc = DBGFR3RegNmQueryAll(ptrVM.raw(), paRegs, cRegs); + vrc = DBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs); if (RT_SUCCESS(vrc)) { try @@ -1345,7 +1405,6 @@ STDMETHODIMP MachineDebugger::GetRegisters(ULONG a_idCpu, ComSafeArrayOut(BSTR, for (uint32_t iReg = 0; iReg < cRegs; iReg++) { - char szHex[128]; Bstr bstrValue; hrc = formatRegisterValue(&bstrValue, &paRegs[iReg].Val, paRegs[iReg].enmType); @@ -1402,12 +1461,12 @@ STDMETHODIMP MachineDebugger::DumpGuestStack(ULONG a_idCpu, BSTR *a_pbstrStack) */ STDMETHODIMP MachineDebugger::ResetStats(IN_BSTR aPattern) { - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (!pVM.isOk()) + if (!ptrVM.isOk()) return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running"); - STAMR3Reset(pVM, Utf8Str(aPattern).c_str()); + STAMR3Reset(ptrVM.rawUVM(), Utf8Str(aPattern).c_str()); return S_OK; } @@ -1418,14 +1477,14 @@ STDMETHODIMP MachineDebugger::ResetStats(IN_BSTR aPattern) * @returns COM status code. * @param aPattern The selection pattern. A bit similar to filename globbing. */ -STDMETHODIMP MachineDebugger::DumpStats (IN_BSTR aPattern) +STDMETHODIMP MachineDebugger::DumpStats(IN_BSTR aPattern) { - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM(mParent); - if (!pVM.isOk()) + if (!ptrVM.isOk()) return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running"); - STAMR3Dump(pVM, Utf8Str(aPattern).c_str()); + STAMR3Dump(ptrVM.rawUVM(), Utf8Str(aPattern).c_str()); return S_OK; } @@ -1440,13 +1499,13 @@ STDMETHODIMP MachineDebugger::DumpStats (IN_BSTR aPattern) */ STDMETHODIMP MachineDebugger::GetStats (IN_BSTR aPattern, BOOL aWithDescriptions, BSTR *aStats) { - Console::SafeVMPtrQuiet pVM (mParent); + Console::SafeVMPtrQuiet ptrVM (mParent); - if (!pVM.isOk()) + if (!ptrVM.isOk()) return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running"); char *pszSnapshot; - int vrc = STAMR3Snapshot(pVM, Utf8Str(aPattern).c_str(), &pszSnapshot, NULL, + int vrc = STAMR3Snapshot(ptrVM.rawUVM(), Utf8Str(aPattern).c_str(), &pszSnapshot, NULL, !!aWithDescriptions); if (RT_FAILURE(vrc)) return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL; @@ -1456,6 +1515,7 @@ STDMETHODIMP MachineDebugger::GetStats (IN_BSTR aPattern, BOOL aWithDescriptions * Until that's done, this method is kind of useless for debugger statistics GUI because * of the amount statistics in a debug build. */ Bstr(pszSnapshot).detachTo(aStats); + STAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot); return S_OK; } @@ -1472,16 +1532,12 @@ void MachineDebugger::flushQueuedSettings() COMSETTER(SingleStep)(mSingleStepQueued); mSingleStepQueued = ~0; } - if (mRecompileUserQueued != ~0) - { - COMSETTER(RecompileUser)(mRecompileUserQueued); - mRecompileUserQueued = ~0; - } - if (mRecompileSupervisorQueued != ~0) - { - COMSETTER(RecompileSupervisor)(mRecompileSupervisorQueued); - mRecompileSupervisorQueued = ~0; - } + for (unsigned i = 0; i < EMEXECPOLICY_END; i++) + if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX) + { + setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i])); + maiQueuedEmExecPolicyParams[i] = UINT8_MAX; + } if (mPatmEnabledQueued != ~0) { COMSETTER(PATMEnabled)(mPatmEnabledQueued); diff --git a/src/VBox/Main/src-client/MouseImpl.cpp b/src/VBox/Main/src-client/MouseImpl.cpp index 641f1ad8..652f2df3 100644 --- a/src/VBox/Main/src-client/MouseImpl.cpp +++ b/src/VBox/Main/src-client/MouseImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -36,7 +36,9 @@ enum /** The mouse device can do relative reporting */ MOUSE_DEVCAP_RELATIVE = 1, /** The mouse device can do absolute reporting */ - MOUSE_DEVCAP_ABSOLUTE = 2 + MOUSE_DEVCAP_ABSOLUTE = 2, + /** The mouse device can do absolute reporting */ + MOUSE_DEVCAP_MULTI_TOUCH = 4 }; /** @} */ @@ -75,8 +77,8 @@ Mouse::~Mouse() HRESULT Mouse::FinalConstruct() { RT_ZERO(mpDrv); - mcLastAbsX = 0x8000; - mcLastAbsY = 0x8000; + mcLastX = 0x8000; + mcLastY = 0x8000; mfLastButtons = 0; mfVMMDevGuestCaps = 0; return BaseFinalConstruct(); @@ -97,7 +99,7 @@ void Mouse::FinalRelease() * @returns COM result indicator * @param parent handle of our parent object */ -HRESULT Mouse::init (Console *parent) +HRESULT Mouse::init (ConsoleMouseInterface *parent) { LogFlowThisFunc(("\n")); @@ -109,13 +111,11 @@ HRESULT Mouse::init (Console *parent) unconst(mParent) = parent; -#ifndef VBOXBFE_WITHOUT_COM unconst(mEventSource).createObject(); - HRESULT rc = mEventSource->init(static_cast(this)); + HRESULT rc = mEventSource->init(); AssertComRCReturnRC(rc); mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse, - 0, 0, 0, 0, 0); -#endif + 0, 0, 0, 0, 0, 0); /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -143,13 +143,9 @@ void Mouse::uninit() mpDrv[i] = NULL; } -#ifdef VBOXBFE_WITHOUT_COM - mParent = NULL; -#else mMouseEvent.uninit(); unconst(mEventSource).setNull(); unconst(mParent) = NULL; -#endif } @@ -162,7 +158,7 @@ void Mouse::uninit() HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded, uint32_t fCapsRemoved) { - VMMDev *pVMMDev = mParent->getVMMDev(); + VMMDevMouseInterface *pVMMDev = mParent->getVMMDevMouseInterface(); if (!pVMMDev) return E_FAIL; /* No assertion, as the front-ends can send events * at all sorts of inconvenient times. */ @@ -176,9 +172,8 @@ HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded, } /** - * Returns whether the current setup can accept absolute mouse events, either - * because an emulated absolute pointing device is active or because the Guest - * Additions are. + * Returns whether the currently active device portfolio can accept absolute + * mouse events. * * @returns COM status code * @param absoluteSupported address of result variable @@ -196,8 +191,8 @@ STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported) } /** - * Returns whether the current setup can accept relative mouse events, that is, - * whether an emulated relative pointing device is active. + * Returns whether the currently active device portfolio can accept relative + * mouse events. * * @returns COM status code * @param relativeSupported address of result variable @@ -214,6 +209,25 @@ STDMETHODIMP Mouse::COMGETTER(RelativeSupported) (BOOL *relativeSupported) return S_OK; } +/** + * Returns whether the currently active device portfolio can accept multi-touch + * mouse events. + * + * @returns COM status code + * @param multiTouchSupported address of result variable + */ +STDMETHODIMP Mouse::COMGETTER(MultiTouchSupported) (BOOL *multiTouchSupported) +{ + if (!multiTouchSupported) + return E_POINTER; + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *multiTouchSupported = supportsMT(); + return S_OK; +} + /** * Returns whether the guest can currently switch to drawing the mouse cursor * itself if it is asked to by the front-end. @@ -255,7 +269,6 @@ static uint32_t mouseButtonsToPDM(LONG buttonState) return fButtons; } -#ifndef VBOXBFE_WITHOUT_COM STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource) { CheckComArgOutPointerValid(aEventSource); @@ -268,7 +281,6 @@ STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource) return S_OK; } -#endif /** * Send a relative pointer event to the relative device we deem most @@ -312,16 +324,16 @@ HRESULT Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz, * * @returns COM status code */ -HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs, +HRESULT Mouse::reportAbsEventToMouseDev(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons) { - if ( mouseXAbs < VMMDEV_MOUSE_RANGE_MIN - || mouseXAbs > VMMDEV_MOUSE_RANGE_MAX) + if ( x < VMMDEV_MOUSE_RANGE_MIN + || x > VMMDEV_MOUSE_RANGE_MAX) return S_OK; - if ( mouseYAbs < VMMDEV_MOUSE_RANGE_MIN - || mouseYAbs > VMMDEV_MOUSE_RANGE_MAX) + if ( y < VMMDEV_MOUSE_RANGE_MIN + || y > VMMDEV_MOUSE_RANGE_MAX) return S_OK; - if ( mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY + if ( x != mcLastX || y != mcLastY || dz || dw || fButtons != mfLastButtons) { PPDMIMOUSEPORT pUpPort = NULL; @@ -337,7 +349,7 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs, if (!pUpPort) return S_OK; - int vrc = pUpPort->pfnPutEventAbs(pUpPort, mouseXAbs, mouseYAbs, dz, + int vrc = pUpPort->pfnPutEventAbs(pUpPort, x, y, dz, dw, fButtons); if (RT_FAILURE(vrc)) return setError(VBOX_E_IPRT_ERROR, @@ -349,6 +361,44 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs, return S_OK; } +HRESULT Mouse::reportMultiTouchEventToDevice(uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime) +{ + HRESULT hrc = S_OK; + + PPDMIMOUSEPORT pUpPort = NULL; + { + AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS); + + unsigned i; + for (i = 0; i < MOUSE_MAX_DEVICES; ++i) + { + if ( mpDrv[i] + && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH)) + { + pUpPort = mpDrv[i]->pUpPort; + break; + } + } + } + + if (pUpPort) + { + int vrc = pUpPort->pfnPutEventMultiTouch(pUpPort, cContacts, pau64Contacts, u32ScanTime); + if (RT_FAILURE(vrc)) + hrc = setError(VBOX_E_IPRT_ERROR, + tr("Could not send the multi-touch event to the virtual device (%Rrc)"), + vrc); + } + else + { + hrc = E_UNEXPECTED; + } + + return hrc; +} + /** * Send an absolute position event to the VMM device. @@ -356,17 +406,17 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs, * * @returns COM status code */ -HRESULT Mouse::reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs) +HRESULT Mouse::reportAbsEventToVMMDev(int32_t x, int32_t y) { - VMMDev *pVMMDev = mParent->getVMMDev(); + VMMDevMouseInterface *pVMMDev = mParent->getVMMDevMouseInterface(); ComAssertRet(pVMMDev, E_FAIL); PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); ComAssertRet(pVMMDevPort, E_FAIL); - if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY) + if (x != mcLastX || y != mcLastY) { int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort, - mouseXAbs, mouseYAbs); + x, y); if (RT_FAILURE(vrc)) return setError(VBOX_E_IPRT_ERROR, tr("Could not send the mouse event to the virtual mouse (%Rrc)"), @@ -382,7 +432,7 @@ HRESULT Mouse::reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs) * * @returns COM status code */ -HRESULT Mouse::reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs, +HRESULT Mouse::reportAbsEvent(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons, bool fUsesVMMDevEvent) { @@ -397,40 +447,73 @@ HRESULT Mouse::reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs, /* * Send the absolute mouse position to the VMM device. */ - if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY) + if (x != mcLastX || y != mcLastY) { - rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs); + rc = reportAbsEventToVMMDev(x, y); cJiggle = !fUsesVMMDevEvent; } rc = reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons); } else - rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs, dz, dw, fButtons); + rc = reportAbsEventToMouseDev(x, y, dz, dw, fButtons); - mcLastAbsX = mouseXAbs; - mcLastAbsY = mouseYAbs; + mcLastX = x; + mcLastY = y; return rc; } -#ifndef VBOXBFE_WITHOUT_COM -void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LONG Buttons) +void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, + LONG fButtons) { /* If mouse button is pressed, we generate new event, to avoid reusable events coalescing and thus dropping key press events */ - if (Buttons != 0) + GuestMouseEventMode_T mode; + if (fAbsolute) + mode = GuestMouseEventMode_Absolute; + else + mode = GuestMouseEventMode_Relative; + + if (fButtons != 0) { VBoxEventDesc evDesc; - evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons); + evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, mode, x, y, + dz, dw, fButtons); evDesc.fire(0); } else { - mMouseEvent.reinit(VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons); + mMouseEvent.reinit(VBoxEventType_OnGuestMouse, mode, x, y, dz, dw, + fButtons); mMouseEvent.fire(0); } } -#endif +void Mouse::fireMultiTouchEvent(uint8_t cContacts, + const LONG64 *paContacts, + uint32_t u32ScanTime) +{ + com::SafeArray xPositions(cContacts); + com::SafeArray yPositions(cContacts); + com::SafeArray contactIds(cContacts); + com::SafeArray contactFlags(cContacts); + + uint8_t i; + for (i = 0; i < cContacts; i++) + { + uint32_t u32Lo = RT_LO_U32(paContacts[i]); + uint32_t u32Hi = RT_HI_U32(paContacts[i]); + xPositions[i] = (int16_t)u32Lo; + yPositions[i] = (int16_t)(u32Lo >> 16); + contactIds[i] = RT_BYTE1(u32Hi); + contactFlags[i] = RT_BYTE2(u32Hi); + } + + VBoxEventDesc evDesc; + evDesc.init(mEventSource, VBoxEventType_OnGuestMultiTouch, + cContacts, ComSafeArrayAsInParam(xPositions), ComSafeArrayAsInParam(yPositions), + ComSafeArrayAsInParam(contactIds), ComSafeArrayAsInParam(contactFlags), u32ScanTime); + evDesc.fire(0); +} /** * Send a relative mouse event to the guest. @@ -442,25 +525,26 @@ void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LON * @param dx X movement * @param dy Y movement * @param dz Z movement - * @param buttonState The mouse button state + * @param fButtons The mouse button state */ -STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState) +STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, + LONG fButtons) { HRESULT rc; - uint32_t fButtons; + uint32_t fButtonsAdj; AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__, dx, dy, dz, dw)); - fButtons = mouseButtonsToPDM(buttonState); + fButtonsAdj = mouseButtonsToPDM(fButtons); /* Make sure that the guest knows that we are sending real movement * events to the PS/2 device and not just dummy wake-up ones. */ updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE); - rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons); + rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtonsAdj); - fireMouseEvent(false, dx, dy, dz, dw, buttonState); + fireMouseEvent(false, dx, dy, dz, dw, fButtons); return rc; } @@ -480,13 +564,13 @@ STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG butto * * @returns COM status value */ -HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY, +HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj, bool *pfValid) { - AssertPtrReturn(pcX, E_POINTER); - AssertPtrReturn(pcY, E_POINTER); + AssertPtrReturn(pxAdj, E_POINTER); + AssertPtrReturn(pyAdj, E_POINTER); AssertPtrNullReturn(pfValid, E_POINTER); - Display *pDisplay = mParent->getDisplay(); + DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); ComAssertRet(pDisplay, E_FAIL); /** The amount to add to the result (multiplied by the screen width/height) * to compensate for differences in guest methods for mapping back to @@ -499,27 +583,29 @@ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY, { ULONG displayWidth, displayHeight; /* Takes the display lock */ - HRESULT rc = pDisplay->GetScreenResolution(0, &displayWidth, - &displayHeight, NULL); + HRESULT rc = pDisplay->getScreenResolution(0, &displayWidth, + &displayHeight, NULL, NULL, NULL); if (FAILED(rc)) return rc; - *pcX = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) - / (LONG) displayWidth: 0; - *pcY = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) - / (LONG) displayHeight: 0; + *pxAdj = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) + / (LONG) displayWidth: 0; + *pyAdj = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) + / (LONG) displayHeight: 0; } else { int32_t x1, y1, x2, y2; /* Takes the display lock */ pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2); - *pcX = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) - / (x2 - x1) : 0; - *pcY = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) - / (y2 - y1) : 0; - if ( *pcX < VMMDEV_MOUSE_RANGE_MIN || *pcX > VMMDEV_MOUSE_RANGE_MAX - || *pcY < VMMDEV_MOUSE_RANGE_MIN || *pcY > VMMDEV_MOUSE_RANGE_MAX) + *pxAdj = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) + / (x2 - x1) : 0; + *pyAdj = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) + / (y2 - y1) : 0; + if ( *pxAdj < VMMDEV_MOUSE_RANGE_MIN + || *pxAdj > VMMDEV_MOUSE_RANGE_MAX + || *pyAdj < VMMDEV_MOUSE_RANGE_MIN + || *pyAdj > VMMDEV_MOUSE_RANGE_MAX) if (pfValid) *pfValid = false; } @@ -540,47 +626,209 @@ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY, * @param x X position (pixel), starting from 1 * @param y Y position (pixel), starting from 1 * @param dz Z movement - * @param buttonState The mouse button state + * @param fButtons The mouse button state */ STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw, - LONG buttonState) + LONG fButtons) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, buttonState=0x%x\n", - __PRETTY_FUNCTION__, x, y, dz, dw, buttonState)); + LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, fButtons=0x%x\n", + __PRETTY_FUNCTION__, x, y, dz, dw, fButtons)); - int32_t mouseXAbs, mouseYAbs; - uint32_t fButtons; + int32_t xAdj, yAdj; + uint32_t fButtonsAdj; bool fValid; /** @todo the front end should do this conversion to avoid races */ /** @note Or maybe not... races are pretty inherent in everything done in * this object and not really bad as far as I can see. */ - HRESULT rc = convertDisplayRes(x, y, &mouseXAbs, &mouseYAbs, &fValid); + HRESULT rc = convertDisplayRes(x, y, &xAdj, &yAdj, &fValid); if (FAILED(rc)) return rc; - fButtons = mouseButtonsToPDM(buttonState); + fButtonsAdj = mouseButtonsToPDM(fButtons); /* If we are doing old-style (IRQ-less) absolute reporting to the VMM * device then make sure the guest is aware of it, so that it knows to * ignore relative movement on the PS/2 device. */ updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0); if (fValid) { - rc = reportAbsEvent(mouseXAbs, mouseYAbs, dz, dw, fButtons, + rc = reportAbsEvent(xAdj, yAdj, dz, dw, fButtonsAdj, RT_BOOL( mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL)); - fireMouseEvent(true, x, y, dz, dw, buttonState); + fireMouseEvent(true, x, y, dz, dw, fButtons); } return rc; } +/** + * Send a multi-touch event. This requires multi-touch pointing device emulation. + * @note all calls out of this object are made with no locks held! + * + * @returns COM status code. + * @param aCount Number of contacts. + * @param aContacts Information about each contact. + * @param aScanTime Timestamp. + */ +STDMETHODIMP Mouse::PutEventMultiTouch(LONG aCount, + ComSafeArrayIn(LONG64, aContacts), + ULONG aScanTime) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + com::SafeArray arrayContacts(ComSafeArrayInArg(aContacts)); + + LogRel3(("%s: aCount %d(actual %d), aScanTime %u\n", + __FUNCTION__, aCount, arrayContacts.size(), aScanTime)); + + HRESULT rc = S_OK; + + if ((LONG)arrayContacts.size() >= aCount) + { + LONG64* paContacts = arrayContacts.raw(); + + rc = putEventMultiTouch(aCount, paContacts, aScanTime); + } + else + { + rc = E_INVALIDARG; + } + + return rc; +} + +/** + * Send a multi-touch event. Version for scripting languages. + * + * @returns COM status code. + * @param aCount Number of contacts. + * @param aContacts Information about each contact. + * @param aScanTime Timestamp. + */ +STDMETHODIMP Mouse::PutEventMultiTouchString(LONG aCount, + IN_BSTR aContacts, + ULONG aScanTime) +{ + /** @todo implement: convert the string to LONG64 array and call putEventMultiTouch. */ + NOREF(aCount); + NOREF(aContacts); + NOREF(aScanTime); + return E_NOTIMPL; +} + + // private methods ///////////////////////////////////////////////////////////////////////////// +/* Used by PutEventMultiTouch and PutEventMultiTouchString. */ +HRESULT Mouse::putEventMultiTouch(LONG aCount, + LONG64 *paContacts, + ULONG aScanTime) +{ + if (aCount >= 256) + { + return E_INVALIDARG; + } + + DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); + ComAssertRet(pDisplay, E_FAIL); + + /* Touch events are mapped to the primary monitor, because the emulated USB + * touchscreen device is associated with one (normally the primary) screen in the guest. + */ + ULONG uScreenId = 0; + + ULONG cWidth = 0; + ULONG cHeight = 0; + LONG xOrigin = 0; + LONG yOrigin = 0; + HRESULT rc = pDisplay->getScreenResolution(uScreenId, &cWidth, &cHeight, NULL, &xOrigin, &yOrigin); + ComAssertComRCRetRC(rc); + + uint64_t* pau64Contacts = NULL; + uint8_t cContacts = 0; + + /* Deliver 0 contacts too, touch device may use this to reset the state. */ + if (aCount > 0) + { + /* Create a copy with converted coords. */ + pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t)); + if (pau64Contacts) + { + int32_t x1 = xOrigin; + int32_t y1 = yOrigin; + int32_t x2 = x1 + cWidth; + int32_t y2 = y1 + cHeight; + + LogRel3(("%s: screen [%d] %d,%d %d,%d\n", + __FUNCTION__, uScreenId, x1, y1, x2, y2)); + + LONG i; + for (i = 0; i < aCount; i++) + { + uint32_t u32Lo = RT_LO_U32(paContacts[i]); + uint32_t u32Hi = RT_HI_U32(paContacts[i]); + int32_t x = (int16_t)u32Lo; + int32_t y = (int16_t)(u32Lo >> 16); + uint8_t contactId = RT_BYTE1(u32Hi); + bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0; + bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0; + + LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n", + __FUNCTION__, i, x, y, contactId, fInContact, fInRange)); + + /* x1,y1 are inclusive and x2,y2 are exclusive, + * while x,y start from 1 and are inclusive. + */ + if (x <= x1 || x > x2 || y <= y1 || y > y2) + { + /* Out of range. Skip the contact. */ + continue; + } + + int32_t xAdj = x1 < x2? ((x - 1 - x1) * VMMDEV_MOUSE_RANGE) / (x2 - x1) : 0; + int32_t yAdj = y1 < y2? ((y - 1 - y1) * VMMDEV_MOUSE_RANGE) / (y2 - y1) : 0; + + bool fValid = ( xAdj >= VMMDEV_MOUSE_RANGE_MIN + && xAdj <= VMMDEV_MOUSE_RANGE_MAX + && yAdj >= VMMDEV_MOUSE_RANGE_MIN + && yAdj <= VMMDEV_MOUSE_RANGE_MAX); + + if (fValid) + { + uint8_t fu8 = (fInContact? 0x01: 0x00) + | (fInRange? 0x02: 0x00); + pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj, + (uint16_t)yAdj, + RT_MAKE_U16(contactId, fu8), + 0); + cContacts++; + } + } + } + else + { + rc = E_OUTOFMEMORY; + } + } + + if (SUCCEEDED(rc)) + { + rc = reportMultiTouchEventToDevice(cContacts, cContacts? pau64Contacts: NULL, (uint32_t)aScanTime); + + /* Send the original contact information. */ + fireMultiTouchEvent(cContacts, cContacts? paContacts: NULL, (uint32_t)aScanTime); + } + + RTMemTmpFree(pau64Contacts); + + return rc; +} + /** Does the guest currently rely on the host to draw the mouse cursor or * can it switch to doing it itself in software? */ @@ -592,10 +840,11 @@ bool Mouse::guestNeedsHostCursor(void) /** Check what sort of reporting can be done using the devices currently * enabled. Does not consider the VMM device. */ -void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel) +void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel, bool *pfMT) { bool fAbsDev = false; bool fRelDev = false; + bool fMTDev = false; AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS); @@ -606,11 +855,15 @@ void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel) fAbsDev = true; if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE) fRelDev = true; + if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH) + fMTDev = true; } if (pfAbs) *pfAbs = fAbsDev; if (pfRel) *pfRel = fRelDev; + if (pfMT) + *pfMT = fMTDev; } @@ -619,7 +872,7 @@ bool Mouse::vmmdevCanAbs(void) { bool fRelDev; - getDeviceCaps(NULL, &fRelDev); + getDeviceCaps(NULL, &fRelDev, NULL); return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE) && fRelDev; } @@ -630,7 +883,7 @@ bool Mouse::deviceCanAbs(void) { bool fAbsDev; - getDeviceCaps(&fAbsDev, NULL); + getDeviceCaps(&fAbsDev, NULL, NULL); return fAbsDev; } @@ -640,7 +893,7 @@ bool Mouse::supportsRel(void) { bool fRelDev; - getDeviceCaps(NULL, &fRelDev); + getDeviceCaps(NULL, &fRelDev, NULL); return fRelDev; } @@ -650,22 +903,32 @@ bool Mouse::supportsAbs(void) { bool fAbsDev; - getDeviceCaps(&fAbsDev, NULL); + getDeviceCaps(&fAbsDev, NULL, NULL); return fAbsDev || vmmdevCanAbs(); } +/** Can we currently send absolute events to the guest? */ +bool Mouse::supportsMT(void) +{ + bool fMTDev; + + getDeviceCaps(NULL, NULL, &fMTDev); + return fMTDev; +} + + /** Check what sort of reporting can be done using the devices currently * enabled (including the VMM device) and notify the guest and the front-end. */ void Mouse::sendMouseCapsNotifications(void) { - bool fAbsDev, fRelDev, fCanAbs, fNeedsHostCursor; + bool fAbsDev, fRelDev, fMTDev, fCanAbs, fNeedsHostCursor; { AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS); - getDeviceCaps(&fAbsDev, &fRelDev); + getDeviceCaps(&fAbsDev, &fRelDev, &fMTDev); fCanAbs = supportsAbs(); fNeedsHostCursor = guestNeedsHostCursor(); } @@ -676,7 +939,7 @@ void Mouse::sendMouseCapsNotifications(void) /** @todo this call takes the Console lock in order to update the cached * callback data atomically. However I can't see any sign that the cached * data is ever used again. */ - mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fNeedsHostCursor); + mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fMTDev, fNeedsHostCursor); } @@ -684,7 +947,7 @@ void Mouse::sendMouseCapsNotifications(void) * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes} * A virtual device is notifying us about its current state and capabilities */ -DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs) +DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs, bool fMT) { PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector); if (fRel) @@ -695,6 +958,10 @@ DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE; else pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE; + if (fMT) + pDrv->u32DevCaps |= MOUSE_DEVCAP_MULTI_TOUCH; + else + pDrv->u32DevCaps &= ~MOUSE_DEVCAP_MULTI_TOUCH; pDrv->pMouse->sendMouseCapsNotifications(); } @@ -722,17 +989,17 @@ DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, const char */ DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns) { - PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE); - LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE); + LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); - if (pData->pMouse) + if (pThis->pMouse) { - AutoWriteLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS); + AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS); for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev) - if (pData->pMouse->mpDrv[cDev] == pData) + if (pThis->pMouse->mpDrv[cDev] == pThis) { - pData->pMouse->mpDrv[cDev] = NULL; + pThis->pMouse->mpDrv[cDev] = NULL; break; } } @@ -746,9 +1013,9 @@ DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { - PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE); - LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE); + LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. @@ -764,13 +1031,13 @@ DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32 */ pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface; - pData->IConnector.pfnReportModes = Mouse::mouseReportModes; + pThis->IConnector.pfnReportModes = Mouse::mouseReportModes; /* * Get the IMousePort interface of the above driver/device. */ - pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID); - if (!pData->pUpPort) + pThis->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID); + if (!pThis->pUpPort) { AssertMsgFailed(("Configuration error: No mouse port interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; @@ -786,15 +1053,15 @@ DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc)); return rc; } - pData->pMouse = (Mouse *)pv; /** @todo Check this cast! */ + pThis->pMouse = (Mouse *)pv; /** @todo Check this cast! */ unsigned cDev; { - AutoReadLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS); + AutoReadLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS); for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev) - if (!pData->pMouse->mpDrv[cDev]) + if (!pThis->pMouse->mpDrv[cDev]) { - pData->pMouse->mpDrv[cDev] = pData; + pThis->pMouse->mpDrv[cDev] = pThis; break; } } diff --git a/src/VBox/Main/src-client/Nvram.cpp b/src/VBox/Main/src-client/Nvram.cpp index d1c2a8a4..d3d4200f 100644 --- a/src/VBox/Main/src-client/Nvram.cpp +++ b/src/VBox/Main/src-client/Nvram.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,6 +20,7 @@ *******************************************************************************/ #include "Nvram.h" #include "ConsoleImpl.h" +#include "Global.h" #include #include @@ -44,21 +45,43 @@ typedef struct NVRAM NVRAM; typedef struct NVRAM *PNVRAM; +/** + * Intstance data associated with PDMDRVINS. + */ struct NVRAM { - Nvram *pNvram; - PDMINVRAM INvram; - int cLoadedVariables; - bool fPermanentSave; + /** Pointer to the associated class instance. */ + Nvram *pNvram; + /** The NVRAM connector interface we provide to DevEFI. */ + PDMINVRAMCONNECTOR INvramConnector; + /** The root of the 'Vars' child of the driver config (i.e. + * VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/). + * This node has one child node per NVRAM variable. */ + PCFGMNODE pCfgVarRoot; + /** The variable node used in the privous drvNvram_VarQueryByIndex call. */ + PCFGMNODE pLastVarNode; + /** The index pLastVarNode corresponds to. */ + uint32_t idxLastVar; + /** Whether to permanently save the variables or not. */ + bool fPermanentSave; }; +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** The default NVRAM attribute value (non-volatile, boot servier access, + runtime access). */ +#define NVRAM_DEFAULT_ATTRIB UINT32_C(0x7) +/** The CFGM overlay path of the NVRAM variables. */ +#define NVRAM_CFGM_OVERLAY_PATH "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars" + /** * Constructor/destructor */ -Nvram::Nvram(Console *console) - : mpDrv(NULL), - mParent(console) +Nvram::Nvram(Console *pConsole) + : mParent(pConsole), + mpDrv(NULL) { } @@ -73,149 +96,216 @@ Nvram::~Nvram() /** - * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue) + * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqEnd) + */ +DECLCALLBACK(int) drvNvram_VarStoreSeqEnd(PPDMINVRAMCONNECTOR pInterface, int rc) +{ + NOREF(pInterface); + return rc; +} + +/** + * Converts the binary to a CFGM overlay binary string. + * + * @returns Pointer to a heap buffer (hand it to RTMemFree when done). + * @param pvBuf The binary data to convert. + * @param cbBuf The number of bytes to convert. */ -DECLCALLBACK(int) drvNvram_pfnStoreNvramValue(PPDMINVRAM pInterface, - int idxVariable, - RTUUID *pVendorUuid, - const char *pcszVariableName, - size_t cbVariableName, - uint8_t *pu8Value, - size_t cbValue) +static char *drvNvram_binaryToCfgmString(void const *pvBuf, size_t cbBuf) { - int rc = VINF_SUCCESS; - char szExtraDataKey[256]; - char szExtraDataValue[1024]; - LogFlowFunc(("ENTER: pVendorUuid:%RTuuid, pcszVariableName:%s, cbVariableName:%d, pu8Value:%.*Rhxs, cbValue:%d\n", - pVendorUuid, - pcszVariableName, - cbVariableName, - cbValue, - pu8Value, - cbValue)); - PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram); - if (!pThis->fPermanentSave) + static char s_szPrefix[] = "bytes:"; + size_t cbStr = RTBase64EncodedLength(cbBuf) + sizeof(s_szPrefix); + char *pszStr = (char *)RTMemAlloc(cbStr); + if (pszStr) { - LogFlowFuncLeaveRC(rc); - return rc; + memcpy(pszStr, s_szPrefix, sizeof(s_szPrefix) - 1); + int rc = RTBase64Encode(pvBuf, cbBuf, &pszStr[sizeof(s_szPrefix) - 1], cbStr - sizeof(s_szPrefix) + 1, NULL); + if (RT_FAILURE(rc)) + { + RTMemFree(pszStr); + pszStr = NULL; + } } + return pszStr; +} - bool fFlushVariable = (!pu8Value); - - RT_ZERO(szExtraDataKey); - RT_ZERO(szExtraDataValue); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable); - if (!fFlushVariable) - RTStrPrintf(szExtraDataValue, 1024, "%s", pcszVariableName); - pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw()); - - RT_ZERO(szExtraDataKey); - RT_ZERO(szExtraDataValue); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable); - if (!fFlushVariable) - RTUuidToStr(pVendorUuid, szExtraDataValue, 1024); - pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw()); - - RT_ZERO(szExtraDataKey); - RT_ZERO(szExtraDataValue); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable); - if (!fFlushVariable) - RTStrPrintf(szExtraDataValue, 1024, "%d", cbValue); - pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw()); - - RT_ZERO(szExtraDataKey); - RT_ZERO(szExtraDataValue); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable); - size_t cbActualSize; - if (pu8Value) - rc = RTBase64Encode(pu8Value, cbValue, szExtraDataValue, 1024, &cbActualSize); - AssertRCReturn(rc, rc); - pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw()); +/** + * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqPut) + */ +DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable, + PCRTUUID pVendorUuid, const char *pszName, size_t cchName, + uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue) +{ + PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector); + int rc = VINF_SUCCESS; + if (pThis->fPermanentSave && pThis->pNvram) + { + char szExtraName[256]; + size_t offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16, + NVRAM_CFGM_OVERLAY_PATH "/%04u/", idxVariable); + + char szUuid[RTUUID_STR_LENGTH]; + int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2); + + char szAttribs[32]; + if (fAttributes != NVRAM_DEFAULT_ATTRIB) + RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes); + else + szAttribs[0] = '\0'; + + char *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue); + if (pszValue) + { + const char *apszTodo[] = + { + "Name", pszName, + "Uuid", szUuid, + "Value", pszValue, + "Attribs", szAttribs, + }; + for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2) + { + if (!apszTodo[i + 1][0]) + continue; + + Assert(strlen(apszTodo[i]) < 16); + strcpy(szExtraName + offValueNm, apszTodo[i]); + try + { + HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(), + Bstr(apszTodo[i + 1]).raw()); + if (FAILED(hrc)) + { + LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc)); + rc = Global::vboxStatusCodeFromCOM(hrc); + } + } + catch (...) + { + LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1])); + rc = VERR_UNEXPECTED_EXCEPTION; + } + } + } + else + rc = VERR_NO_MEMORY; + RTMemFree(pszValue); + } + + NOREF(cchName); LogFlowFuncLeaveRC(rc); return rc; } - /** - * @interface_method_impl(PDMINVRAM,pfnFlushNvramStorage) + * Deletes a variable. + * + * @param pThis The NVRAM driver instance data. + * @param pszVarNodeNm The variable node name. */ -DECLCALLBACK(int) drvNvram_pfnFlushNvramStorage(PPDMINVRAM pInterface) +static void drvNvram_deleteVar(PNVRAM pThis, const char *pszVarNodeNm) { - int rc = VINF_SUCCESS; - LogFlowFuncEnter(); - PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram); - if (!pThis->fPermanentSave) + char szExtraName[256]; + size_t offValue = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16, NVRAM_CFGM_OVERLAY_PATH "/%s/", pszVarNodeNm); + static const char *s_apszValueNames[] = { "Name", "Uuid", "Value", "Attribs" }; + for (unsigned i = 0; i < RT_ELEMENTS(s_apszValueNames); i++) { - LogFlowFuncLeaveRC(rc); - return rc; + Assert(strlen(s_apszValueNames[i]) < 16); + strcpy(szExtraName + offValue, s_apszValueNames[i]); + try + { + HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(), Bstr().raw()); + if (FAILED(hrc)) + LogRel(("drvNvram_deleteVar: SetExtraData(%s,) returned %Rhrc\n", szExtraName, hrc)); + } + catch (...) + { + LogRel(("drvNvram_deleteVar: SetExtraData(%s,) threw exception\n", szExtraName)); + } } +} - for (int idxVariable = 0; idxVariable < pThis->cLoadedVariables; ++idxVariable) +/** + * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqBegin) + */ +DECLCALLBACK(int) drvNvram_VarStoreSeqBegin(PPDMINVRAMCONNECTOR pInterface, uint32_t cVariables) +{ + PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector); + int rc = VINF_SUCCESS; + if (pThis->fPermanentSave && pThis->pNvram) { - drvNvram_pfnStoreNvramValue(pInterface, idxVariable, NULL, NULL, 0, NULL, 0); + /* + * Remove all existing variables. + */ + for (PCFGMNODE pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot); pVarNode; pVarNode = CFGMR3GetNextChild(pVarNode)) + { + char szName[128]; + rc = CFGMR3GetName(pVarNode, szName, sizeof(szName)); + if (RT_SUCCESS(rc)) + drvNvram_deleteVar(pThis, szName); + else + LogRel(("drvNvram_VarStoreSeqBegin: CFGMR3GetName -> %Rrc\n", rc)); + } } - LogFlowFuncLeaveRC(rc); + + NOREF(cVariables); return rc; } - /** - * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue) + * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex) */ -DECLCALLBACK(int) drvNvram_pfnLoadNvramValue(PPDMINVRAM pInterface, - int idxVariable, - RTUUID *pVendorUuid, - char *pcszVariableName, - size_t *pcbVariableName, - uint8_t *pu8Value, - size_t *pcbValue) +DECLCALLBACK(int) drvNvram_VarQueryByIndex(PPDMINVRAMCONNECTOR pInterface, uint32_t idxVariable, + PRTUUID pVendorUuid, char *pszName, uint32_t *pcchName, + uint32_t *pfAttributes, uint8_t *pbValue, uint32_t *pcbValue) { - int rc = VINF_SUCCESS; - char szExtraDataKey[256]; - Bstr bstrValue; - HRESULT hrc; - LogFlowFunc(("ENTER: idxVariable:%d, *pcbVariableName:%d, *pcbValue:%d\n", - idxVariable, - *pcbVariableName, - *pcbValue)); - PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram); - if (!pThis->fPermanentSave) + PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector); + + /* + * Find the requested variable node. + */ + PCFGMNODE pVarNode; + if (pThis->idxLastVar + 1 == idxVariable && pThis->pLastVarNode) + pVarNode = CFGMR3GetNextChild(pThis->pLastVarNode); + else { - rc = VERR_NOT_FOUND; - LogFlowFuncLeaveRC(rc); - return rc; + pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot); + for (uint32_t i = 0; i < idxVariable && pVarNode; i++) + pVarNode = CFGMR3GetNextChild(pVarNode); } + if (!pVarNode) + return VERR_NOT_FOUND; + /* cache it */ + pThis->pLastVarNode = pVarNode; + pThis->idxLastVar = idxVariable; - RT_ZERO(szExtraDataKey); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable); - hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam()); - if (!SUCCEEDED(hrc)) - return VERR_NOT_FOUND; - *pcbVariableName = RTStrCopy(pcszVariableName, 1024, Utf8Str(bstrValue).c_str()); - - RT_ZERO(szExtraDataKey); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable); - hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam()); - RTUuidFromStr(pVendorUuid, Utf8Str(bstrValue).c_str()); - -#if 0 - RT_ZERO(szExtraDataKey); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable); - hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam()); - *pcbValue = Utf8Str(bstrValue).toUInt32(); -#endif - - RT_ZERO(szExtraDataKey); - RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable); - hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam()); - rc = RTBase64Decode(Utf8Str(bstrValue).c_str(), pu8Value, 1024, pcbValue, NULL); + /* + * Read the variable node. + */ + int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName); AssertRCReturn(rc, rc); + *pcchName = (uint32_t)strlen(pszName); - pThis->cLoadedVariables++; - LogFlowFuncLeaveRC(rc); - return rc; + char szUuid[RTUUID_STR_LENGTH]; + rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid)); + AssertRCReturn(rc, rc); + rc = RTUuidFromStr(pVendorUuid, szUuid); + AssertRCReturn(rc, rc); + + rc = CFGMR3QueryU32Def(pVarNode, "Attribs", pfAttributes, NVRAM_DEFAULT_ATTRIB); + AssertRCReturn(rc, rc); + + size_t cbValue; + rc = CFGMR3QuerySize(pVarNode, "Value", &cbValue); + AssertRCReturn(rc, rc); + AssertReturn(cbValue <= *pcbValue, VERR_BUFFER_OVERFLOW); + rc = CFGMR3QueryBytes(pVarNode, "Value", pbValue, cbValue); + AssertRCReturn(rc, rc); + *pcbValue = (uint32_t)cbValue; + + return VINF_SUCCESS; } @@ -229,7 +319,7 @@ DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM); PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); - PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAM, &pThis->INvram); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector); return NULL; } @@ -239,8 +329,11 @@ DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const */ DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns) { + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); LogFlow(("%s: iInstance/#d\n", __FUNCTION__, pDrvIns->iInstance)); PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM); + if (pThis->pNvram != NULL) + pThis->pNvram->mpDrv = NULL; } @@ -249,9 +342,29 @@ DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); LogFlowFunc(("iInstance/#d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags)); PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM); + /* + * Initalize instance data variables first. + */ + //pThis->pNvram = NULL; + //pThis->cLoadedVariables = 0; + //pThis->fPermanentSave = false; + pThis->pCfgVarRoot = CFGMR3GetChild(pCfg, "Vars"); + //pThis->pLastVarNode = NULL; + pThis->idxLastVar = UINT32_MAX / 2; + + pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface; + pThis->INvramConnector.pfnVarQueryByIndex = drvNvram_VarQueryByIndex; + pThis->INvramConnector.pfnVarStoreSeqBegin = drvNvram_VarStoreSeqBegin; + pThis->INvramConnector.pfnVarStoreSeqPut = drvNvram_VarStoreSeqPut; + pThis->INvramConnector.pfnVarStoreSeqEnd = drvNvram_VarStoreSeqEnd; + + /* + * Validate and read configuration. + */ if (!CFGMR3AreValuesValid(pCfg, "Object\0" "PermanentSave\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; @@ -259,23 +372,16 @@ DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, ("Configuration error: Not possible to attach anything to this driver!\n"), VERR_PDM_DRVINS_NO_ATTACH); - void *pv; - int rc = CFGMR3QueryPtr(pCfg, "Object", &pv); + int rc = CFGMR3QueryPtr(pCfg, "Object", (void **)&pThis->pNvram); AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc); - pThis->pNvram = (Nvram *)pv; - bool fPermanentSave = false; - rc = CFGMR3QueryBool(pCfg, "PermanentSave", &fPermanentSave); - if ( RT_SUCCESS(rc) - || rc == VERR_CFGM_VALUE_NOT_FOUND) - pThis->fPermanentSave = fPermanentSave; - else - AssertRCReturn(rc, rc); + rc = CFGMR3QueryBoolDef(pCfg, "PermanentSave", &pThis->fPermanentSave, false); + AssertRCReturn(rc, rc); - pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface; - pThis->INvram.pfnFlushNvramStorage = drvNvram_pfnFlushNvramStorage; - pThis->INvram.pfnStoreNvramValue = drvNvram_pfnStoreNvramValue; - pThis->INvram.pfnLoadNvramValue = drvNvram_pfnLoadNvramValue; + /* + * Let the associated class instance know about us. + */ + pThis->pNvram->mpDrv = pThis; return VINF_SUCCESS; } diff --git a/src/VBox/Main/src-client/PCIRawDevImpl.cpp b/src/VBox/Main/src-client/PCIRawDevImpl.cpp index 35617c8a..b60adf43 100644 --- a/src/VBox/Main/src-client/PCIRawDevImpl.cpp +++ b/src/VBox/Main/src-client/PCIRawDevImpl.cpp @@ -14,6 +14,7 @@ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ + #include "Logging.h" #include "PCIRawDevImpl.h" #include "PCIDeviceAttachmentImpl.h" @@ -104,41 +105,33 @@ DECLCALLBACK(int) PCIRawDev::drvDeviceConstructComplete(PPDMIPCIRAWCONNECTOR pIn /** - * Destruct a PCI raw driver instance. - * - * @returns VBox status. - * @param pDrvIns The driver instance data. + * @interface_method_impl{PDMDRVREG,pfnReset} */ -DECLCALLBACK(void) PCIRawDev::drvDestruct(PPDMDRVINS pDrvIns) +DECLCALLBACK(void) PCIRawDev::drvReset(PPDMDRVINS pDrvIns) { - PDRVMAINPCIRAWDEV pData = PDMINS_2_DATA(pDrvIns, PDRVMAINPCIRAWDEV); - PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); - - if (pData->pPCIRawDev) - pData->pPCIRawDev->mpDrv = NULL; } /** - * Reset notification. - * - * @returns VBox status. - * @param pDrvIns The driver instance data. + * @interface_method_impl{PDMDRVREG,pfnReset} */ -DECLCALLBACK(void) PCIRawDev::drvReset(PPDMDRVINS pDrvIns) +DECLCALLBACK(void) PCIRawDev::drvDestruct(PPDMDRVINS pDrvIns) { + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINPCIRAWDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINPCIRAWDEV); + + if (pThis->pPCIRawDev) + pThis->pPCIRawDev->mpDrv = NULL; } /** - * Construct a raw PCI driver instance. - * - * @copydoc FNPDMDRVCONSTRUCT + * @interface_method_impl{PDMDRVREG,pfnConstruct} */ DECLCALLBACK(int) PCIRawDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags) { - PDRVMAINPCIRAWDEV pData = PDMINS_2_DATA(pDrvIns, PDRVMAINPCIRAWDEV); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINPCIRAWDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINPCIRAWDEV); /* * Validate configuration. @@ -158,7 +151,7 @@ DECLCALLBACK(int) PCIRawDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHand /* * IConnector. */ - pData->IConnector.pfnDeviceConstructComplete = PCIRawDev::drvDeviceConstructComplete; + pThis->IConnector.pfnDeviceConstructComplete = PCIRawDev::drvDeviceConstructComplete; /* * Get the object pointer and update the mpDrv member. @@ -171,8 +164,8 @@ DECLCALLBACK(int) PCIRawDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHand return rc; } - pData->pPCIRawDev = (PCIRawDev *)pv; - pData->pPCIRawDev->mpDrv = pData; + pThis->pPCIRawDev = (PCIRawDev *)pv; + pThis->pPCIRawDev->mpDrv = pThis; return VINF_SUCCESS; } @@ -227,3 +220,4 @@ const PDMDRVREG PCIRawDev::DrvReg = /* u32EndVersion */ PDM_DRVREG_VERSION }; + diff --git a/src/VBox/Main/src-client/RemoteUSBBackend.cpp b/src/VBox/Main/src-client/RemoteUSBBackend.cpp index c8d7811f..83d30b15 100644 --- a/src/VBox/Main/src-client/RemoteUSBBackend.cpp +++ b/src/VBox/Main/src-client/RemoteUSBBackend.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -900,7 +900,7 @@ bool RemoteUSBBackend::addUUID (const Guid *pUuid) unsigned i; for (i = 0; i < RT_ELEMENTS(aGuids); i++) { - if (aGuids[i].isEmpty ()) + if (aGuids[i].isZero()) { aGuids[i] = *pUuid; return true; @@ -961,7 +961,7 @@ RemoteUSBBackend::RemoteUSBBackend(Console *console, ConsoleVRDPServer *server, if (RT_FAILURE(rc)) { AssertFailed (); - memset (&mCritsect, 0, sizeof (mCritsect)); + RT_ZERO(mCritsect); } mCallback.pInstance = (PREMOTEUSBBACKEND)this; @@ -1320,7 +1320,7 @@ int RemoteUSBBackend::reapURB (const void *pvBody, uint32_t cbBody) /* And insert it to its new place. */ if (pDevice->pHeadQURBs->fCompleted) { - /* At least one other completed URB; insert after the + /* At least one other completed URB; insert after the * last completed URB. */ REMOTEUSBQURB *prev_qurb = pDevice->pHeadQURBs; @@ -1341,7 +1341,7 @@ int RemoteUSBBackend::reapURB (const void *pvBody, uint32_t cbBody) /* No other completed URBs; insert at head. */ qurb->next = pDevice->pHeadQURBs; qurb->prev = NULL; - + pDevice->pHeadQURBs->prev = qurb; pDevice->pHeadQURBs = qurb; } diff --git a/src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp b/src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp index 92a2338c..99986690 100644 --- a/src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp +++ b/src/VBox/Main/src-client/RemoteUSBDeviceImpl.cpp @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-client/SessionImpl.cpp b/src/VBox/Main/src-client/SessionImpl.cpp index 5c030550..6d2cbbd0 100644 --- a/src/VBox/Main/src-client/SessionImpl.cpp +++ b/src/VBox/Main/src-client/SessionImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -15,17 +15,10 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER -# include -# include -# include -# include -# include -#endif - #include "SessionImpl.h" #include "ConsoleImpl.h" #include "Global.h" +#include "ClientTokenHolder.h" #include "AutoCaller.h" #include "Logging.h" @@ -33,11 +26,6 @@ #include #include -#if defined(RT_OS_WINDOWS) || defined (RT_OS_OS2) -/** VM IPC mutex holder thread */ -static DECLCALLBACK(int) IPCMutexHolderThread(RTTHREAD Thread, void *pvUser); -#endif - /** * Local macro to check whether the session is open and return an error if not. * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this @@ -89,17 +77,7 @@ HRESULT Session::init() mState = SessionState_Unlocked; mType = SessionType_Null; -#if defined(RT_OS_WINDOWS) - mIPCSem = NULL; - mIPCThreadSem = NULL; -#elif defined(RT_OS_OS2) - mIPCThread = NIL_RTTHREAD; - mIPCThreadSem = NIL_RTSEMEVENT; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - mIPCSem = -1; -#else -# error "Port me!" -#endif + mClientTokenHolder = NULL; /* Confirm a successful initialization when it's the case */ autoInitSpan.setSucceeded(); @@ -186,16 +164,21 @@ STDMETHODIMP Session::COMGETTER(Machine)(IMachine **aMachine) CHECK_OPEN(); HRESULT rc; +#ifndef VBOX_COM_INPROC_API_CLIENT if (mConsole) rc = mConsole->machine().queryInterfaceTo(aMachine); else +#endif rc = mRemoteMachine.queryInterfaceTo(aMachine); if (FAILED(rc)) { /** @todo VBox 3.3: replace E_FAIL with rc here. */ +#ifndef VBOX_COM_INPROC_API_CLIENT if (mConsole) setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc); - else if (FAILED_DEAD_INTERFACE(rc)) + else +#endif + if (FAILED_DEAD_INTERFACE(rc)) setError(E_FAIL, tr("Peer process crashed")); else setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc); @@ -216,17 +199,22 @@ STDMETHODIMP Session::COMGETTER(Console)(IConsole **aConsole) CHECK_OPEN(); HRESULT rc; +#ifndef VBOX_COM_INPROC_API_CLIENT if (mConsole) rc = mConsole.queryInterfaceTo(aConsole); else +#endif rc = mRemoteConsole.queryInterfaceTo(aConsole); if (FAILED(rc)) { /** @todo VBox 3.3: replace E_FAIL with rc here. */ +#ifndef VBOX_COM_INPROC_API_CLIENT if (mConsole) setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc); - else if (FAILED_DEAD_INTERFACE(rc)) + else +#endif + if (FAILED_DEAD_INTERFACE(rc)) setError(E_FAIL, tr("Peer process crashed")); else setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc); @@ -283,6 +271,7 @@ STDMETHODIMP Session::GetRemoteConsole(IConsole **aConsole) AssertReturn(mState != SessionState_Unlocked, VBOX_E_INVALID_VM_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole, ("This is not a direct session!\n"), VBOX_E_INVALID_OBJECT_STATE); @@ -297,9 +286,20 @@ STDMETHODIMP Session::GetRemoteConsole(IConsole **aConsole) LogFlowThisFuncLeave(); return S_OK; + +#else /* VBOX_COM_INPROC_API_CLIENT */ + AssertFailed(); + return VBOX_E_INVALID_OBJECT_STATE; +#endif /* VBOX_COM_INPROC_API_CLIENT */ } -STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType) +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER +STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType, + IN_BSTR aTokenId) +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType, + IToken *aToken) +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ { LogFlowThisFuncEnter(); LogFlowThisFunc(("aMachine=%p\n", aMachine)); @@ -327,19 +327,46 @@ STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType) return S_OK; } - HRESULT rc = E_FAIL; - /* query IInternalMachineControl interface */ mControl = aMachine; AssertReturn(!!mControl, E_FAIL); - rc = mConsole.createObject(); +#ifndef VBOX_COM_INPROC_API_CLIENT + HRESULT rc = mConsole.createObject(); AssertComRCReturn(rc, rc); rc = mConsole->init(aMachine, mControl, aLockType); AssertComRCReturn(rc, rc); +#else + HRESULT rc = S_OK; + mRemoteMachine = aMachine; +#endif - rc = grabIPCSemaphore(); +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + Utf8Str strTokenId(aTokenId); + Assert(!strTokenId.isEmpty()); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + AssertPtr(aToken); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + /* create the machine client token */ + try + { +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + mClientTokenHolder = new ClientTokenHolder(strTokenId); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + mClientTokenHolder = new ClientTokenHolder(aToken); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + if (!mClientTokenHolder->isReady()) + { + delete mClientTokenHolder; + mClientTokenHolder = NULL; + rc = E_FAIL; + } + } + catch (std::bad_alloc &) + { + rc = E_OUTOFMEMORY; + } /* * Reference the VirtualBox object to ensure the server is up @@ -357,11 +384,13 @@ STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType) { /* some cleanup */ mControl.setNull(); +#ifndef VBOX_COM_INPROC_API_CLIENT if (!mConsole.isNull()) { mConsole->uninit(); mConsole.setNull(); } +#endif } LogFlowThisFunc(("rc=%08X\n", rc)); @@ -469,9 +498,13 @@ STDMETHODIMP Session::UpdateMachineState(MachineState_T aMachineState) AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); AssertReturn(!mControl.isNull(), E_FAIL); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(!mConsole.isNull(), E_FAIL); return mConsole->updateMachineState(aMachineState); +#else + return S_OK; +#endif } STDMETHODIMP Session::Uninitialize() @@ -495,10 +528,11 @@ STDMETHODIMP Session::Uninitialize() return S_OK; } -#ifndef DEBUG_andy /* Don't bug me -- now time to fix this at the moment. */ - AssertReturn(mState == SessionState_Locked || - mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE); -#endif + AssertMsgReturn( mState == SessionState_Locked + || mState == SessionState_Spawning, + ("Session is in wrong state (%ld), expected locked (%ld) or spawning (%ld)\n", + mState, SessionState_Locked, SessionState_Spawning), + VBOX_E_INVALID_VM_STATE); /* close ourselves */ rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */); @@ -533,9 +567,13 @@ STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter, BO AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onNetworkAdapterChange(networkAdapter, changeAdapter); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnSerialPortChange(ISerialPort *serialPort) @@ -548,9 +586,13 @@ STDMETHODIMP Session::OnSerialPortChange(ISerialPort *serialPort) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onSerialPortChange(serialPort); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnParallelPortChange(IParallelPort *parallelPort) @@ -563,9 +605,13 @@ STDMETHODIMP Session::OnParallelPortChange(IParallelPort *parallelPort) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onParallelPortChange(parallelPort); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnStorageControllerChange() @@ -578,9 +624,13 @@ STDMETHODIMP Session::OnStorageControllerChange() AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onStorageControllerChange(); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce) @@ -593,9 +643,13 @@ STDMETHODIMP Session::OnMediumChange(IMediumAttachment *aMediumAttachment, BOOL AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onMediumChange(aMediumAttachment, aForce); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnCPUChange(ULONG aCPU, BOOL aRemove) @@ -608,9 +662,13 @@ STDMETHODIMP Session::OnCPUChange(ULONG aCPU, BOOL aRemove) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onCPUChange(aCPU, aRemove); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnCPUExecutionCapChange(ULONG aExecutionCap) @@ -623,9 +681,13 @@ STDMETHODIMP Session::OnCPUExecutionCapChange(ULONG aExecutionCap) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onCPUExecutionCapChange(aExecutionCap); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnVRDEServerChange(BOOL aRestart) @@ -638,9 +700,32 @@ STDMETHODIMP Session::OnVRDEServerChange(BOOL aRestart) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onVRDEServerChange(aRestart); +#else + return S_OK; +#endif +} + +STDMETHODIMP Session::OnVideoCaptureChange() +{ + LogFlowThisFunc(("\n")); + + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); + AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT + AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); + + return mConsole->onVideoCaptureChange(); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnUSBControllerChange() @@ -653,9 +738,13 @@ STDMETHODIMP Session::OnUSBControllerChange() AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onUSBControllerChange(); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnSharedFolderChange(BOOL aGlobal) @@ -668,9 +757,13 @@ STDMETHODIMP Session::OnSharedFolderChange(BOOL aGlobal) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onSharedFolderChange(aGlobal); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnClipboardModeChange(ClipboardMode_T aClipboardMode) @@ -683,9 +776,13 @@ STDMETHODIMP Session::OnClipboardModeChange(ClipboardMode_T aClipboardMode) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onClipboardModeChange(aClipboardMode); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode) @@ -697,9 +794,13 @@ STDMETHODIMP Session::OnDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onDragAndDropModeChange(aDragAndDropMode); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnUSBDeviceAttach(IUSBDevice *aDevice, @@ -714,9 +815,13 @@ STDMETHODIMP Session::OnUSBDeviceAttach(IUSBDevice *aDevice, AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onUSBDeviceAttach(aDevice, aError, aMaskedIfs); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnUSBDeviceDetach(IN_BSTR aId, @@ -730,9 +835,13 @@ STDMETHODIMP Session::OnUSBDeviceDetach(IN_BSTR aId, AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onUSBDeviceDetach(aId, aError); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId) @@ -743,7 +852,9 @@ STDMETHODIMP Session::OnShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); +#endif if (mState != SessionState_Locked) { @@ -756,7 +867,11 @@ STDMETHODIMP Session::OnShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId) return aCheck ? S_OK : E_FAIL; } +#ifndef VBOX_COM_INPROC_API_CLIENT return mConsole->onShowWindow(aCheck, aCanShow, aWinId); +#else + return S_OK; +#endif } STDMETHODIMP Session::OnBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) @@ -769,12 +884,16 @@ STDMETHODIMP Session::OnBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); return mConsole->onBandwidthGroupChange(aBandwidthGroup); +#else + return S_OK; +#endif } -STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove) +STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent) { LogFlowThisFunc(("\n")); @@ -784,15 +903,20 @@ STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); - return mConsole->onStorageDeviceChange(aMediumAttachment, aRemove); + return mConsole->onStorageDeviceChange(aMediumAttachment, aRemove, aSilent); +#else + return S_OK; +#endif } STDMETHODIMP Session::AccessGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags, BOOL aIsSetter, BSTR *aRetValue, LONG64 *aRetTimestamp, BSTR *aRetFlags) { #ifdef VBOX_WITH_GUEST_PROPS +# ifndef VBOX_COM_INPROC_API_CLIENT AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); @@ -810,10 +934,10 @@ STDMETHODIMP Session::AccessGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR return E_POINTER; /* aValue can be NULL for a setter call if the property is to be deleted. */ if (aIsSetter && (aValue != NULL) && !VALID_PTR(aValue)) - return E_INVALIDARG; + return setError(E_INVALIDARG, tr("Invalid value pointer")); /* aFlags can be null if it is to be left as is */ if (aIsSetter && (aFlags != NULL) && !VALID_PTR(aFlags)) - return E_INVALIDARG; + return setError(E_INVALIDARG, tr("Invalid flags pointer")); /* If this session is not in a VM process fend off the call. The caller * handles this correctly, by doing the operation in VBoxSVC. */ @@ -824,9 +948,17 @@ STDMETHODIMP Session::AccessGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR return mConsole->getGuestProperty(aName, aRetValue, aRetTimestamp, aRetFlags); else return mConsole->setGuestProperty(aName, aValue, aFlags); -#else /* VBOX_WITH_GUEST_PROPS not defined */ + +# else /* VBOX_COM_INPROC_API_CLIENT */ + /** @todo This is nonsense, non-VM API users shouldn't need to deal with this + * method call, VBoxSVC should be clever enough to see that the + * session doesn't have a console! */ + return E_ACCESSDENIED; +# endif /* VBOX_COM_INPROC_API_CLIENT */ + +#else /* VBOX_WITH_GUEST_PROPS */ ReturnComNotImplemented(); -#endif /* VBOX_WITH_GUEST_PROPS not defined */ +#endif /* VBOX_WITH_GUEST_PROPS */ } STDMETHODIMP Session::EnumerateGuestProperties(IN_BSTR aPatterns, @@ -835,7 +967,7 @@ STDMETHODIMP Session::EnumerateGuestProperties(IN_BSTR aPatterns, ComSafeArrayOut(LONG64, aTimestamps), ComSafeArrayOut(BSTR, aFlags)) { -#ifdef VBOX_WITH_GUEST_PROPS +#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT) AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); @@ -872,10 +1004,6 @@ STDMETHODIMP Session::EnumerateGuestProperties(IN_BSTR aPatterns, STDMETHODIMP Session::OnlineMergeMedium(IMediumAttachment *aMediumAttachment, ULONG aSourceIdx, ULONG aTargetIdx, - IMedium *aSource, IMedium *aTarget, - BOOL aMergeForward, - IMedium *aParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent), IProgress *aProgress) { AutoCaller autoCaller(this); @@ -885,16 +1013,18 @@ STDMETHODIMP Session::OnlineMergeMedium(IMediumAttachment *aMediumAttachment, return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not locked by session (session state: %s)."), Global::stringifySessionState(mState)); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); CheckComArgNotNull(aMediumAttachment); - CheckComArgSafeArrayNotNull(aChildrenToReparent); - return mConsole->onlineMergeMedium(aMediumAttachment, aSourceIdx, - aTargetIdx, aSource, aTarget, - aMergeForward, aParentForTarget, - ComSafeArrayInArg(aChildrenToReparent), + return mConsole->onlineMergeMedium(aMediumAttachment, + aSourceIdx, aTargetIdx, aProgress); +#else + AssertFailed(); + return E_NOTIMPL; +#endif } STDMETHODIMP Session::EnableVMMStatistics(BOOL aEnable) @@ -905,11 +1035,70 @@ STDMETHODIMP Session::EnableVMMStatistics(BOOL aEnable) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); mConsole->enableVMMStatistics(aEnable); return S_OK; +#else + AssertFailed(); + return E_NOTIMPL; +#endif +} + +STDMETHODIMP Session::PauseWithReason(Reason_T aReason) +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); + AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT + AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); + + return mConsole->pause(aReason); +#else + AssertFailed(); + return E_NOTIMPL; +#endif +} + +STDMETHODIMP Session::ResumeWithReason(Reason_T aReason) +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); + AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT + AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); + + return mConsole->resume(aReason); +#else + AssertFailed(); + return E_NOTIMPL; +#endif +} + +STDMETHODIMP Session::SaveStateWithReason(Reason_T aReason, IProgress **aProgress) +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE); + AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE); +#ifndef VBOX_COM_INPROC_API_CLIENT + AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE); + + return mConsole->saveState(aReason, aProgress); +#else + AssertFailed(); + return E_NOTIMPL; +#endif } // private methods @@ -953,16 +1142,9 @@ HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) mState = SessionState_Unlocked; mType = SessionType_Null; -#if defined(RT_OS_WINDOWS) - Assert(!mIPCSem && !mIPCThreadSem); -#elif defined(RT_OS_OS2) - Assert(mIPCThread == NIL_RTTHREAD && - mIPCThreadSem == NIL_RTSEMEVENT); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - Assert(mIPCSem == -1); -#else -# error "Port me!" -#endif + + Assert(!mClientTokenHolder); + LogFlowThisFuncLeave(); return S_OK; } @@ -972,11 +1154,15 @@ HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) if (mType == SessionType_WriteLock) { +#ifndef VBOX_COM_INPROC_API_CLIENT if (!mConsole.isNull()) { mConsole->uninit(); mConsole.setNull(); } +#else + mRemoteMachine.setNull(); +#endif } else { @@ -1032,7 +1218,12 @@ HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) if (mType == SessionType_WriteLock) { - releaseIPCSemaphore(); + if (mClientTokenHolder) + { + delete mClientTokenHolder; + mClientTokenHolder = NULL; + } + if (!aFinalRelease && !aFromServer) { /* @@ -1056,286 +1247,4 @@ HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer) return S_OK; } -/** @note To be called only from #AssignMachine() */ -HRESULT Session::grabIPCSemaphore() -{ - HRESULT rc = E_FAIL; - - /* open the IPC semaphore based on the sessionId and try to grab it */ - Bstr ipcId; - rc = mControl->GetIPCId(ipcId.asOutParam()); - AssertComRCReturnRC(rc); - - LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw())); - -#if defined(RT_OS_WINDOWS) - - /* - * Since Session is an MTA object, this method can be executed on - * any thread, and this thread will not necessarily match the thread on - * which close() will be called later. Therefore, we need a separate - * thread to hold the IPC mutex and then release it in close(). - */ - - mIPCThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); - AssertMsgReturn(mIPCThreadSem, - ("Cannot create an event sem, err=%d", ::GetLastError()), - E_FAIL); - - void *data[3]; - data[0] = (void*)(BSTR)ipcId.raw(); - data[1] = (void*)mIPCThreadSem; - data[2] = 0; /* will get an output from the thread */ - - /* create a thread to hold the IPC mutex until signalled to release it */ - RTTHREAD tid; - int vrc = RTThreadCreate(&tid, IPCMutexHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); - AssertRCReturn(vrc, E_FAIL); - - /* wait until thread init is completed */ - DWORD wrc = ::WaitForSingleObject(mIPCThreadSem, INFINITE); - AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError())); - Assert(data[2]); - - if (wrc == WAIT_OBJECT_0 && data[2]) - { - /* memorize the event sem we should signal in close() */ - mIPCSem = (HANDLE)data[2]; - rc = S_OK; - } - else - { - ::CloseHandle(mIPCThreadSem); - mIPCThreadSem = NULL; - rc = E_FAIL; - } - -#elif defined(RT_OS_OS2) - - /* We use XPCOM where any message (including close()) can arrive on any - * worker thread (which will not necessarily match this thread that opens - * the mutex). Therefore, we need a separate thread to hold the IPC mutex - * and then release it in close(). */ - - int vrc = RTSemEventCreate(&mIPCThreadSem); - AssertRCReturn(vrc, E_FAIL); - - void *data[3]; - data[0] = (void*)ipcId.raw(); - data[1] = (void*)mIPCThreadSem; - data[2] = (void*)false; /* will get the thread result here */ - - /* create a thread to hold the IPC mutex until signalled to release it */ - vrc = RTThreadCreate(&mIPCThread, IPCMutexHolderThread, (void *) data, - 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); - AssertRCReturn(vrc, E_FAIL); - - /* wait until thread init is completed */ - vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); - AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL); - - /* the thread must succeed */ - AssertReturn((bool)data[2], E_FAIL); - -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN - Utf8Str ipcKey = ipcId; - key_t key = RTStrToUInt32(ipcKey.c_str()); - AssertMsgReturn (key != 0, - ("Key value of 0 is not valid for IPC semaphore"), - E_FAIL); -# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ - Utf8Str semName = ipcId; - char *pszSemName = NULL; - RTStrUtf8ToCurrentCP (&pszSemName, semName); - key_t key = ::ftok (pszSemName, 'V'); - RTStrFree (pszSemName); -# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ - - mIPCSem = ::semget (key, 0, 0); - AssertMsgReturn (mIPCSem >= 0, - ("Cannot open IPC semaphore, errno=%d", errno), - E_FAIL); - - /* grab the semaphore */ - ::sembuf sop = { 0, -1, SEM_UNDO }; - int rv = ::semop (mIPCSem, &sop, 1); - AssertMsgReturn (rv == 0, - ("Cannot grab IPC semaphore, errno=%d", errno), - E_FAIL); - -#else -# error "Port me!" -#endif - - return rc; -} - -/** @note To be called only from #close() */ -void Session::releaseIPCSemaphore() -{ - /* release the IPC semaphore */ -#if defined(RT_OS_WINDOWS) - - if (mIPCSem && mIPCThreadSem) - { - /* - * tell the thread holding the IPC mutex to release it; - * it will close mIPCSem handle - */ - ::SetEvent (mIPCSem); - /* wait for the thread to finish */ - ::WaitForSingleObject (mIPCThreadSem, INFINITE); - ::CloseHandle (mIPCThreadSem); - - mIPCThreadSem = NULL; - mIPCSem = NULL; - } - -#elif defined(RT_OS_OS2) - - if (mIPCThread != NIL_RTTHREAD) - { - Assert (mIPCThreadSem != NIL_RTSEMEVENT); - - /* tell the thread holding the IPC mutex to release it */ - int vrc = RTSemEventSignal (mIPCThreadSem); - AssertRC(vrc == NO_ERROR); - - /* wait for the thread to finish */ - vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); - Assert (RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); - - mIPCThread = NIL_RTTHREAD; - } - - if (mIPCThreadSem != NIL_RTSEMEVENT) - { - RTSemEventDestroy (mIPCThreadSem); - mIPCThreadSem = NIL_RTSEMEVENT; - } - -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - - if (mIPCSem >= 0) - { - ::sembuf sop = { 0, 1, SEM_UNDO }; - ::semop (mIPCSem, &sop, 1); - - mIPCSem = -1; - } - -#else -# error "Port me!" -#endif -} - -#if defined(RT_OS_WINDOWS) -/** VM IPC mutex holder thread */ -DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser) -{ - LogFlowFuncEnter(); - - Assert (pvUser); - void **data = (void **) pvUser; - - BSTR sessionId = (BSTR)data[0]; - HANDLE initDoneSem = (HANDLE)data[1]; - - HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId); - AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%d\n", ::GetLastError())); - - if (ipcMutex) - { - /* grab the mutex */ - DWORD wrc = ::WaitForSingleObject (ipcMutex, 0); - AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc)); - if (wrc == WAIT_OBJECT_0) - { - HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL); - AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError())); - if (finishSem) - { - data[2] = (void*)finishSem; - /* signal we're done with init */ - ::SetEvent (initDoneSem); - /* wait until we're signaled to release the IPC mutex */ - ::WaitForSingleObject (finishSem, INFINITE); - /* release the IPC mutex */ - LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n")); - BOOL success = ::ReleaseMutex (ipcMutex); - AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError())); - ::CloseHandle (ipcMutex); - ::CloseHandle (finishSem); - } - } - } - - /* signal we're done */ - ::SetEvent (initDoneSem); - - LogFlowFuncLeave(); - - return 0; -} -#endif - -#if defined(RT_OS_OS2) -/** VM IPC mutex holder thread */ -DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser) -{ - LogFlowFuncEnter(); - - Assert (pvUser); - void **data = (void **) pvUser; - - Utf8Str ipcId = (BSTR)data[0]; - RTSEMEVENT finishSem = (RTSEMEVENT)data[1]; - - LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem)); - - HMTX ipcMutex = NULLHANDLE; - APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex); - AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc)); - - if (arc == NO_ERROR) - { - /* grab the mutex */ - LogFlowFunc (("grabbing IPC mutex...\n")); - arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN); - AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc)); - if (arc == NO_ERROR) - { - /* store the answer */ - data[2] = (void*)true; - /* signal we're done */ - int vrc = RTThreadUserSignal (Thread); - AssertRC(vrc); - - /* wait until we're signaled to release the IPC mutex */ - LogFlowFunc (("waiting for termination signal..\n")); - vrc = RTSemEventWait (finishSem, RT_INDEFINITE_WAIT); - Assert (arc == ERROR_INTERRUPT || ERROR_TIMEOUT); - - /* release the IPC mutex */ - LogFlowFunc (("releasing IPC mutex...\n")); - arc = ::DosReleaseMutexSem (ipcMutex); - AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc)); - } - - ::DosCloseMutexSem (ipcMutex); - } - - /* store the answer */ - data[1] = (void*)false; - /* signal we're done */ - int vrc = RTThreadUserSignal (Thread); - AssertRC(vrc); - - LogFlowFuncLeave(); - - return 0; -} -#endif /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-client/USBDeviceImpl.cpp b/src/VBox/Main/src-client/USBDeviceImpl.cpp index a927d64f..023b6979 100644 --- a/src/VBox/Main/src-client/USBDeviceImpl.cpp +++ b/src/VBox/Main/src-client/USBDeviceImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -82,10 +82,10 @@ HRESULT OUSBDevice::init(IUSBDevice *aUSBDevice) hrc = aUSBDevice->COMGETTER(Port)(&unconst(mData.port)); ComAssertComRCRet(hrc, hrc); - hrc = aUSBDevice->COMGETTER(Port)(&unconst(mData.version)); + hrc = aUSBDevice->COMGETTER(Version)(&unconst(mData.version)); ComAssertComRCRet(hrc, hrc); - hrc = aUSBDevice->COMGETTER(Port)(&unconst(mData.portVersion)); + hrc = aUSBDevice->COMGETTER(PortVersion)(&unconst(mData.portVersion)); ComAssertComRCRet(hrc, hrc); hrc = aUSBDevice->COMGETTER(Remote)(&unconst(mData.remote)); diff --git a/src/VBox/Main/src-client/UsbCardReader.cpp b/src/VBox/Main/src-client/UsbCardReader.cpp index f7a7bc5b..477beeff 100644 --- a/src/VBox/Main/src-client/UsbCardReader.cpp +++ b/src/VBox/Main/src-client/UsbCardReader.cpp @@ -1,5 +1,4 @@ /* $Id: UsbCardReader.cpp $ */ - /** @file * UsbCardReader - Driver Interface to USB Smart Card Reader emulation. */ @@ -69,9 +68,9 @@ static DECLCALLBACK(void) drvCardReaderCmdStatusChange(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpSetStatusChange(pThis->pICardReaderUp, - pvUser, VRDE_SCARD_E_NO_SMARTCARD, - paReaderStats, cReaderStats); + pThis->pICardReaderUp->pfnSetStatusChange(pThis->pICardReaderUp, + pvUser, VRDE_SCARD_E_NO_SMARTCARD, + paReaderStats, cReaderStats); } else { @@ -90,8 +89,8 @@ static DECLCALLBACK(void) drvCardReaderCmdEstablishContext(PUSBCARDREADER pThis) UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpEstablishContext(pThis->pICardReaderUp, - VRDE_SCARD_E_NO_SMARTCARD); + pThis->pICardReaderUp->pfnEstablishContext(pThis->pICardReaderUp, + VRDE_SCARD_E_NO_SMARTCARD); } else { @@ -130,15 +129,15 @@ static DECLCALLBACK(void) drvCardReaderCmdStatus(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpStatus(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - /* pszReaderName */ NULL, - /* cchReaderName */ 0, - /* u32CardState */ 0, - /* u32Protocol */ 0, - /* pu8Atr */ 0, - /* cbAtr */ 0); + pThis->pICardReaderUp->pfnStatus(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + /* pszReaderName */ NULL, + /* cchReaderName */ 0, + /* u32CardState */ 0, + /* u32Protocol */ 0, + /* pu8Atr */ 0, + /* cbAtr */ 0); } else { @@ -160,10 +159,10 @@ static DECLCALLBACK(void) drvCardReaderCmdConnect(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpConnect(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - 0); + pThis->pICardReaderUp->pfnConnect(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + 0); } else { @@ -184,9 +183,9 @@ static DECLCALLBACK(void) drvCardReaderCmdDisconnect(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpDisconnect(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD); + pThis->pICardReaderUp->pfnDisconnect(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD); } else { @@ -209,12 +208,12 @@ static DECLCALLBACK(void) drvCardReaderCmdTransmit(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpTransmit(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - /* pioRecvPci */ NULL, - /* pu8RecvBuffer */ NULL, - /* cbRecvBuffer*/ 0); + pThis->pICardReaderUp->pfnTransmit(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + /* pioRecvPci */ NULL, + /* pu8RecvBuffer */ NULL, + /* cbRecvBuffer*/ 0); } else { @@ -240,12 +239,12 @@ static DECLCALLBACK(void) drvCardReaderCmdGetAttr(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpGetAttrib(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - u32AttrId, - /* pvAttrib */ NULL, - /* cbAttrib */ 0); + pThis->pICardReaderUp->pfnGetAttrib(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + u32AttrId, + /* pvAttrib */ NULL, + /* cbAttrib */ 0); } else { @@ -267,10 +266,10 @@ static DECLCALLBACK(void) drvCardReaderCmdSetAttr(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpSetAttrib(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - u32AttrId); + pThis->pICardReaderUp->pfnSetAttrib(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + u32AttrId); } else { @@ -296,12 +295,12 @@ static DECLCALLBACK(void) drvCardReaderCmdControl(PUSBCARDREADER pThis, UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { - pThis->pICardReaderUp->pfnCardReaderUpControl(pThis->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - u32ControlCode, - /* pvOutBuffer */ NULL, - /* cbOutBuffer */ 0); + pThis->pICardReaderUp->pfnControl(pThis->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + u32ControlCode, + /* pvOutBuffer */ NULL, + /* cbOutBuffer */ 0); } else { @@ -891,11 +890,11 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pCtx->u.GetStatusChange.paReaderStats, - pCtx->u.GetStatusChange.cReaderStats); + mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pCtx->u.GetStatusChange.paReaderStats, + pCtx->u.GetStatusChange.cReaderStats); RTMemFree(pCtx); } break; @@ -942,10 +941,10 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - u32ActiveProtocol); + mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + u32ActiveProtocol); RTMemFree(pCtx); } break; @@ -984,9 +983,9 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio rcCard = pRsp->u32ReturnCode; } - mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard); + mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard); RTMemFree(pCtx); } break; @@ -1054,7 +1053,7 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pszReaderName = pRsp->szReader; - cchReaderName = strlen(pRsp->szReader) + 1; + cchReaderName = (uint32_t)strlen(pRsp->szReader) + 1; u32CardState = pRsp->u32State; u32Protocol = pRsp->u32Protocol; u32AtrLength = pRsp->u32AtrLength; @@ -1062,15 +1061,15 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pszReaderName, - cchReaderName, - u32CardState, - u32Protocol, - pbAtr, - u32AtrLength); + mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pszReaderName, + cchReaderName, + u32CardState, + u32Protocol, + pbAtr, + u32AtrLength); RTMemFree(pCtx); } break; @@ -1107,12 +1106,12 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpTransmit(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pioRecvPci, - pu8RecvBuffer, - cbRecvBuffer); + mpDrv->pICardReaderUp->pfnTransmit(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pioRecvPci, + pu8RecvBuffer, + cbRecvBuffer); RTMemFree(pioRecvPci); @@ -1149,12 +1148,12 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpControl(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pCtx->u.Control.u32ControlCode, - pu8OutBuffer, - cbOutBuffer); + mpDrv->pICardReaderUp->pfnControl(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pCtx->u.Control.u32ControlCode, + pu8OutBuffer, + cbOutBuffer); RTMemFree(pCtx); } break; @@ -1189,12 +1188,12 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio } } - mpDrv->pICardReaderUp->pfnCardReaderUpGetAttrib(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pCtx->u.GetAttrib.u32AttrId, - pu8Attrib, - cbAttrib); + mpDrv->pICardReaderUp->pfnGetAttrib(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pCtx->u.GetAttrib.u32AttrId, + pu8Attrib, + cbAttrib); RTMemFree(pCtx); } break; @@ -1220,10 +1219,10 @@ int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Functio rcCard = pRsp->u32ReturnCode; } - mpDrv->pICardReaderUp->pfnCardReaderUpSetAttrib(mpDrv->pICardReaderUp, - pCtx->pvUser, - rcCard, - pCtx->u.SetAttrib.u32AttrId); + mpDrv->pICardReaderUp->pfnSetAttrib(mpDrv->pICardReaderUp, + pCtx->pvUser, + rcCard, + pCtx->u.SetAttrib.u32AttrId); RTMemFree(pCtx); } break; @@ -1245,8 +1244,8 @@ int UsbCardReader::EstablishContext(struct USBCARDREADER *pDrv) * The device can be detached at the moment, for example the VRDP client did not connect yet. */ - return mpDrv->pICardReaderUp->pfnCardReaderUpEstablishContext(mpDrv->pICardReaderUp, - VRDE_SCARD_S_SUCCESS); + return mpDrv->pICardReaderUp->pfnEstablishContext(mpDrv->pICardReaderUp, + VRDE_SCARD_S_SUCCESS); } int UsbCardReader::ReleaseContext(struct USBCARDREADER *pDrv) @@ -1306,22 +1305,22 @@ int UsbCardReader::GetStatusChange(struct USBCARDREADER *pDrv, || !m_pRemote->fContext || !m_pRemote->reader.fAvailable) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - paReaderStats, - cReaderStats); + rc = mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + paReaderStats, + cReaderStats); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_MEMORY, - paReaderStats, - cReaderStats); + rc = mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_MEMORY, + paReaderStats, + cReaderStats); } else { @@ -1364,20 +1363,20 @@ int UsbCardReader::Connect(struct USBCARDREADER *pDrv, || !m_pRemote->fContext || !m_pRemote->reader.fAvailable) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - VRDE_SCARD_PROTOCOL_T0); + rc = mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + VRDE_SCARD_PROTOCOL_T0); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_MEMORY, - VRDE_SCARD_PROTOCOL_T0); + rc = mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_MEMORY, + VRDE_SCARD_PROTOCOL_T0); } else { @@ -1416,18 +1415,18 @@ int UsbCardReader::Disconnect(struct USBCARDREADER *pDrv, || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD); + rc = mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_MEMORY); + rc = mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_MEMORY); } else { @@ -1467,30 +1466,30 @@ int UsbCardReader::Status(struct USBCARDREADER *pDrv, || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_SMARTCARD, - /* pszReaderName */ NULL, - /* cchReaderName */ 0, - /* u32CardState */ 0, - /* u32Protocol */ 0, - /* pu8Atr */ 0, - /* cbAtr */ 0); + rc = mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_SMARTCARD, + /* pszReaderName */ NULL, + /* cchReaderName */ 0, + /* u32CardState */ 0, + /* u32Protocol */ 0, + /* pu8Atr */ 0, + /* cbAtr */ 0); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { - rc = mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp, - pvUser, - VRDE_SCARD_E_NO_MEMORY, - /* pszReaderName */ NULL, - /* cchReaderName */ 0, - /* u32CardState */ 0, - /* u32Protocol */ 0, - /* pu8Atr */ 0, - /* cbAtr */ 0); + rc = mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, + pvUser, + VRDE_SCARD_E_NO_MEMORY, + /* pszReaderName */ NULL, + /* cchReaderName */ 0, + /* u32CardState */ 0, + /* u32Protocol */ 0, + /* pu8Atr */ 0, + /* cbAtr */ 0); } else { @@ -1560,12 +1559,12 @@ int UsbCardReader::Transmit(struct USBCARDREADER *pDrv, { Assert(pCtx == NULL); - rc = pDrv->pICardReaderUp->pfnCardReaderUpTransmit(pDrv->pICardReaderUp, - pvUser, - rcSCard, - /* pioRecvPci */ NULL, - /* pu8RecvBuffer */ NULL, - /* cbRecvBuffer*/ 0); + rc = pDrv->pICardReaderUp->pfnTransmit(pDrv->pICardReaderUp, + pvUser, + rcSCard, + /* pioRecvPci */ NULL, + /* pu8RecvBuffer */ NULL, + /* cbRecvBuffer*/ 0); } else { @@ -1645,12 +1644,12 @@ int UsbCardReader::Control(struct USBCARDREADER *pDrv, { Assert(pCtx == NULL); - rc = pDrv->pICardReaderUp->pfnCardReaderUpControl(pDrv->pICardReaderUp, - pvUser, - rcSCard, - u32ControlCode, - /* pvOutBuffer */ NULL, - /* cbOutBuffer*/ 0); + rc = pDrv->pICardReaderUp->pfnControl(pDrv->pICardReaderUp, + pvUser, + rcSCard, + u32ControlCode, + /* pvOutBuffer */ NULL, + /* cbOutBuffer*/ 0); } else { @@ -1719,12 +1718,12 @@ int UsbCardReader::GetAttrib(struct USBCARDREADER *pDrv, { Assert(pCtx == NULL); - pDrv->pICardReaderUp->pfnCardReaderUpGetAttrib(pDrv->pICardReaderUp, - pvUser, - rcSCard, - u32AttrId, - /* pvAttrib */ NULL, - /* cbAttrib */ 0); + pDrv->pICardReaderUp->pfnGetAttrib(pDrv->pICardReaderUp, + pvUser, + rcSCard, + u32AttrId, + /* pvAttrib */ NULL, + /* cbAttrib */ 0); } else { @@ -1792,10 +1791,10 @@ int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, { Assert(pCtx == NULL); - pDrv->pICardReaderUp->pfnCardReaderUpSetAttrib(pDrv->pICardReaderUp, - pvUser, - rcSCard, - u32AttrId); + pDrv->pICardReaderUp->pfnSetAttrib(pDrv->pICardReaderUp, + pvUser, + rcSCard, + u32AttrId); } else { @@ -1823,7 +1822,7 @@ int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, /* - * PDM + * PDMDRVINS */ /* static */ DECLCALLBACK(void *) UsbCardReader::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID) @@ -1837,11 +1836,38 @@ int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, return NULL; } +/* static */ DECLCALLBACK(void) UsbCardReader::drvDestruct(PPDMDRVINS pDrvIns) +{ + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + LogFlowFunc(("iInstance/%d\n",pDrvIns->iInstance)); + PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); + + /** @todo The driver is destroyed before the device. + * So device calls ReleaseContext when there is no more driver. + * Notify the device here so it can do cleanup or + * do a cleanup now in the driver. + */ + if (pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE) + { + int rc = RTReqQueueDestroy(pThis->hReqQCardReaderCmd); + AssertRC(rc); + pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; + } + + /** @todo r=bird: why doesn't this set pThis->pUsbCardReader->mpDrv to NULL like + * everyone else? */ + pThis->pUsbCardReader = NULL; + LogFlowFuncLeave(); +} + /* static */ DECLCALLBACK(int) UsbCardReader::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); LogFlowFunc(("iInstance/%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags)); PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); + pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; + if (!CFGMR3AreValuesValid(pCfg, "Object\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, @@ -1858,18 +1884,18 @@ int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, pDrvIns->IBase.pfnQueryInterface = UsbCardReader::drvQueryInterface; - pThis->ICardReaderDown.pfnCardReaderDownEstablishContext = drvCardReaderDownEstablishContext; - pThis->ICardReaderDown.pfnCardReaderDownReleaseContext = drvCardReaderDownReleaseContext; - pThis->ICardReaderDown.pfnCardReaderDownConnect = drvCardReaderDownConnect; - pThis->ICardReaderDown.pfnCardReaderDownDisconnect = drvCardReaderDownDisconnect; - pThis->ICardReaderDown.pfnCardReaderDownStatus = drvCardReaderDownStatus; - pThis->ICardReaderDown.pfnCardReaderDownGetStatusChange = drvCardReaderDownGetStatusChange; - pThis->ICardReaderDown.pfnCardReaderDownBeginTransaction = drvCardReaderDownBeginTransaction; - pThis->ICardReaderDown.pfnCardReaderDownEndTransaction = drvCardReaderDownEndTransaction; - pThis->ICardReaderDown.pfnCardReaderDownTransmit = drvCardReaderDownTransmit; - pThis->ICardReaderDown.pfnCardReaderDownGetAttr = drvCardReaderDownGetAttr; - pThis->ICardReaderDown.pfnCardReaderDownSetAttr = drvCardReaderDownSetAttr; - pThis->ICardReaderDown.pfnCardReaderDownControl = drvCardReaderDownControl; + pThis->ICardReaderDown.pfnEstablishContext = drvCardReaderDownEstablishContext; + pThis->ICardReaderDown.pfnReleaseContext = drvCardReaderDownReleaseContext; + pThis->ICardReaderDown.pfnConnect = drvCardReaderDownConnect; + pThis->ICardReaderDown.pfnDisconnect = drvCardReaderDownDisconnect; + pThis->ICardReaderDown.pfnStatus = drvCardReaderDownStatus; + pThis->ICardReaderDown.pfnGetStatusChange = drvCardReaderDownGetStatusChange; + pThis->ICardReaderDown.pfnBeginTransaction = drvCardReaderDownBeginTransaction; + pThis->ICardReaderDown.pfnEndTransaction = drvCardReaderDownEndTransaction; + pThis->ICardReaderDown.pfnTransmit = drvCardReaderDownTransmit; + pThis->ICardReaderDown.pfnGetAttr = drvCardReaderDownGetAttr; + pThis->ICardReaderDown.pfnSetAttr = drvCardReaderDownSetAttr; + pThis->ICardReaderDown.pfnControl = drvCardReaderDownControl; pThis->pICardReaderUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICARDREADERUP); AssertReturn(pThis->pICardReaderUp, VERR_PDM_MISSING_INTERFACE); @@ -1894,27 +1920,6 @@ int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, return rc; } -/* static */ DECLCALLBACK(void) UsbCardReader::drvDestruct(PPDMDRVINS pDrvIns) -{ - LogFlowFunc(("iInstance/%d\n",pDrvIns->iInstance)); - PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); - - /* @todo The driver is destroyed before the device. - * So device calls ReleaseContext when there is no more driver. - * Notify the device here so it can do cleanup or - * do a cleanup now in the driver. - */ - if (pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE) - { - int rc = RTReqQueueDestroy(pThis->hReqQCardReaderCmd); - AssertRC(rc); - pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; - } - - pThis->pUsbCardReader = NULL; - LogFlowFuncLeave(); -} - /* static */ const PDMDRVREG UsbCardReader::DrvReg = { /* u32Version */ diff --git a/src/VBox/Main/src-client/UsbWebcamInterface.cpp b/src/VBox/Main/src-client/UsbWebcamInterface.cpp new file mode 100644 index 00000000..5a924eb4 --- /dev/null +++ b/src/VBox/Main/src-client/UsbWebcamInterface.cpp @@ -0,0 +1,472 @@ +/* $Id: UsbWebcamInterface.cpp $ */ +/** @file + * UsbWebcamInterface - Driver Interface for USB Webcam emulation. + */ + +/* + * Copyright (C) 2011-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +#define LOG_GROUP LOG_GROUP_USB_WEBCAM +#include "UsbWebcamInterface.h" +#include "ConsoleImpl.h" +#include "ConsoleVRDPServer.h" +#include "EmulatedUSBImpl.h" + +#include + + +typedef struct EMWEBCAMREMOTE +{ + EmWebcam *pEmWebcam; + + VRDEVIDEOINDEVICEHANDLE deviceHandle; /* The remote identifier. */ + + /* Received from the remote client. */ + uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */ + uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */ + VRDEVIDEOINDEVICEDESC *pDeviceDesc; + uint32_t cbDeviceDesc; + + /* The device identifier for the PDM device.*/ + uint64_t u64DeviceId; +} EMWEBCAMREMOTE; + +typedef struct EMWEBCAMDRV +{ + EMWEBCAMREMOTE *pRemote; + PPDMIWEBCAMUP pIWebcamUp; + PDMIWEBCAMDOWN IWebcamDown; +} EMWEBCAMDRV, *PEMWEBCAMDRV; + +typedef struct EMWEBCAMREQCTX +{ + EMWEBCAMREMOTE *pRemote; + void *pvUser; +} EMWEBCAMREQCTX; + + +static DECLCALLBACK(void) drvEmWebcamReady(PPDMIWEBCAMDOWN pInterface, + bool fReady) +{ + NOREF(fReady); + + PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown); + EMWEBCAMREMOTE *pRemote = pThis->pRemote; + + LogFlowFunc(("pRemote:%p\n", pThis->pRemote)); + + if (pThis->pIWebcamUp) + { + pThis->pIWebcamUp->pfnWebcamUpAttached(pThis->pIWebcamUp, + pRemote->u64DeviceId, + (const PDMIWEBCAM_DEVICEDESC *)pRemote->pDeviceDesc, + pRemote->cbDeviceDesc, + pRemote->u32Version, + pRemote->fu32Capabilities); + } +} + +static DECLCALLBACK(int) drvEmWebcamControl(PPDMIWEBCAMDOWN pInterface, + void *pvUser, + uint64_t u64DeviceId, + const PDMIWEBCAM_CTRLHDR *pCtrl, + uint32_t cbCtrl) +{ + PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown); + EMWEBCAMREMOTE *pRemote = pThis->pRemote; + + LogFlowFunc(("pRemote:%p, u64DeviceId %lld\n", pRemote, u64DeviceId)); + + return pRemote->pEmWebcam->SendControl(pThis, pvUser, u64DeviceId, (const VRDEVIDEOINCTRLHDR *)pCtrl, cbCtrl); +} + + +EmWebcam::EmWebcam(ConsoleVRDPServer *pServer) + : + mParent(pServer), + mpDrv(NULL), + mpRemote(NULL), + mu64DeviceIdSrc(0) +{ +} + +EmWebcam::~EmWebcam() +{ + if (mpDrv) + { + mpDrv->pRemote = NULL; + mpDrv = NULL; + } +} + +void EmWebcam::EmWebcamConstruct(EMWEBCAMDRV *pDrv) +{ + AssertReturnVoid(mpDrv == NULL); + + mpDrv = pDrv; +} + +void EmWebcam::EmWebcamDestruct(EMWEBCAMDRV *pDrv) +{ + AssertReturnVoid(pDrv == mpDrv); + + if (mpRemote) + { + mParent->VideoInDeviceDetach(&mpRemote->deviceHandle); + + RTMemFree(mpRemote->pDeviceDesc); + mpRemote->pDeviceDesc = NULL; + mpRemote->cbDeviceDesc = 0; + + RTMemFree(mpRemote); + mpRemote = NULL; + } + + mpDrv->pRemote = NULL; + mpDrv = NULL; +} + +void EmWebcam::EmWebcamCbNotify(uint32_t u32Id, const void *pvData, uint32_t cbData) +{ + int rc = VINF_SUCCESS; + + switch (u32Id) + { + case VRDE_VIDEOIN_NOTIFY_ID_ATTACH: + { + VRDEVIDEOINNOTIFYATTACH *p = (VRDEVIDEOINNOTIFYATTACH *)pvData; + + /* Older versions did not report u32Version and fu32Capabilities. */ + uint32_t u32Version = 1; + uint32_t fu32Capabilities = VRDE_VIDEOIN_NEGOTIATE_CAP_VOID; + + if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, u32Version) + sizeof(p->u32Version)) + { + u32Version = p->u32Version; + } + + if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, fu32Capabilities) + sizeof(p->fu32Capabilities)) + { + fu32Capabilities = p->fu32Capabilities; + } + + LogFlowFunc(("ATTACH[%d,%d] version %d, caps 0x%08X\n", + p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId, + u32Version, fu32Capabilities)); + + /* Currently only one device is allowed. */ + if (mpRemote) + { + AssertFailed(); + rc = VERR_NOT_SUPPORTED; + break; + } + + EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)RTMemAllocZ(sizeof(EMWEBCAMREMOTE)); + if (pRemote == NULL) + { + rc = VERR_NO_MEMORY; + break; + } + + pRemote->pEmWebcam = this; + pRemote->deviceHandle = p->deviceHandle; + pRemote->u32Version = u32Version; + pRemote->fu32Capabilities = fu32Capabilities; + pRemote->pDeviceDesc = NULL; + pRemote->cbDeviceDesc = 0; + pRemote->u64DeviceId = ASMAtomicIncU64(&mu64DeviceIdSrc); + + mpRemote = pRemote; + + /* Tell the server that this webcam will be used. */ + rc = mParent->VideoInDeviceAttach(&mpRemote->deviceHandle, mpRemote); + if (RT_FAILURE(rc)) + { + RTMemFree(mpRemote); + mpRemote = NULL; + break; + } + + /* Get the device description. */ + rc = mParent->VideoInGetDeviceDesc(NULL, &mpRemote->deviceHandle); + + if (RT_FAILURE(rc)) + { + mParent->VideoInDeviceDetach(&mpRemote->deviceHandle); + RTMemFree(mpRemote); + mpRemote = NULL; + break; + } + + LogFlowFunc(("sent DeviceDesc\n")); + } break; + + case VRDE_VIDEOIN_NOTIFY_ID_DETACH: + { + VRDEVIDEOINNOTIFYDETACH *p = (VRDEVIDEOINNOTIFYDETACH *)pvData; + Assert(cbData == sizeof(VRDEVIDEOINNOTIFYDETACH)); + + LogFlowFunc(("DETACH[%d,%d]\n", p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId)); + + /* @todo */ + if (mpRemote) + { + if (mpDrv && mpDrv->pIWebcamUp) + { + mpDrv->pIWebcamUp->pfnWebcamUpDetached(mpDrv->pIWebcamUp, + mpRemote->u64DeviceId); + } + /* mpRemote is deallocated in EmWebcamDestruct */ + } + } break; + + default: + rc = VERR_INVALID_PARAMETER; + AssertFailed(); + break; + } + + return; +} + +void EmWebcam::EmWebcamCbDeviceDesc(int rcRequest, void *pDeviceCtx, void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, uint32_t cbDeviceDesc) +{ + EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx; + Assert(pRemote == mpRemote); + + LogFlowFunc(("mpDrv %p, rcRequest %Rrc %p %p %p %d\n", + mpDrv, rcRequest, pDeviceCtx, pvUser, pDeviceDesc, cbDeviceDesc)); + + if (RT_SUCCESS(rcRequest)) + { + /* Save device description. */ + Assert(pRemote->pDeviceDesc == NULL); + pRemote->pDeviceDesc = (VRDEVIDEOINDEVICEDESC *)RTMemDup(pDeviceDesc, cbDeviceDesc); + pRemote->cbDeviceDesc = cbDeviceDesc; + + /* Try to attach the device. */ + EmulatedUSB *pEUSB = mParent->getConsole()->getEmulatedUSB(); + pEUSB->webcamAttachInternal("", "", "EmWebcam", pRemote); + } + else + { + mParent->VideoInDeviceDetach(&mpRemote->deviceHandle); + RTMemFree(mpRemote); + mpRemote = NULL; + } +} + +void EmWebcam::EmWebcamCbControl(int rcRequest, void *pDeviceCtx, void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl) +{ + EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx; + Assert(pRemote == mpRemote); + + LogFlowFunc(("rcRequest %Rrc %p %p %p %d\n", + rcRequest, pDeviceCtx, pvUser, pControl, cbControl)); + + bool fResponse = (pvUser != NULL); + + if (mpDrv && mpDrv->pIWebcamUp) + { + mpDrv->pIWebcamUp->pfnWebcamUpControl(mpDrv->pIWebcamUp, + fResponse, + pvUser, + mpRemote->u64DeviceId, + (const PDMIWEBCAM_CTRLHDR *)pControl, + cbControl); + } + + RTMemFree(pvUser); +} + +void EmWebcam::EmWebcamCbFrame(int rcRequest, void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, uint32_t cbFrame) +{ + LogFlowFunc(("rcRequest %Rrc %p %p %d\n", + rcRequest, pDeviceCtx, pFrame, cbFrame)); + + if (mpDrv && mpDrv->pIWebcamUp) + { + if ( cbFrame >= sizeof(VRDEVIDEOINPAYLOADHDR) + && cbFrame >= pFrame->u8HeaderLength) + { + uint32_t cbImage = cbFrame - pFrame->u8HeaderLength; + const uint8_t *pu8Image = cbImage > 0? (const uint8_t *)pFrame + pFrame->u8HeaderLength: NULL; + + mpDrv->pIWebcamUp->pfnWebcamUpFrame(mpDrv->pIWebcamUp, + mpRemote->u64DeviceId, + (PDMIWEBCAM_FRAMEHDR *)pFrame, + pFrame->u8HeaderLength, + pu8Image, + cbImage); + } + } +} + +int EmWebcam::SendControl(EMWEBCAMDRV *pDrv, void *pvUser, uint64_t u64DeviceId, + const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl) +{ + AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); + + int rc = VINF_SUCCESS; + + EMWEBCAMREQCTX *pCtx = NULL; + + /* Verify that there is a remote device. */ + if ( !mpRemote + || mpRemote->u64DeviceId != u64DeviceId) + { + rc = VERR_NOT_SUPPORTED; + } + + if (RT_SUCCESS(rc)) + { + pCtx = (EMWEBCAMREQCTX *)RTMemAlloc(sizeof(EMWEBCAMREQCTX)); + if (!pCtx) + { + rc = VERR_NO_MEMORY; + } + } + + if (RT_SUCCESS(rc)) + { + pCtx->pRemote = mpRemote; + pCtx->pvUser = pvUser; + + rc = mParent->VideoInControl(pCtx, &mpRemote->deviceHandle, pControl, cbControl); + + if (RT_FAILURE(rc)) + { + RTMemFree(pCtx); + } + } + + return rc; +} + +/* static */ DECLCALLBACK(void *) EmWebcam::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID) +{ + PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); + PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV); + + LogFlowFunc(("pszIID:%s\n", pszIID)); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIWEBCAMDOWN, &pThis->IWebcamDown); + return NULL; +} + +/* static */ DECLCALLBACK(void) EmWebcam::drvDestruct(PPDMDRVINS pDrvIns) +{ + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV); + EMWEBCAMREMOTE *pRemote = pThis->pRemote; + + LogFlowFunc(("iInstance %d, pRemote %p, pIWebcamUp %p\n", + pDrvIns->iInstance, pRemote, pThis->pIWebcamUp)); + + if (pRemote && pRemote->pEmWebcam) + { + pRemote->pEmWebcam->EmWebcamDestruct(pThis); + } +} + +/* static */ DECLCALLBACK(int) EmWebcam::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) +{ + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + LogFlowFunc(("iInstance:%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags)); + + PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV); + + AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, + ("Configuration error: Not possible to attach anything to this driver!\n"), + VERR_PDM_DRVINS_NO_ATTACH); + + /* Check early that there is a device. No need to init anything if there is no device. */ + pThis->pIWebcamUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIWEBCAMUP); + if (pThis->pIWebcamUp == NULL) + { + LogRel(("USBWEBCAM: Emulated webcam device does not exist.\n")); + return VERR_PDM_MISSING_INTERFACE; + } + + void *pv = NULL; + int rc = CFGMR3QueryPtr(pCfg, "Object", &pv); + if (!RT_VALID_PTR(pv)) + rc = VERR_INVALID_PARAMETER; + AssertMsgReturn(RT_SUCCESS(rc), + ("Configuration error: No/bad \"Object\" %p value! rc=%Rrc\n", pv, rc), rc); + + /* Everything ok. Initialize. */ + pThis->pRemote = (EMWEBCAMREMOTE *)pv; + pThis->pRemote->pEmWebcam->EmWebcamConstruct(pThis); + + pDrvIns->IBase.pfnQueryInterface = drvQueryInterface; + + pThis->IWebcamDown.pfnWebcamDownReady = drvEmWebcamReady; + pThis->IWebcamDown.pfnWebcamDownControl = drvEmWebcamControl; + + return VINF_SUCCESS; +} + +/* static */ const PDMDRVREG EmWebcam::DrvReg = +{ + /* u32Version */ + PDM_DRVREG_VERSION, + /* szName[32] */ + "EmWebcam", + /* szRCMod[32] */ + "", + /* szR0Mod[32] */ + "", + /* pszDescription */ + "Main Driver communicating with VRDE", + /* fFlags */ + PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, + /* fClass */ + PDM_DRVREG_CLASS_USB, + /* cMaxInstances */ + 1, + /* cbInstance */ + sizeof(EMWEBCAMDRV), + /* pfnConstruct */ + EmWebcam::drvConstruct, + /* pfnDestruct */ + EmWebcam::drvDestruct, + /* pfnRelocate */ + NULL, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + NULL, + /* pfnSuspend */ + NULL, + /* pfnResume */ + NULL, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnPowerOff */ + NULL, + /* pfnSoftReset */ + NULL, + /* u32VersionEnd */ + PDM_DRVREG_VERSION +}; +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-client/VBoxDriversRegister.cpp b/src/VBox/Main/src-client/VBoxDriversRegister.cpp index b98babe2..7fa0f998 100644 --- a/src/VBox/Main/src-client/VBoxDriversRegister.cpp +++ b/src/VBox/Main/src-client/VBoxDriversRegister.cpp @@ -25,9 +25,7 @@ #include "VMMDev.h" #include "AudioSnifferInterface.h" #include "Nvram.h" -#ifdef VBOX_WITH_USB_VIDEO -# include "UsbWebcamInterface.h" -#endif +#include "UsbWebcamInterface.h" #ifdef VBOX_WITH_USB_CARDREADER # include "UsbCardReader.h" #endif @@ -77,11 +75,9 @@ extern "C" DECLEXPORT(int) VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_ if (RT_FAILURE(rc)) return rc; -#ifdef VBOX_WITH_USB_VIDEO - rc = pCallbacks->pfnRegister(pCallbacks, &UsbWebcamInterface::DrvReg); + rc = pCallbacks->pfnRegister(pCallbacks, &EmWebcam::DrvReg); if (RT_FAILURE(rc)) return rc; -#endif #ifdef VBOX_WITH_USB_CARDREADER rc = pCallbacks->pfnRegister(pCallbacks, &UsbCardReader::DrvReg); diff --git a/src/VBox/Main/src-client/VMMDevInterface.cpp b/src/VBox/Main/src-client/VMMDevInterface.cpp index 5c3809fe..b4f4da47 100644 --- a/src/VBox/Main/src-client/VMMDevInterface.cpp +++ b/src/VBox/Main/src-client/VMMDevInterface.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -177,6 +177,30 @@ DECLCALLBACK(void) vmmdevUpdateGuestStatus(PPDMIVMMDEVCONNECTOR pInterface, uint } +/** + * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestUserState} + */ +DECLCALLBACK(void) vmmdevUpdateGuestUserState(PPDMIVMMDEVCONNECTOR pInterface, + const char *pszUser, const char *pszDomain, + uint32_t uState, + const uint8_t *puDetails, uint32_t cbDetails) +{ + PDRVMAINVMMDEV pDrv = PDMIVMMDEVCONNECTOR_2_MAINVMMDEV(pInterface); + AssertPtr(pDrv); + Console *pConsole = pDrv->pVMMDev->getParent(); + AssertPtr(pConsole); + + /* Store that information in IGuest. */ + Guest* pGuest = pConsole->getGuest(); + AssertPtr(pGuest); + if (!pGuest) + return; + + pGuest->onUserStateChange(Bstr(pszUser), Bstr(pszDomain), (VBoxGuestUserState)uState, + puDetails, cbDetails); +} + + /** * Reports Guest Additions API and OS version. * @@ -745,44 +769,39 @@ DECLCALLBACK(void *) VMMDev::drvQueryInterface(PPDMIBASE pInterface, const char } /** - * Destruct a VMMDev driver instance. - * - * @returns VBox status. - * @param pDrvIns The driver instance data. + * @interface_method_impl{PDMDRVREG,pfnReset} */ -DECLCALLBACK(void) VMMDev::drvDestruct(PPDMDRVINS pDrvIns) +DECLCALLBACK(void) VMMDev::drvReset(PPDMDRVINS pDrvIns) { - PDRVMAINVMMDEV pData = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); - LogFlow(("VMMDev::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); + LogFlow(("VMMDev::drvReset: iInstance=%d\n", pDrvIns->iInstance)); #ifdef VBOX_WITH_HGCM - /* HGCM is shut down on the VMMDev destructor. */ + HGCMHostReset (); #endif /* VBOX_WITH_HGCM */ - if (pData->pVMMDev) - pData->pVMMDev->mpDrv = NULL; } /** - * Reset notification. - * - * @returns VBox status. - * @param pDrvIns The driver instance data. + * @interface_method_impl{PDMDRVREG,pfnDestruct} */ -DECLCALLBACK(void) VMMDev::drvReset(PPDMDRVINS pDrvIns) +DECLCALLBACK(void) VMMDev::drvDestruct(PPDMDRVINS pDrvIns) { - LogFlow(("VMMDev::drvReset: iInstance=%d\n", pDrvIns->iInstance)); + PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + LogFlow(("VMMDev::drvDestruct: iInstance=%d\n", pDrvIns->iInstance)); + #ifdef VBOX_WITH_HGCM - HGCMHostReset (); + /* HGCM is shut down on the VMMDev destructor. */ #endif /* VBOX_WITH_HGCM */ + if (pThis->pVMMDev) + pThis->pVMMDev->mpDrv = NULL; } /** - * Construct a VMMDev driver instance. - * - * @copydoc FNPDMDRVCONSTRUCT + * @interface_method_impl{PDMDRVREG,pfnConstruct} */ DECLCALLBACK(int) VMMDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags) { - PDRVMAINVMMDEV pData = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV); LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); /* @@ -799,39 +818,40 @@ DECLCALLBACK(int) VMMDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, */ pDrvIns->IBase.pfnQueryInterface = VMMDev::drvQueryInterface; - pData->Connector.pfnUpdateGuestStatus = vmmdevUpdateGuestStatus; - pData->Connector.pfnUpdateGuestInfo = vmmdevUpdateGuestInfo; - pData->Connector.pfnUpdateGuestInfo2 = vmmdevUpdateGuestInfo2; - pData->Connector.pfnUpdateGuestCapabilities = vmmdevUpdateGuestCapabilities; - pData->Connector.pfnUpdateMouseCapabilities = vmmdevUpdateMouseCapabilities; - pData->Connector.pfnUpdatePointerShape = vmmdevUpdatePointerShape; - pData->Connector.pfnVideoAccelEnable = iface_VideoAccelEnable; - pData->Connector.pfnVideoAccelFlush = iface_VideoAccelFlush; - pData->Connector.pfnVideoModeSupported = vmmdevVideoModeSupported; - pData->Connector.pfnGetHeightReduction = vmmdevGetHeightReduction; - pData->Connector.pfnSetCredentialsJudgementResult = vmmdevSetCredentialsJudgementResult; - pData->Connector.pfnSetVisibleRegion = vmmdevSetVisibleRegion; - pData->Connector.pfnQueryVisibleRegion = vmmdevQueryVisibleRegion; - pData->Connector.pfnReportStatistics = vmmdevReportStatistics; - pData->Connector.pfnQueryStatisticsInterval = vmmdevQueryStatisticsInterval; - pData->Connector.pfnQueryBalloonSize = vmmdevQueryBalloonSize; - pData->Connector.pfnIsPageFusionEnabled = vmmdevIsPageFusionEnabled; + pThis->Connector.pfnUpdateGuestStatus = vmmdevUpdateGuestStatus; + pThis->Connector.pfnUpdateGuestUserState = vmmdevUpdateGuestUserState; + pThis->Connector.pfnUpdateGuestInfo = vmmdevUpdateGuestInfo; + pThis->Connector.pfnUpdateGuestInfo2 = vmmdevUpdateGuestInfo2; + pThis->Connector.pfnUpdateGuestCapabilities = vmmdevUpdateGuestCapabilities; + pThis->Connector.pfnUpdateMouseCapabilities = vmmdevUpdateMouseCapabilities; + pThis->Connector.pfnUpdatePointerShape = vmmdevUpdatePointerShape; + pThis->Connector.pfnVideoAccelEnable = iface_VideoAccelEnable; + pThis->Connector.pfnVideoAccelFlush = iface_VideoAccelFlush; + pThis->Connector.pfnVideoModeSupported = vmmdevVideoModeSupported; + pThis->Connector.pfnGetHeightReduction = vmmdevGetHeightReduction; + pThis->Connector.pfnSetCredentialsJudgementResult = vmmdevSetCredentialsJudgementResult; + pThis->Connector.pfnSetVisibleRegion = vmmdevSetVisibleRegion; + pThis->Connector.pfnQueryVisibleRegion = vmmdevQueryVisibleRegion; + pThis->Connector.pfnReportStatistics = vmmdevReportStatistics; + pThis->Connector.pfnQueryStatisticsInterval = vmmdevQueryStatisticsInterval; + pThis->Connector.pfnQueryBalloonSize = vmmdevQueryBalloonSize; + pThis->Connector.pfnIsPageFusionEnabled = vmmdevIsPageFusionEnabled; #ifdef VBOX_WITH_HGCM - pData->HGCMConnector.pfnConnect = iface_hgcmConnect; - pData->HGCMConnector.pfnDisconnect = iface_hgcmDisconnect; - pData->HGCMConnector.pfnCall = iface_hgcmCall; + pThis->HGCMConnector.pfnConnect = iface_hgcmConnect; + pThis->HGCMConnector.pfnDisconnect = iface_hgcmDisconnect; + pThis->HGCMConnector.pfnCall = iface_hgcmCall; #endif /* * Get the IVMMDevPort interface of the above driver/device. */ - pData->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIVMMDEVPORT); - AssertMsgReturn(pData->pUpPort, ("Configuration error: No VMMDev port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); + pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIVMMDEVPORT); + AssertMsgReturn(pThis->pUpPort, ("Configuration error: No VMMDev port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); #ifdef VBOX_WITH_HGCM - pData->pHGCMPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHGCMPORT); - AssertMsgReturn(pData->pHGCMPort, ("Configuration error: No HGCM port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); + pThis->pHGCMPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHGCMPORT); + AssertMsgReturn(pThis->pHGCMPort, ("Configuration error: No HGCM port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); #endif /* @@ -845,13 +865,13 @@ DECLCALLBACK(int) VMMDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, return rc; } - pData->pVMMDev = (VMMDev*)pv; /** @todo Check this cast! */ - pData->pVMMDev->mpDrv = pData; + pThis->pVMMDev = (VMMDev*)pv; /** @todo Check this cast! */ + pThis->pVMMDev->mpDrv = pThis; #ifdef VBOX_WITH_HGCM - rc = pData->pVMMDev->hgcmLoadService(VBOXSHAREDFOLDERS_DLL, + rc = pThis->pVMMDev->hgcmLoadService(VBOXSHAREDFOLDERS_DLL, "VBoxSharedFolders"); - pData->pVMMDev->fSharedFolderActive = RT_SUCCESS(rc); + pThis->pVMMDev->fSharedFolderActive = RT_SUCCESS(rc); if (RT_SUCCESS(rc)) { PPDMLED pLed; diff --git a/src/VBox/Main/src-client/VideoRec.cpp b/src/VBox/Main/src-client/VideoRec.cpp new file mode 100644 index 00000000..f47527e4 --- /dev/null +++ b/src/VBox/Main/src-client/VideoRec.cpp @@ -0,0 +1,885 @@ +/* $Id: VideoRec.cpp $ */ +/** @file + * Encodes the screen content in VPX format. + */ + +/* + * Copyright (C) 2012-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#define LOG_GROUP LOG_GROUP_MAIN +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "EbmlWriter.h" +#include "VideoRec.h" + +#define VPX_CODEC_DISABLE_COMPAT 1 +#include +#include + +/** Default VPX codec to use */ +#define DEFAULTCODEC (vpx_codec_vp8_cx()) + +static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStrm); +static int videoRecRGBToYUV(PVIDEORECSTREAM pStrm); + +/* state to synchronized between threads */ +enum +{ + VIDREC_UNINITIALIZED = 0, + /* initialized, idle */ + VIDREC_IDLE = 1, + /* currently in VideoRecCopyToIntBuf(), delay termination */ + VIDREC_COPYING = 2, + /* signal that we are terminating */ + VIDREC_TERMINATING = 3 +}; + +/* Must be always accessible and therefore cannot be part of VIDEORECCONTEXT */ +static uint32_t g_enmState = VIDREC_UNINITIALIZED; + + +typedef struct VIDEORECSTREAM +{ + /* container context */ + EbmlGlobal Ebml; + /* VPX codec context */ + vpx_codec_ctx_t VpxCodec; + /* VPX configuration */ + vpx_codec_enc_cfg_t VpxConfig; + /* X resolution */ + uint32_t uTargetWidth; + /* Y resolution */ + uint32_t uTargetHeight; + /* X resolution of the last encoded picture */ + uint32_t uLastSourceWidth; + /* Y resolution of the last encoded picture */ + uint32_t uLastSourceHeight; + /* current frame number */ + uint32_t cFrame; + /* RGB buffer containing the most recent frame of the framebuffer */ + uint8_t *pu8RgbBuf; + /* YUV buffer the encode function fetches the frame from */ + uint8_t *pu8YuvBuf; + /* VPX image context */ + vpx_image_t VpxRawImage; + /* true if video recording is enabled */ + bool fEnabled; + /* true if the RGB buffer is filled */ + bool fRgbFilled; + /* pixel format of the current frame */ + uint32_t u32PixelFormat; + /* minimal delay between two frames */ + uint32_t uDelay; + /* time stamp of the last frame we encoded */ + uint64_t u64LastTimeStamp; + /* time stamp of the current frame */ + uint64_t u64TimeStamp; +} VIDEORECSTREAM; + +typedef struct VIDEORECCONTEXT +{ + /* semaphore to signal the encoding worker thread */ + RTSEMEVENT WaitEvent; + /* semaphore required during termination */ + RTSEMEVENT TermEvent; + /* true if video recording is enabled */ + bool fEnabled; + /* worker thread */ + RTTHREAD Thread; + /* number of stream contexts */ + uint32_t cScreens; + /* video recording stream contexts */ + VIDEORECSTREAM Strm[1]; +} VIDEORECCONTEXT; + + +/** + * Iterator class for running through a BGRA32 image buffer and converting + * it to RGB. + */ +class ColorConvBGRA32Iter +{ +private: + enum { PIX_SIZE = 4 }; +public: + ColorConvBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf) + { + LogFlow(("width = %d height=%d aBuf=%lx\n", aWidth, aHeight, aBuf)); + mPos = 0; + mSize = aWidth * aHeight * PIX_SIZE; + mBuf = aBuf; + } + /** + * Convert the next pixel to RGB. + * @returns true on success, false if we have reached the end of the buffer + * @param aRed where to store the red value + * @param aGreen where to store the green value + * @param aBlue where to store the blue value + */ + bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue) + { + bool rc = false; + if (mPos + PIX_SIZE <= mSize) + { + *aRed = mBuf[mPos + 2]; + *aGreen = mBuf[mPos + 1]; + *aBlue = mBuf[mPos ]; + mPos += PIX_SIZE; + rc = true; + } + return rc; + } + + /** + * Skip forward by a certain number of pixels + * @param aPixels how many pixels to skip + */ + void skip(unsigned aPixels) + { + mPos += PIX_SIZE * aPixels; + } +private: + /** Size of the picture buffer */ + unsigned mSize; + /** Current position in the picture buffer */ + unsigned mPos; + /** Address of the picture buffer */ + uint8_t *mBuf; +}; + +/** + * Iterator class for running through an BGR24 image buffer and converting + * it to RGB. + */ +class ColorConvBGR24Iter +{ +private: + enum { PIX_SIZE = 3 }; +public: + ColorConvBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf) + { + mPos = 0; + mSize = aWidth * aHeight * PIX_SIZE; + mBuf = aBuf; + } + /** + * Convert the next pixel to RGB. + * @returns true on success, false if we have reached the end of the buffer + * @param aRed where to store the red value + * @param aGreen where to store the green value + * @param aBlue where to store the blue value + */ + bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue) + { + bool rc = false; + if (mPos + PIX_SIZE <= mSize) + { + *aRed = mBuf[mPos + 2]; + *aGreen = mBuf[mPos + 1]; + *aBlue = mBuf[mPos ]; + mPos += PIX_SIZE; + rc = true; + } + return rc; + } + + /** + * Skip forward by a certain number of pixels + * @param aPixels how many pixels to skip + */ + void skip(unsigned aPixels) + { + mPos += PIX_SIZE * aPixels; + } +private: + /** Size of the picture buffer */ + unsigned mSize; + /** Current position in the picture buffer */ + unsigned mPos; + /** Address of the picture buffer */ + uint8_t *mBuf; +}; + +/** + * Iterator class for running through an BGR565 image buffer and converting + * it to RGB. + */ +class ColorConvBGR565Iter +{ +private: + enum { PIX_SIZE = 2 }; +public: + ColorConvBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf) + { + mPos = 0; + mSize = aWidth * aHeight * PIX_SIZE; + mBuf = aBuf; + } + /** + * Convert the next pixel to RGB. + * @returns true on success, false if we have reached the end of the buffer + * @param aRed where to store the red value + * @param aGreen where to store the green value + * @param aBlue where to store the blue value + */ + bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue) + { + bool rc = false; + if (mPos + PIX_SIZE <= mSize) + { + unsigned uFull = (((unsigned) mBuf[mPos + 1]) << 8) + | ((unsigned) mBuf[mPos]); + *aRed = (uFull >> 8) & ~7; + *aGreen = (uFull >> 3) & ~3 & 0xff; + *aBlue = (uFull << 3) & ~7 & 0xff; + mPos += PIX_SIZE; + rc = true; + } + return rc; + } + + /** + * Skip forward by a certain number of pixels + * @param aPixels how many pixels to skip + */ + void skip(unsigned aPixels) + { + mPos += PIX_SIZE * aPixels; + } +private: + /** Size of the picture buffer */ + unsigned mSize; + /** Current position in the picture buffer */ + unsigned mPos; + /** Address of the picture buffer */ + uint8_t *mBuf; +}; + +/** + * Convert an image to YUV420p format + * @returns true on success, false on failure + * @param aWidth width of image + * @param aHeight height of image + * @param aDestBuf an allocated memory buffer large enough to hold the + * destination image (i.e. width * height * 12bits) + * @param aSrcBuf the source image as an array of bytes + */ +template +inline bool colorConvWriteYUV420p(unsigned aWidth, unsigned aHeight, + uint8_t *aDestBuf, uint8_t *aSrcBuf) +{ + AssertReturn(0 == (aWidth & 1), false); + AssertReturn(0 == (aHeight & 1), false); + bool rc = true; + T iter1(aWidth, aHeight, aSrcBuf); + T iter2 = iter1; + iter2.skip(aWidth); + unsigned cPixels = aWidth * aHeight; + unsigned offY = 0; + unsigned offU = cPixels; + unsigned offV = cPixels + cPixels / 4; + for (unsigned i = 0; (i < aHeight / 2) && rc; ++i) + { + for (unsigned j = 0; (j < aWidth / 2) && rc; ++j) + { + unsigned red, green, blue, u, v; + rc = iter1.getRGB(&red, &green, &blue); + if (rc) + { + aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; + u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; + v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; + rc = iter1.getRGB(&red, &green, &blue); + } + if (rc) + { + aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; + u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; + v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; + rc = iter2.getRGB(&red, &green, &blue); + } + if (rc) + { + aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; + u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; + v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; + rc = iter2.getRGB(&red, &green, &blue); + } + if (rc) + { + aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; + u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; + v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; + aDestBuf[offU] = u; + aDestBuf[offV] = v; + offY += 2; + ++offU; + ++offV; + } + } + if (rc) + { + iter1.skip(aWidth); + iter2.skip(aWidth); + offY += aWidth; + } + } + return rc; +} + +/** + * Convert an image to RGB24 format + * @returns true on success, false on failure + * @param aWidth width of image + * @param aHeight height of image + * @param aDestBuf an allocated memory buffer large enough to hold the + * destination image (i.e. width * height * 12bits) + * @param aSrcBuf the source image as an array of bytes + */ +template +inline bool colorConvWriteRGB24(unsigned aWidth, unsigned aHeight, + uint8_t *aDestBuf, uint8_t *aSrcBuf) +{ + enum { PIX_SIZE = 3 }; + bool rc = true; + AssertReturn(0 == (aWidth & 1), false); + AssertReturn(0 == (aHeight & 1), false); + T iter(aWidth, aHeight, aSrcBuf); + unsigned cPixels = aWidth * aHeight; + for (unsigned i = 0; i < cPixels && rc; ++i) + { + unsigned red, green, blue; + rc = iter.getRGB(&red, &green, &blue); + if (rc) + { + aDestBuf[i * PIX_SIZE ] = red; + aDestBuf[i * PIX_SIZE + 1] = green; + aDestBuf[i * PIX_SIZE + 2] = blue; + } + } + return rc; +} + +/** + * Worker thread for all streams. + * + * RGB/YUV conversion and encoding. + */ +static DECLCALLBACK(int) videoRecThread(RTTHREAD Thread, void *pvUser) +{ + PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)pvUser; + for (;;) + { + int rc = RTSemEventWait(pCtx->WaitEvent, RT_INDEFINITE_WAIT); + AssertRCBreak(rc); + + if (ASMAtomicReadU32(&g_enmState) == VIDREC_TERMINATING) + break; + for (unsigned uScreen = 0; uScreen < pCtx->cScreens; uScreen++) + { + PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen]; + if ( pStrm->fEnabled + && ASMAtomicReadBool(&pStrm->fRgbFilled)) + { + rc = videoRecRGBToYUV(pStrm); + ASMAtomicWriteBool(&pStrm->fRgbFilled, false); + if (RT_SUCCESS(rc)) + rc = videoRecEncodeAndWrite(pStrm); + if (RT_FAILURE(rc)) + { + static unsigned cErrors = 100; + if (cErrors > 0) + { + LogRel(("Error %Rrc encoding / writing video frame\n", rc)); + cErrors--; + } + } + } + } + } + + return VINF_SUCCESS; +} + +/** + * VideoRec utility function to create video recording context. + * + * @returns IPRT status code. + * @param ppCtx Video recording context + * @param cScreens Number of screens. + */ +int VideoRecContextCreate(PVIDEORECCONTEXT *ppCtx, uint32_t cScreens) +{ + Assert(ASMAtomicReadU32(&g_enmState) == VIDREC_UNINITIALIZED); + + PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)RTMemAllocZ(RT_OFFSETOF(VIDEORECCONTEXT, Strm[cScreens])); + *ppCtx = pCtx; + AssertPtrReturn(pCtx, VERR_NO_MEMORY); + + pCtx->cScreens = cScreens; + for (unsigned uScreen = 0; uScreen < cScreens; uScreen++) + pCtx->Strm[uScreen].Ebml.last_pts_ms = -1; + + int rc = RTSemEventCreate(&pCtx->WaitEvent); + AssertRCReturn(rc, rc); + + rc = RTSemEventCreate(&pCtx->TermEvent); + AssertRCReturn(rc, rc); + + rc = RTThreadCreate(&pCtx->Thread, videoRecThread, (void*)pCtx, 0, + RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE, "VideoRec"); + AssertRCReturn(rc, rc); + + ASMAtomicWriteU32(&g_enmState, VIDREC_IDLE); + return VINF_SUCCESS; +} + +/** + * VideoRec utility function to initialize video recording context. + * + * @returns IPRT status code. + * @param pCtx Pointer to video recording context to initialize Framebuffer width. + * @param uScreeen Screen number. + * @param strFile File to save the recorded data + * @param uTargetWidth Width of the target image in the video recoriding file (movie) + * @param uTargetHeight Height of the target image in video recording file. + */ +int VideoRecStrmInit(PVIDEORECCONTEXT pCtx, uint32_t uScreen, const char *pszFile, + uint32_t uWidth, uint32_t uHeight, uint32_t uRate, uint32_t uFps) +{ + AssertPtrReturn(pCtx, VERR_INVALID_PARAMETER); + AssertReturn(uScreen < pCtx->cScreens, VERR_INVALID_PARAMETER); + + PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen]; + pStrm->uTargetWidth = uWidth; + pStrm->uTargetHeight = uHeight; + pStrm->pu8RgbBuf = (uint8_t *)RTMemAllocZ(uWidth * uHeight * 4); + AssertReturn(pStrm->pu8RgbBuf, VERR_NO_MEMORY); + + /* Play safe: the file must not exist, overwriting is potentially + * hazardous as nothing prevents the user from picking a file name of some + * other important file, causing unintentional data loss. */ + int rc = RTFileOpen(&pStrm->Ebml.file, pszFile, + RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); + if (RT_FAILURE(rc)) + { + LogRel(("Failed to create the video capture output file \"%s\" (%Rrc)\n", pszFile, rc)); + return rc; + } + + vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &pStrm->VpxConfig, 0); + if (rcv != VPX_CODEC_OK) + { + LogFlow(("Failed to configure codec\n", vpx_codec_err_to_string(rcv))); + return VERR_INVALID_PARAMETER; + } + + /* target bitrate in kilobits per second */ + pStrm->VpxConfig.rc_target_bitrate = uRate; + /* frame width */ + pStrm->VpxConfig.g_w = uWidth; + /* frame height */ + pStrm->VpxConfig.g_h = uHeight; + /* 1ms per frame */ + pStrm->VpxConfig.g_timebase.num = 1; + pStrm->VpxConfig.g_timebase.den = 1000; + /* disable multithreading */ + pStrm->VpxConfig.g_threads = 0; + + pStrm->uDelay = 1000 / uFps; + + struct vpx_rational arg_framerate = { 30, 1 }; + rc = Ebml_WriteWebMFileHeader(&pStrm->Ebml, &pStrm->VpxConfig, &arg_framerate); + AssertRCReturn(rc, rc); + + /* Initialize codec */ + rcv = vpx_codec_enc_init(&pStrm->VpxCodec, DEFAULTCODEC, &pStrm->VpxConfig, 0); + if (rcv != VPX_CODEC_OK) + { + LogFlow(("Failed to initialize VP8 encoder %s", vpx_codec_err_to_string(rcv))); + return VERR_INVALID_PARAMETER; + } + + if (!vpx_img_alloc(&pStrm->VpxRawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1)) + { + LogFlow(("Failed to allocate image %dx%d", uWidth, uHeight)); + return VERR_NO_MEMORY; + } + pStrm->pu8YuvBuf = pStrm->VpxRawImage.planes[0]; + + pCtx->fEnabled = true; + pStrm->fEnabled = true; + return VINF_SUCCESS; +} + +/** + * VideoRec utility function to close the video recording context. + * + * @param pCtx Pointer to video recording context. + */ +void VideoRecContextClose(PVIDEORECCONTEXT pCtx) +{ + if (!pCtx) + return; + + uint32_t enmState = VIDREC_IDLE; + for (;;) + { + if (ASMAtomicCmpXchgExU32(&g_enmState, VIDREC_TERMINATING, enmState, &enmState)) + break; + if (enmState == VIDREC_UNINITIALIZED) + return; + } + if (enmState == VIDREC_COPYING) + { + int rc = RTSemEventWait(pCtx->TermEvent, RT_INDEFINITE_WAIT); + AssertRC(rc); + } + + RTSemEventSignal(pCtx->WaitEvent); + RTThreadWait(pCtx->Thread, 10000, NULL); + RTSemEventDestroy(pCtx->WaitEvent); + RTSemEventDestroy(pCtx->TermEvent); + + for (unsigned uScreen = 0; uScreen < pCtx->cScreens; uScreen++) + { + PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen]; + if (pStrm->fEnabled) + { + if (pStrm->Ebml.file != NIL_RTFILE) + { + int rc = Ebml_WriteWebMFileFooter(&pStrm->Ebml, 0); + AssertRC(rc); + RTFileClose(pStrm->Ebml.file); + pStrm->Ebml.file = NIL_RTFILE; + } + if (pStrm->Ebml.cue_list) + { + RTMemFree(pStrm->Ebml.cue_list); + pStrm->Ebml.cue_list = NULL; + } + vpx_img_free(&pStrm->VpxRawImage); + vpx_codec_err_t rcv = vpx_codec_destroy(&pStrm->VpxCodec); + Assert(rcv == VPX_CODEC_OK); + RTMemFree(pStrm->pu8RgbBuf); + pStrm->pu8RgbBuf = NULL; + } + } + + RTMemFree(pCtx); + + ASMAtomicWriteU32(&g_enmState, VIDREC_UNINITIALIZED); +} + +/** + * VideoRec utility function to check if recording is enabled. + * + * @returns true if recording is enabled + * @param pCtx Pointer to video recording context. + */ +bool VideoRecIsEnabled(PVIDEORECCONTEXT pCtx) +{ + uint32_t enmState = ASMAtomicReadU32(&g_enmState); + return ( enmState == VIDREC_IDLE + || enmState == VIDREC_COPYING); +} + +/** + * VideoRec utility function to check if recording engine is ready to accept a new frame + * for the given screen. + * + * @returns true if recording engine is ready + * @param pCtx Pointer to video recording context. + * @param uScreen screen id. + * @param u64TimeStamp current time stamp + */ +bool VideoRecIsReady(PVIDEORECCONTEXT pCtx, uint32_t uScreen, uint64_t u64TimeStamp) +{ + uint32_t enmState = ASMAtomicReadU32(&g_enmState); + if (enmState != VIDREC_IDLE) + return false; + + PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen]; + if (!pStrm->fEnabled) + return false; + + if (u64TimeStamp < pStrm->u64LastTimeStamp + pStrm->uDelay) + return false; + + if (ASMAtomicReadBool(&pStrm->fRgbFilled)) + return false; + + return true; +} + +/** + * VideoRec utility function to encode the source image and write the encoded + * image to target file. + * + * @returns IPRT status code. + * @param pCtx Pointer to video recording context. + * @param uSourceWidth Width of the source image. + * @param uSourceHeight Height of the source image. + */ +static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStrm) +{ + /* presentation time stamp */ + vpx_codec_pts_t pts = pStrm->u64TimeStamp; + vpx_codec_err_t rcv = vpx_codec_encode(&pStrm->VpxCodec, + &pStrm->VpxRawImage, + pts /* time stamp */, + 10 /* how long to show this frame */, + 0 /* flags */, + VPX_DL_REALTIME /* deadline */); + if (rcv != VPX_CODEC_OK) + { + LogFlow(("Failed to encode:%s\n", vpx_codec_err_to_string(rcv))); + return VERR_GENERAL_FAILURE; + } + + vpx_codec_iter_t iter = NULL; + int rc = VERR_NO_DATA; + for (;;) + { + const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(&pStrm->VpxCodec, &iter); + if (!pkt) + break; + switch (pkt->kind) + { + case VPX_CODEC_CX_FRAME_PKT: + rc = Ebml_WriteWebMBlock(&pStrm->Ebml, &pStrm->VpxConfig, pkt); + break; + default: + LogFlow(("Unexpected CODEC Packet.\n")); + break; + } + } + + pStrm->cFrame++; + return rc; +} + +/** + * VideoRec utility function to convert RGB to YUV. + * + * @returns IPRT status code. + * @param pCtx Pointer to video recording context. + */ +static int videoRecRGBToYUV(PVIDEORECSTREAM pStrm) +{ + switch (pStrm->u32PixelFormat) + { + case VPX_IMG_FMT_RGB32: + LogFlow(("32 bit\n")); + if (!colorConvWriteYUV420p(pStrm->uTargetWidth, + pStrm->uTargetHeight, + pStrm->pu8YuvBuf, + pStrm->pu8RgbBuf)) + return VERR_GENERAL_FAILURE; + break; + case VPX_IMG_FMT_RGB24: + LogFlow(("24 bit\n")); + if (!colorConvWriteYUV420p(pStrm->uTargetWidth, + pStrm->uTargetHeight, + pStrm->pu8YuvBuf, + pStrm->pu8RgbBuf)) + return VERR_GENERAL_FAILURE; + break; + case VPX_IMG_FMT_RGB565: + LogFlow(("565 bit\n")); + if (!colorConvWriteYUV420p(pStrm->uTargetWidth, + pStrm->uTargetHeight, + pStrm->pu8YuvBuf, + pStrm->pu8RgbBuf)) + return VERR_GENERAL_FAILURE; + break; + default: + return VERR_GENERAL_FAILURE; + } + return VINF_SUCCESS; +} + +/** + * VideoRec utility function to copy a source image (FrameBuf) to the intermediate + * RGB buffer. This function is executed only once per time. + * + * @thread EMT + * + * @returns IPRT status code. + * @param pCtx Pointer to the video recording context. + * @param uScreen Screen number. + * @param x Starting x coordinate of the source buffer (Framebuffer). + * @param y Starting y coordinate of the source buffer (Framebuffer). + * @param uPixelFormat Pixel Format. + * @param uBitsPerPixel Bits Per Pixel + * @param uBytesPerLine Bytes per source scanlineName. + * @param uSourceWidth Width of the source image (framebuffer). + * @param uSourceHeight Height of the source image (framebuffer). + * @param pu8BufAddr Pointer to source image(framebuffer). + * @param u64TimeStamp Time stamp (milliseconds). + */ +int VideoRecCopyToIntBuf(PVIDEORECCONTEXT pCtx, uint32_t uScreen, uint32_t x, uint32_t y, + uint32_t uPixelFormat, uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uSourceWidth, uint32_t uSourceHeight, uint8_t *pu8BufAddr, + uint64_t u64TimeStamp) +{ + /* Do not execute during termination and guard against termination */ + if (!ASMAtomicCmpXchgU32(&g_enmState, VIDREC_COPYING, VIDREC_IDLE)) + return VINF_TRY_AGAIN; + + int rc = VINF_SUCCESS; + do + { + AssertPtrBreakStmt(pu8BufAddr, rc = VERR_INVALID_PARAMETER); + AssertBreakStmt(uSourceWidth, rc = VERR_INVALID_PARAMETER); + AssertBreakStmt(uSourceHeight, rc = VERR_INVALID_PARAMETER); + AssertBreakStmt(uScreen < pCtx->cScreens, rc = VERR_INVALID_PARAMETER); + + PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen]; + if (!pStrm->fEnabled) + { + rc = VINF_TRY_AGAIN; /* not (yet) enabled */ + break; + } + if (u64TimeStamp < pStrm->u64LastTimeStamp + pStrm->uDelay) + { + rc = VINF_TRY_AGAIN; /* respect maximum frames per second */ + break; + } + if (ASMAtomicReadBool(&pStrm->fRgbFilled)) + { + rc = VERR_TRY_AGAIN; /* previous frame not yet encoded */ + break; + } + + pStrm->u64LastTimeStamp = u64TimeStamp; + + int xDiff = ((int)pStrm->uTargetWidth - (int)uSourceWidth) / 2; + uint32_t w = uSourceWidth; + if ((int)w + xDiff + (int)x <= 0) /* nothing visible */ + { + rc = VERR_INVALID_PARAMETER; + break; + } + + uint32_t destX; + if ((int)x < -xDiff) + { + w += xDiff + x; + x = -xDiff; + destX = 0; + } + else + destX = x + xDiff; + + uint32_t h = uSourceHeight; + int yDiff = ((int)pStrm->uTargetHeight - (int)uSourceHeight) / 2; + if ((int)h + yDiff + (int)y <= 0) /* nothing visible */ + { + rc = VERR_INVALID_PARAMETER; + break; + } + + uint32_t destY; + if ((int)y < -yDiff) + { + h += yDiff + (int)y; + y = -yDiff; + destY = 0; + } + else + destY = y + yDiff; + + if ( destX > pStrm->uTargetWidth + || destY > pStrm->uTargetHeight) + { + rc = VERR_INVALID_PARAMETER; /* nothing visible */ + break; + } + + if (destX + w > pStrm->uTargetWidth) + w = pStrm->uTargetWidth - destX; + + if (destY + h > pStrm->uTargetHeight) + h = pStrm->uTargetHeight - destY; + + /* Calculate bytes per pixel */ + uint32_t bpp = 1; + if (uPixelFormat == FramebufferPixelFormat_FOURCC_RGB) + { + switch (uBitsPerPixel) + { + case 32: + pStrm->u32PixelFormat = VPX_IMG_FMT_RGB32; + bpp = 4; + break; + case 24: + pStrm->u32PixelFormat = VPX_IMG_FMT_RGB24; + bpp = 3; + break; + case 16: + pStrm->u32PixelFormat = VPX_IMG_FMT_RGB565; + bpp = 2; + break; + default: + AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBitsPerPixel)); + break; + } + } + else + AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", uPixelFormat)); + + /* One of the dimensions of the current frame is smaller than before so + * clear the entire buffer to prevent artifacts from the previous frame */ + if ( uSourceWidth < pStrm->uLastSourceWidth + || uSourceHeight < pStrm->uLastSourceHeight) + memset(pStrm->pu8RgbBuf, 0, pStrm->uTargetWidth * pStrm->uTargetHeight * 4); + + pStrm->uLastSourceWidth = uSourceWidth; + pStrm->uLastSourceHeight = uSourceHeight; + + /* Calculate start offset in source and destination buffers */ + uint32_t offSrc = y * uBytesPerLine + x * bpp; + uint32_t offDst = (destY * pStrm->uTargetWidth + destX) * bpp; + /* do the copy */ + for (unsigned int i = 0; i < h; i++) + { + /* Overflow check */ + Assert(offSrc + w * bpp <= uSourceHeight * uBytesPerLine); + Assert(offDst + w * bpp <= pStrm->uTargetHeight * pStrm->uTargetWidth * bpp); + memcpy(pStrm->pu8RgbBuf + offDst, pu8BufAddr + offSrc, w * bpp); + offSrc += uBytesPerLine; + offDst += pStrm->uTargetWidth * bpp; + } + + pStrm->u64TimeStamp = u64TimeStamp; + + ASMAtomicWriteBool(&pStrm->fRgbFilled, true); + RTSemEventSignal(pCtx->WaitEvent); + } while (0); + + if (!ASMAtomicCmpXchgU32(&g_enmState, VIDREC_IDLE, VIDREC_COPYING)) + { + rc = RTSemEventSignal(pCtx->TermEvent); + AssertRC(rc); + } + + return rc; +} diff --git a/src/VBox/Main/src-client/VideoRec.h b/src/VBox/Main/src-client/VideoRec.h new file mode 100644 index 00000000..7d0d6fa3 --- /dev/null +++ b/src/VBox/Main/src-client/VideoRec.h @@ -0,0 +1,39 @@ +/* $Id: VideoRec.h $ */ +/** @file + * Encodes the screen content in VPX format. + */ + +/* + * Copyright (C) 2012-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_VIDEOREC +#define ____H_VIDEOREC + +struct VIDEORECCONTEXT; +typedef struct VIDEORECCONTEXT *PVIDEORECCONTEXT; + +struct VIDEORECSTREAM; +typedef struct VIDEORECSTREAM *PVIDEORECSTREAM; + +int VideoRecContextCreate(PVIDEORECCONTEXT *ppCtx, uint32_t cScreens); +int VideoRecStrmInit(PVIDEORECCONTEXT pCtx, uint32_t uScreen, const char *pszFile, + uint32_t uWidth, uint32_t uHeight, uint32_t uRate, uint32_t uFps); +void VideoRecContextClose(PVIDEORECCONTEXT pCtx); +bool VideoRecIsEnabled(PVIDEORECCONTEXT pCtx); +int VideoRecCopyToIntBuf(PVIDEORECCONTEXT pCtx, uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBitsPerPixel, + uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp); +bool VideoRecIsReady(PVIDEORECCONTEXT pCtx, uint32_t uScreen, uint64_t u64TimeStamp); + +#endif /* !____H_VIDEOREC */ + diff --git a/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp b/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp index 94ed652d..0e2405af 100644 --- a/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp +++ b/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,6 +20,7 @@ #include "AutoCaller.h" #include "VBoxEvents.h" #include "Logging.h" +#include "VBox/com/ErrorInfo.h" #include #include @@ -80,7 +81,7 @@ HRESULT VirtualBoxClient::init() rc = unconst(mData.m_pEventSource).createObject(); AssertComRCReturnRC(rc); - rc = mData.m_pEventSource->init(static_cast(this)); + rc = mData.m_pEventSource->init(); AssertComRCReturnRC(rc); /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it @@ -200,6 +201,37 @@ STDMETHODIMP VirtualBoxClient::COMGETTER(EventSource)(IEventSource **aEventSourc return mData.m_pEventSource.isNull() ? E_FAIL : S_OK; } +/** + * Checks a Machine object for any pending errors. + * + * @returns COM status code + * @param aMachine Machine object to check. + */ +STDMETHODIMP VirtualBoxClient::CheckMachineError(IMachine *aMachine) +{ + HRESULT rc; + CheckComArgNotNull(aMachine); + + BOOL fAccessible = FALSE; + rc = aMachine->COMGETTER(Accessible)(&fAccessible); + if (FAILED(rc)) + return setError(rc, tr("Could not check the accessibility status of the VM")); + else if (!fAccessible) + { + ComPtr pAccessError; + rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam()); + if (FAILED(rc)) + return setError(rc, tr("Could not get the access error message of the VM")); + else + { + ErrorInfo info(pAccessError); + ErrorInfoKeeper eik(info); + return info.getResultCode(); + } + } + return S_OK; +} + // private methods ///////////////////////////////////////////////////////////////////////////// diff --git a/src/VBox/Main/src-client/win/VBoxC.def b/src/VBox/Main/src-client/win/VBoxC.def index 360d0f8e..250b9372 100644 --- a/src/VBox/Main/src-client/win/VBoxC.def +++ b/src/VBox/Main/src-client/win/VBoxC.def @@ -3,7 +3,7 @@ ; VBoxC DLL Definition File. ; -; Copyright (C) 2006-2007 Oracle Corporation +; Copyright (C) 2006-2010 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-client/win/VBoxClient-x86.def b/src/VBox/Main/src-client/win/VBoxClient-x86.def new file mode 100644 index 00000000..c6894441 --- /dev/null +++ b/src/VBox/Main/src-client/win/VBoxClient-x86.def @@ -0,0 +1,26 @@ +; $Id: VBoxClient-x86.def $ +;; @file +; VBoxClient-x86 DLL Definition File. +; + +; +; Copyright (C) 2006-2013 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; + +LIBRARY VBoxClient-x86.dll + +EXPORTS + ; COM entry points + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/src/VBox/Main/src-client/win/VBoxClient-x86.rc b/src/VBox/Main/src-client/win/VBoxClient-x86.rc new file mode 100644 index 00000000..d5c4ae09 --- /dev/null +++ b/src/VBox/Main/src-client/win/VBoxClient-x86.rc @@ -0,0 +1,67 @@ +/* $Id: VBoxClient-x86.rc $ */ +/** @file + * VBoxC - Resource file containing version info and icon. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include + +#include "win/resource.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + PRODUCTVERSION VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG|VS_FF_PRIVATEBUILD|VS_FF_PRERELEASE +#else + FILEFLAGS 0 // final version +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual + BEGIN + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileDescription", "VirtualBox Interface (32-bit)\0" + VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0" + VALUE "InternalName", "VBoxClient-x86.dll\0" + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "OriginalFilename","VBoxClient-x86.dll\0" + VALUE "ProductName", VBOX_PRODUCT "\0" + VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD ".r" VBOX_SVN_REV "\0" + + VALUE "OLESelfRegister", "" + + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_VIRTUALBOX REGISTRY "VBoxClient-x86.rgs" + +1 TYPELIB "VirtualBox-x86.tlb" + diff --git a/src/VBox/Main/src-client/win/dllmain.cpp b/src/VBox/Main/src-client/win/dllmain.cpp index db1181cb..2410e97c 100644 --- a/src/VBox/Main/src-client/win/dllmain.cpp +++ b/src/VBox/Main/src-client/win/dllmain.cpp @@ -1,11 +1,10 @@ +/* $Id: dllmain.cpp $ */ /** @file - * - * DLLMAIN - COM DLL exports - * + * VBoxC - COM DLL exports and DLL init/term. */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -16,6 +15,10 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ #include "VBox/com/defs.h" #include @@ -25,7 +28,13 @@ #include #include +#include +#include + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) @@ -33,6 +42,46 @@ BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_VirtualBoxClient, VirtualBoxClient) END_OBJECT_MAP() + +/** @def WITH_MANUAL_CLEANUP + * Manually clean up the registry. */ +#if defined(DEBUG) && !defined(VBOX_IN_32_ON_64_MAIN_API) +//# define WITH_MANUAL_CLEANUP +#endif + + +#ifdef WITH_MANUAL_CLEANUP +/** Type library GUIDs to clean up manually. */ +static const char * const g_apszTypelibGuids[] = +{ + "{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}", + "{d7569351-1750-46f0-936e-bd127d5bc264}", +}; + +/** Same as above but with a "Typelib\\" prefix. */ +static const char * const g_apszTypelibGuidKeys[] = +{ + "TypeLib\\{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}", + "TypeLib\\{d7569351-1750-46f0-936e-bd127d5bc264}", +}; + +/** Type library version to clean up manually. */ +static const char * const g_apszTypelibVersions[] = +{ + "1.0", + "1.3", +}; +#endif + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +#ifdef WITH_MANUAL_CLEANUP +static void removeOldMess(void); +#endif + + ///////////////////////////////////////////////////////////////////////////// // DLL Entry Point @@ -45,7 +94,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) DisableThreadLibraryCalls(hInstance); // idempotent, so doesn't harm, and needed for COM embedding scenario - RTR3InitDll(0); + RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); } else if (dwReason == DLL_PROCESS_DETACH) { @@ -84,5 +133,271 @@ STDAPI DllRegisterServer(void) STDAPI DllUnregisterServer(void) { - return _Module.UnregisterServer(TRUE); + HRESULT hrc = _Module.UnregisterServer(TRUE); +#ifdef WITH_MANUAL_CLEANUP + removeOldMess(); +#endif + return hrc; } + +#ifdef WITH_MANUAL_CLEANUP + +/** + * Checks if the typelib GUID is one of the ones we wish to clean up. + * + * @returns true if it should be cleaned up, false if not. + * @param pszTypelibGuid The typelib GUID as bracketed string. + */ +static bool isTypelibGuidToRemove(const char *pszTypelibGuid) +{ + unsigned i = RT_ELEMENTS(g_apszTypelibGuids); + while (i-- > 0) + if (!stricmp(g_apszTypelibGuids[i], pszTypelibGuid)) + return true; + return false; +} + + +/** + * Checks if the typelib version is one of the ones we wish to clean up. + * + * @returns true if it should be cleaned up, false if not. + * @param pszTypelibVer The typelib version as string. + */ +static bool isTypelibVersionToRemove(const char *pszTypelibVer) +{ + unsigned i = RT_ELEMENTS(g_apszTypelibVersions); + while (i-- > 0) + if (!strcmp(g_apszTypelibVersions[i], pszTypelibVer)) + return true; + return false; +} + + +/** + * Hack to clean out the class IDs belonging to obsolete typelibs on development + * boxes and such likes. + */ +static void removeOldClassIDs(HKEY hkeyClassesRoot) +{ + HKEY hkeyClsId; + LONG rc = RegOpenKeyExA(hkeyClassesRoot, "CLSID", NULL, DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, + &hkeyClsId); + if (rc == ERROR_SUCCESS) + { + for (DWORD idxKey = 0;; idxKey++) + { + char szCurNm[128 + 128]; + DWORD cbCurNm = 128; + rc = RegEnumKeyExA(hkeyClsId, idxKey, szCurNm, &cbCurNm, NULL, NULL, NULL, NULL); + if (rc == ERROR_NO_MORE_ITEMS) + break; + + /* + * Get the typelib GUID and program ID with the class ID. + */ + AssertBreak(rc == ERROR_SUCCESS); + strcpy(&szCurNm[cbCurNm], "\\TypeLib"); + HKEY hkeyIfTypelib; + rc = RegOpenKeyExA(hkeyClsId, szCurNm, NULL, KEY_QUERY_VALUE, &hkeyIfTypelib); + if (rc != ERROR_SUCCESS) + continue; + + char szTypelibGuid[128]; + DWORD cbValue = sizeof(szTypelibGuid) - 1; + rc = RegQueryValueExA(hkeyIfTypelib, NULL, NULL, NULL, (PBYTE)&szTypelibGuid[0], &cbValue); + if (rc != ERROR_SUCCESS) + cbValue = 0; + szTypelibGuid[cbValue] = '\0'; + RegCloseKey(hkeyIfTypelib); + if (!isTypelibGuidToRemove(szTypelibGuid)) + continue; + + /* ProgId */ + strcpy(&szCurNm[cbCurNm], "\\ProgId"); + HKEY hkeyIfProgId; + rc = RegOpenKeyExA(hkeyClsId, szCurNm, NULL, KEY_QUERY_VALUE, &hkeyIfProgId); + if (rc != ERROR_SUCCESS) + continue; + + char szProgId[64]; + cbValue = sizeof(szProgId) - 1; + rc = RegQueryValueExA(hkeyIfProgId, NULL, NULL, NULL, (PBYTE)&szProgId[0], &cbValue); + if (rc != ERROR_SUCCESS) + cbValue = 0; + szProgId[cbValue] = '\0'; + RegCloseKey(hkeyIfProgId); + if (strnicmp(szProgId, RT_STR_TUPLE("VirtualBox."))) + continue; + + /* + * Ok, it's an orphaned VirtualBox interface. Delete it. + */ + szCurNm[cbCurNm] = '\0'; + RTAssertMsg2("Should delete HCR/CLSID/%s\n", szCurNm); + //rc = SHDeleteKeyA(hkeyClsId, szCurNm); + Assert(rc == ERROR_SUCCESS); + } + + RegCloseKey(hkeyClsId); + } +} + + +/** + * Hack to clean out the interfaces belonging to obsolete typelibs on + * development boxes and such likes. + */ +static void removeOldInterfaces(HKEY hkeyClassesRoot) +{ + HKEY hkeyInterface; + LONG rc = RegOpenKeyExA(hkeyClassesRoot, "Interface", NULL, DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, + &hkeyInterface); + if (rc == ERROR_SUCCESS) + { + for (DWORD idxKey = 0;; idxKey++) + { + char szCurNm[128 + 128]; + DWORD cbCurNm = 128; + rc = RegEnumKeyExA(hkeyInterface, idxKey, szCurNm, &cbCurNm, NULL, NULL, NULL, NULL); + if (rc == ERROR_NO_MORE_ITEMS) + break; + + /* + * Get the typelib GUID and version associated with the interface. + */ + AssertBreak(rc == ERROR_SUCCESS); + strcpy(&szCurNm[cbCurNm], "\\TypeLib"); + HKEY hkeyIfTypelib; + rc = RegOpenKeyExA(hkeyInterface, szCurNm, NULL, KEY_QUERY_VALUE, &hkeyIfTypelib); + if (rc != ERROR_SUCCESS) + continue; + + char szTypelibGuid[128]; + DWORD cbValue = sizeof(szTypelibGuid) - 1; + rc = RegQueryValueExA(hkeyIfTypelib, NULL, NULL, NULL, (PBYTE)&szTypelibGuid[0], &cbValue); + if (rc != ERROR_SUCCESS) + cbValue = 0; + szTypelibGuid[cbValue] = '\0'; + if (!isTypelibGuidToRemove(szTypelibGuid)) + { + RegCloseKey(hkeyIfTypelib); + continue; + } + + char szTypelibVer[64]; + cbValue = sizeof(szTypelibVer) - 1; + rc = RegQueryValueExA(hkeyIfTypelib, "Version", NULL, NULL, (PBYTE)&szTypelibVer[0], &cbValue); + if (rc != ERROR_SUCCESS) + cbValue = 0; + szTypelibVer[cbValue] = '\0'; + + RegCloseKey(hkeyIfTypelib); + + if (!isTypelibVersionToRemove(szTypelibVer)) + continue; + + + /* + * Ok, it's an orphaned VirtualBox interface. Delete it. + */ + szCurNm[cbCurNm] = '\0'; + //RTAssertMsg2("Should delete HCR/Interface/%s\n", szCurNm); + rc = SHDeleteKeyA(hkeyInterface, szCurNm); + Assert(rc == ERROR_SUCCESS); + } + + RegCloseKey(hkeyInterface); + } +} + + +/** + * Hack to clean obsolete typelibs on development boxes and such. + */ +static void removeOldTypelib(HKEY hkeyClassesRoot) +{ + /* + * Open it and verify the identity. + */ + unsigned i = RT_ELEMENTS(g_apszTypelibGuidKeys); + while (i-- > 0) + { + HKEY hkeyTyplib; + LONG rc = RegOpenKeyExA(hkeyClassesRoot, g_apszTypelibGuidKeys[i], NULL, + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hkeyTyplib); + if (rc == ERROR_SUCCESS) + { + unsigned iVer = RT_ELEMENTS(g_apszTypelibVersions); + while (iVer-- > 0) + { + HKEY hkeyVer; + rc = RegOpenKeyExA(hkeyTyplib, g_apszTypelibVersions[iVer], NULL, KEY_READ, &hkeyVer); + if (rc == ERROR_SUCCESS) + { + char szValue[128]; + DWORD cbValue = sizeof(szValue) - 1; + rc = RegQueryValueExA(hkeyVer, NULL, NULL, NULL, (PBYTE)&szValue[0], &cbValue); + if (rc == ERROR_SUCCESS) + { + szValue[cbValue] = '\0'; + if (!strcmp(szValue, "VirtualBox Type Library")) + { + RegCloseKey(hkeyVer); + hkeyVer = NULL; + + /* + * Delete the type library. + */ + //RTAssertMsg2("Should delete HCR\\%s\\%s\n", g_apszTypelibGuidKeys[i], g_apszTypelibVersions[iVer]); + rc = SHDeleteKeyA(hkeyTyplib, g_apszTypelibVersions[iVer]); + Assert(rc == ERROR_SUCCESS); + } + } + + if (hkeyVer != NULL) + RegCloseKey(hkeyVer); + } + } + RegCloseKey(hkeyTyplib); + + /* + * The typelib key should be empty now, so we can try remove it (non-recursively). + */ + rc = RegDeleteKeyA(hkeyClassesRoot, g_apszTypelibGuidKeys[i]); + Assert(rc == ERROR_SUCCESS); + } + } +} + + +/** + * Hack to clean out obsolete typelibs on development boxes and such. + */ +static void removeOldMess(void) +{ + /* + * The standard location. + */ + removeOldTypelib(HKEY_CLASSES_ROOT); + removeOldInterfaces(HKEY_CLASSES_ROOT); + removeOldClassIDs(HKEY_CLASSES_ROOT); + + /* + * Wow64 if present. + */ + HKEY hkeyWow64; + LONG rc = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Wow6432Node", NULL, + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hkeyWow64); + if (rc == ERROR_SUCCESS) + { + removeOldTypelib(hkeyWow64); + removeOldInterfaces(hkeyWow64); + removeOldClassIDs(hkeyWow64); + + RegCloseKey(hkeyWow64); + } +} + +#endif /* WITH_MANUAL_CLEANUP */ + diff --git a/src/VBox/Main/src-client/xpcom/module.cpp b/src/VBox/Main/src-client/xpcom/module.cpp index e646a3bd..f66603d6 100644 --- a/src/VBox/Main/src-client/xpcom/module.cpp +++ b/src/VBox/Main/src-client/xpcom/module.cpp @@ -48,7 +48,6 @@ #include "MouseImpl.h" #include "NATEngineImpl.h" #include "NetworkAdapterImpl.h" -#include "ProgressCombinedImpl.h" #include "ProgressImpl.h" #include "RemoteUSBDeviceImpl.h" #include "SessionImpl.h" @@ -60,9 +59,15 @@ // XPCOM glue code unfolding +NS_DECL_CLASSINFO(VirtualBoxClient) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBoxClient, IVirtualBoxClient) +NS_DECL_CLASSINFO(Session) +NS_IMPL_THREADSAFE_ISUPPORTS2_CI(Session, ISession, IInternalSessionControl) + +#ifndef VBOX_COM_INPROC_API_CLIENT NS_DECL_CLASSINFO(Guest) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Guest, IGuest) -#ifdef VBOX_WITH_GUEST_CONTROL + #ifdef VBOX_WITH_GUEST_CONTROL NS_DECL_CLASSINFO(GuestDirectory) NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestDirectory, IGuestDirectory, IDirectory) NS_DECL_CLASSINFO(GuestFile) @@ -73,7 +78,7 @@ NS_DECL_CLASSINFO(GuestProcess) NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestProcess, IGuestProcess, IProcess) NS_DECL_CLASSINFO(GuestSession) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestSession, IGuestSession) -#endif + #endif NS_DECL_CLASSINFO(Keyboard) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Keyboard, IKeyboard) NS_DECL_CLASSINFO(Mouse) @@ -84,8 +89,6 @@ NS_DECL_CLASSINFO(MachineDebugger) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MachineDebugger, IMachineDebugger) NS_DECL_CLASSINFO(Progress) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress) -NS_DECL_CLASSINFO(CombinedProgress) -NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress) NS_DECL_CLASSINFO(OUSBDevice) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(OUSBDevice, IUSBDevice) NS_DECL_CLASSINFO(RemoteUSBDevice) @@ -94,24 +97,22 @@ NS_DECL_CLASSINFO(SharedFolder) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder) NS_DECL_CLASSINFO(VRDEServerInfo) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDEServerInfo, IVRDEServerInfo) -#ifdef VBOX_WITH_EXTPACK -NS_DECL_CLASSINFO(ExtPackFile) -NS_IMPL_THREADSAFE_ISUPPORTS2_CI(ExtPackFile, IExtPackFile, IExtPackBase) + #ifdef VBOX_WITH_EXTPACK +// deliberately omit ExtPackFile as it's unusable in the client context +// NS_DECL_CLASSINFO(ExtPackFile) +// NS_IMPL_THREADSAFE_ISUPPORTS2_CI(ExtPackFile, IExtPackFile, IExtPackBase) NS_DECL_CLASSINFO(ExtPack) NS_IMPL_THREADSAFE_ISUPPORTS2_CI(ExtPack, IExtPack, IExtPackBase) NS_DECL_CLASSINFO(ExtPackManager) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ExtPackManager, IExtPackManager) -#endif + #endif NS_DECL_CLASSINFO(AdditionsFacility) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AdditionsFacility, IAdditionsFacility) -NS_DECL_CLASSINFO(Session) -NS_IMPL_THREADSAFE_ISUPPORTS2_CI(Session, ISession, IInternalSessionControl) NS_DECL_CLASSINFO(Console) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Console, IConsole) -NS_DECL_CLASSINFO(VirtualBoxClient) -NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBoxClient, IVirtualBoxClient) +#endif /* VBOX_COM_INPROC_API_CLIENT */ /** * Singleton class factory that holds a reference to the created instance diff --git a/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp b/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp index 6929eb7e..21d97de8 100644 --- a/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp +++ b/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp @@ -1087,7 +1087,7 @@ static RTEXITCODE DoCleanup(int argc, char **argv) char *pszMarker = strstr(Entry.szName, "-_-"); if ( pszMarker && ( !strcmp(pszMarker, "-_-uninst") - || !strncmp(pszMarker, "-_-inst", sizeof("-_-inst") - 1))) + || !strncmp(pszMarker, RT_STR_TUPLE("-_-inst")))) fCandidate = VBoxExtPackIsValidMangledName(Entry.szName, pszMarker - &Entry.szName[0]); if (fCandidate) { @@ -1767,7 +1767,11 @@ int main(int argc, char **argv) /* * Initialize IPRT and check that we're correctly installed. */ +#ifdef RT_OS_WINDOWS + int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_UTF8_ARGV); /* WinMain gives us UTF-8, see below. */ +#else int rc = RTR3InitExe(argc, &argv, 0); +#endif if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); diff --git a/src/VBox/Main/src-helper-apps/VBoxVolInfo.cpp b/src/VBox/Main/src-helper-apps/VBoxVolInfo.cpp new file mode 100644 index 00000000..ec1c265d --- /dev/null +++ b/src/VBox/Main/src-helper-apps/VBoxVolInfo.cpp @@ -0,0 +1,96 @@ +/* $Id: VBoxVolInfo.cpp $ */ +/** @file + * Apps - VBoxVolInfo, Volume information tool. + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +extern "C" +{ +#define private privatekw +#include +} +#include +#include +#include +#include + +/******************************************************************************* +* Function Prototypes * +*******************************************************************************/ +void print_dev_name(dev_t devid); + +/* + * Extracts logical volume dependencies via devmapper API and print them out. + */ +int main(int argc, char **argv) +{ + struct dm_task *dmtask; + struct dm_info dminfo; + + if (argc != 2) + { + fprintf(stderr, "USAGE: %s \n", argv[0]); + return 1; + } + + dmtask = dm_task_create(DM_DEVICE_DEPS); + if (!dmtask) + return 2; + + if (dm_task_set_name(dmtask, argv[1])) + if (dm_task_run(dmtask)) + if (dm_task_get_info(dmtask, &dminfo)) + { + struct dm_deps *dmdeps = dm_task_get_deps(dmtask); + if (dmdeps) + { + unsigned i; + for (i = 0; i < dmdeps->count; ++i) + print_dev_name(dmdeps->device[i]); + } + } + + dm_task_destroy(dmtask); + return 0; +} + +/* + * Looks up device name by id using /dev directory. Prints it to stdout. + */ +void print_dev_name(dev_t devid) +{ + char path[PATH_MAX]; + struct dirent *de; + DIR *dir = opendir("/dev"); + + while ((de = readdir(dir)) != NULL) + { + struct stat st; + snprintf(path, sizeof(path), "/dev/%s", de->d_name); + if (!stat(path, &st)) + if (S_ISBLK(st.st_mode)) + if (devid == st.st_rdev) + { + puts(de->d_name); + break; + } + } + closedir(dir); +} diff --git a/src/VBox/Main/src-server/ApplianceImpl.cpp b/src/VBox/Main/src-server/ApplianceImpl.cpp index 05fc3b67..8d1e6014 100644 --- a/src/VBox/Main/src-server/ApplianceImpl.cpp +++ b/src/VBox/Main/src-server/ApplianceImpl.cpp @@ -1,11 +1,10 @@ /* $Id: ApplianceImpl.cpp $ */ /** @file - * * IAppliance and IVirtualSystem COM class implementations. */ /* - * Copyright (C) 2008-2012 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -18,8 +17,8 @@ #include #include - #include +#include #include "ApplianceImpl.h" #include "VFSExplorerImpl.h" @@ -28,7 +27,8 @@ #include "Global.h" #include "ProgressImpl.h" #include "MachineImpl.h" - +#include "MediumFormatImpl.h" +#include "SystemPropertiesImpl.h" #include "AutoCaller.h" #include "Logging.h" @@ -42,6 +42,21 @@ using namespace std; // //////////////////////////////////////////////////////////////////////////////// +static const char* const strISOURI = "http://www.ecma-international.org/publications/standards/Ecma-119.htm"; +static const char* const strVMDKStreamURI = "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"; +static const char* const strVMDKSparseURI = "http://www.vmware.com/specifications/vmdk.html#sparse"; +static const char* const strVMDKCompressedURI = "http://www.vmware.com/specifications/vmdk.html#compressed"; +static const char* const strVMDKCompressedURI2 = "http://www.vmware.com/interfaces/specifications/vmdk.html#compressed"; +static const char* const strVHDURI = "http://go.microsoft.com/fwlink/?LinkId=137171"; + +static std::map supportedStandardsURI; + +static const char* const applianceIOTarName = "Appliance::IOTar"; +static const char* const applianceIOShaName = "Appliance::IOSha"; +static const char* const applianceIOFileName = "Appliance::IOFile"; + +static std::map applianceIONameMap; + static const struct { ovf::CIMOSType_T cim; @@ -83,6 +98,11 @@ g_osTypes[] = { ovf::CIMOSType_CIMOS_FreeBSD_64, VBOXOSTYPE_FreeBSD_x64 }, { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS }, { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS_x64 }, // there is no CIM 64-bit type for this + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS107_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS108_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS109_x64 }, // Linuxes { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat }, @@ -238,24 +258,44 @@ void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf } } - strType = Global::OSTypeId(VBOXOSTYPE_Unknown); + if (c == ovf::CIMOSType_CIMOS_Other_64) + strType = Global::OSTypeId(VBOXOSTYPE_Unknown_x64); + else + strType = Global::OSTypeId(VBOXOSTYPE_Unknown); } /** * Private helper func that suggests a VirtualBox guest OS type * for the given OVF operating system type. - * @param osTypeVBox - * @param c + * @returns CIM OS type. + * @param pcszVBox Our guest OS type identifier string. + * @param fLongMode Whether long mode is enabled and a 64-bit CIM type is + * preferred even if the VBox guest type isn't 64-bit. */ -ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox) +ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVBox, BOOL fLongMode) { for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i) { - if (!RTStrICmp(pcszVbox, Global::OSTypeId(g_osTypes[i].osType))) + if (!RTStrICmp(pcszVBox, Global::OSTypeId(g_osTypes[i].osType))) + { + if (fLongMode && !(g_osTypes[i].osType & VBOXOSTYPE_x64)) + { + VBOXOSTYPE enmDesiredOsType = (VBOXOSTYPE)((int)g_osTypes[i].osType | (int)VBOXOSTYPE_x64); + size_t j = i; + while (++j < RT_ELEMENTS(g_osTypes)) + if (g_osTypes[j].osType == enmDesiredOsType) + return g_osTypes[j].cim; + j = i; + while (--j > 0) + if (g_osTypes[j].osType == enmDesiredOsType) + return g_osTypes[j].cim; + /* Not all OSes have 64-bit versions, so just return the 32-bit variant. */ + } return g_osTypes[i].cim; + } } - return ovf::CIMOSType_CIMOS_Other; + return fLongMode ? ovf::CIMOSType_CIMOS_Other_64 : ovf::CIMOSType_CIMOS_Other; } Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type) @@ -268,6 +308,7 @@ Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type) case NetworkAttachmentType_Internal: strType = "Internal"; break; case NetworkAttachmentType_HostOnly: strType = "HostOnly"; break; case NetworkAttachmentType_Generic: strType = "Generic"; break; + case NetworkAttachmentType_NATNetwork: strType = "NATNetwork"; break; case NetworkAttachmentType_Null: strType = "Null"; break; } return strType; @@ -324,6 +365,7 @@ Appliance::~Appliance() */ HRESULT Appliance::init(VirtualBox *aVirtualBox) { + HRESULT rc = S_OK; /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); @@ -334,10 +376,14 @@ HRESULT Appliance::init(VirtualBox *aVirtualBox) // initialize data m = new Data; + initApplianceIONameMap(); + + rc = initSetOfSupportedStandardsURI(); + /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); - return S_OK; + return rc; } /** @@ -573,6 +619,113 @@ STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings)) // //////////////////////////////////////////////////////////////////////////////// +HRESULT Appliance::initSetOfSupportedStandardsURI() +{ + HRESULT rc = S_OK; + if (!supportedStandardsURI.empty()) + return rc; + + /* Get the system properties. */ + SystemProperties *pSysProps = mVirtualBox->getSystemProperties(); + { + ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension("iso"); + if (trgFormat.isNull()) + return setError(E_FAIL, tr("Can't find appropriate medium format for ISO type of a virtual disk.")); + + Bstr bstrFormatName; + rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); + if (FAILED(rc)) return rc; + + Utf8Str strTrgFormat = Utf8Str(bstrFormatName); + + supportedStandardsURI.insert(std::make_pair(Utf8Str(strISOURI), strTrgFormat)); + } + + { + ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension("vmdk"); + if (trgFormat.isNull()) + return setError(E_FAIL, tr("Can't find appropriate medium format for VMDK type of a virtual disk.")); + + Bstr bstrFormatName; + rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); + if (FAILED(rc)) return rc; + + Utf8Str strTrgFormat = Utf8Str(bstrFormatName); + + supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKStreamURI), strTrgFormat)); + supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKSparseURI), strTrgFormat)); + supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKCompressedURI), strTrgFormat)); + supportedStandardsURI.insert(std::make_pair(Utf8Str(strVMDKCompressedURI2), strTrgFormat)); + } + + { + ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension("vhd"); + if (trgFormat.isNull()) + return setError(E_FAIL, tr("Can't find appropriate medium format for VHD type of a virtual disk.")); + + Bstr bstrFormatName; + rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); + if (FAILED(rc)) return rc; + + Utf8Str strTrgFormat = Utf8Str(bstrFormatName); + + supportedStandardsURI.insert(std::make_pair(Utf8Str(strVHDURI), strTrgFormat)); + } + + return rc; +} + +Utf8Str Appliance::typeOfVirtualDiskFormatFromURI(Utf8Str uri) const +{ + Utf8Str type; + std::map::const_iterator cit = supportedStandardsURI.find(uri); + if (cit != supportedStandardsURI.end()) + { + type = cit->second; + } + + return type; +} + +std::set Appliance::URIFromTypeOfVirtualDiskFormat(Utf8Str type) +{ + std::set uri; + std::map::const_iterator cit = supportedStandardsURI.begin(); + while(cit != supportedStandardsURI.end()) + { + if (cit->second.compare(type,Utf8Str::CaseInsensitive) == 0) + uri.insert(cit->first); + ++cit; + } + + return uri; +} + +HRESULT Appliance::initApplianceIONameMap() +{ + HRESULT rc = S_OK; + if (!applianceIONameMap.empty()) + return rc; + + applianceIONameMap.insert(std::make_pair(applianceIOTar, applianceIOTarName)); + applianceIONameMap.insert(std::make_pair(applianceIOFile, applianceIOFileName)); + applianceIONameMap.insert(std::make_pair(applianceIOSha, applianceIOShaName)); + + return rc; +} + +Utf8Str Appliance::applianceIOName(APPLIANCEIONAME type) const +{ + Utf8Str name; + std::map::const_iterator cit = applianceIONameMap.find(type); + if (cit != applianceIONameMap.end()) + { + name = cit->second; + } + + return name; +} + /** * Returns true if the appliance is in "idle" state. This should always be the * case unless an import or export is currently in progress. Similar to machine @@ -626,7 +779,7 @@ HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const * already */ /** @todo: Maybe too cost-intensive; try to find a lighter way */ while ( RTPathExists(tmpName) - || mVirtualBox->OpenMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND + || mVirtualBox->OpenMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND ) { RTStrFree(tmpName); @@ -783,7 +936,7 @@ void Appliance::waitForAsyncProgress(ComObjPtr &pProgressThis, that in the meantime more than one async operation was finished. So we have to loop as long as we reached the same operation count. */ ULONG curOp; - for(;;) + for (;;) { rc = pProgressAsync->COMGETTER(Operation(&curOp)); if (FAILED(rc)) throw rc; @@ -866,6 +1019,16 @@ void Appliance::disksWeight() m->ulTotalDisksMB += pHD->ulSizeMB; ++m->cDisks; } + + avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM); + for (itH = avsdeHDs.begin(); + itH != avsdeHDs.end(); + ++itH) + { + const VirtualSystemDescriptionEntry *pHD = *itH; + m->ulTotalDisksMB += pHD->ulSizeMB; + ++m->cDisks; + } } } @@ -1109,13 +1272,13 @@ STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount) STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes), ComSafeArrayOut(BSTR, aRefs), ComSafeArrayOut(BSTR, aOrigValues), - ComSafeArrayOut(BSTR, aVboxValues), + ComSafeArrayOut(BSTR, aVBoxValues), ComSafeArrayOut(BSTR, aExtraConfigValues)) { if (ComSafeArrayOutIsNull(aTypes) || ComSafeArrayOutIsNull(aRefs) || ComSafeArrayOutIsNull(aOrigValues) || - ComSafeArrayOutIsNull(aVboxValues) || + ComSafeArrayOutIsNull(aVBoxValues) || ComSafeArrayOutIsNull(aExtraConfigValues)) return E_POINTER; @@ -1128,7 +1291,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys com::SafeArray sfaTypes(c); com::SafeArray sfaRefs(c); com::SafeArray sfaOrigValues(c); - com::SafeArray sfaVboxValues(c); + com::SafeArray sfaVBoxValues(c); com::SafeArray sfaExtraConfigValues(c); list::const_iterator it; @@ -1147,8 +1310,8 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys bstr = vsde.strOvf; bstr.cloneTo(&sfaOrigValues[i]); - bstr = vsde.strVboxCurrent; - bstr.cloneTo(&sfaVboxValues[i]); + bstr = vsde.strVBoxCurrent; + bstr.cloneTo(&sfaVBoxValues[i]); bstr = vsde.strExtraConfigCurrent; bstr.cloneTo(&sfaExtraConfigValues[i]); @@ -1157,7 +1320,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys sfaTypes.detachTo(ComSafeArrayOutArg(aTypes)); sfaRefs.detachTo(ComSafeArrayOutArg(aRefs)); sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues)); - sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues)); + sfaVBoxValues.detachTo(ComSafeArrayOutArg(aVBoxValues)); sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues)); return S_OK; @@ -1171,13 +1334,13 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes), ComSafeArrayOut(BSTR, aRefs), ComSafeArrayOut(BSTR, aOrigValues), - ComSafeArrayOut(BSTR, aVboxValues), + ComSafeArrayOut(BSTR, aVBoxValues), ComSafeArrayOut(BSTR, aExtraConfigValues)) { if (ComSafeArrayOutIsNull(aTypes) || ComSafeArrayOutIsNull(aRefs) || ComSafeArrayOutIsNull(aOrigValues) || - ComSafeArrayOutIsNull(aVboxValues) || + ComSafeArrayOutIsNull(aVBoxValues) || ComSafeArrayOutIsNull(aExtraConfigValues)) return E_POINTER; @@ -1191,7 +1354,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip com::SafeArray sfaTypes(c); com::SafeArray sfaRefs(c); com::SafeArray sfaOrigValues(c); - com::SafeArray sfaVboxValues(c); + com::SafeArray sfaVBoxValues(c); com::SafeArray sfaExtraConfigValues(c); list::const_iterator it; @@ -1210,8 +1373,8 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip bstr = vsde->strOvf; bstr.cloneTo(&sfaOrigValues[i]); - bstr = vsde->strVboxCurrent; - bstr.cloneTo(&sfaVboxValues[i]); + bstr = vsde->strVBoxCurrent; + bstr.cloneTo(&sfaVBoxValues[i]); bstr = vsde->strExtraConfigCurrent; bstr.cloneTo(&sfaExtraConfigValues[i]); @@ -1220,7 +1383,7 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip sfaTypes.detachTo(ComSafeArrayOutArg(aTypes)); sfaRefs.detachTo(ComSafeArrayOutArg(aRefs)); sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues)); - sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues)); + sfaVBoxValues.detachTo(ComSafeArrayOutArg(aVBoxValues)); sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues)); return S_OK; @@ -1258,7 +1421,7 @@ STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionT { case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break; case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break; - case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break; + case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVBoxCurrent; break; case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break; } @@ -1275,7 +1438,7 @@ STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionT * @return */ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled), - ComSafeArrayIn(IN_BSTR, argVboxValues), + ComSafeArrayIn(IN_BSTR, argVBoxValues), ComSafeArrayIn(IN_BSTR, argExtraConfigValues)) { #ifndef RT_OS_WINDOWS @@ -1283,7 +1446,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab #endif /* RT_OS_WINDOWS */ CheckComArgSafeArrayNotNull(aEnabled); - CheckComArgSafeArrayNotNull(argVboxValues); + CheckComArgSafeArrayNotNull(argVBoxValues); CheckComArgSafeArrayNotNull(argExtraConfigValues); AutoCaller autoCaller(this); @@ -1292,11 +1455,11 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); com::SafeArray sfaEnabled(ComSafeArrayInArg(aEnabled)); - com::SafeArray sfaVboxValues(ComSafeArrayInArg(argVboxValues)); + com::SafeArray sfaVBoxValues(ComSafeArrayInArg(argVBoxValues)); com::SafeArray sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues)); if ( (sfaEnabled.size() != m->llDescriptions.size()) - || (sfaVboxValues.size() != m->llDescriptions.size()) + || (sfaVBoxValues.size() != m->llDescriptions.size()) || (sfaExtraConfigValues.size() != m->llDescriptions.size()) ) return E_INVALIDARG; @@ -1311,7 +1474,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab if (sfaEnabled[i]) { - vsde.strVboxCurrent = sfaVboxValues[i]; + vsde.strVBoxCurrent = sfaVBoxValues[i]; vsde.strExtraConfigCurrent = sfaExtraConfigValues[i]; } else @@ -1326,7 +1489,7 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab * @return */ STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType, - IN_BSTR aVboxValue, + IN_BSTR aVBoxValue, IN_BSTR aExtraConfigValue) { AutoCaller autoCaller(this); @@ -1334,7 +1497,7 @@ STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionTy AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue); + addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue); return S_OK; } @@ -1351,7 +1514,7 @@ STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionTy void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType, const Utf8Str &strRef, const Utf8Str &aOvfValue, - const Utf8Str &aVboxValue, + const Utf8Str &aVBoxValue, uint32_t ulSizeMB, const Utf8Str &strExtraConfig /*= ""*/) { @@ -1360,15 +1523,17 @@ void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType, vsde.type = aType; vsde.strRef = strRef; vsde.strOvf = aOvfValue; - vsde.strVboxSuggested // remember original value - = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues() - = aVboxValue; + vsde.strVBoxSuggested // remember original value + = vsde.strVBoxCurrent // and set current value which can be overridden by setFinalValues() + = aVBoxValue; vsde.strExtraConfigSuggested = vsde.strExtraConfigCurrent = strExtraConfig; vsde.ulSizeMB = ulSizeMB; + vsde.skipIt = false; m->llDescriptions.push_back(vsde); + } /** @@ -1393,6 +1558,26 @@ std::list VirtualSystemDescription::findByType(V return vsd; } +/** + * Private method; delete all records from the list + * m->llDescriptions that match the given type. + * @param aType + * @return + */ +void VirtualSystemDescription::removeByType(VirtualSystemDescriptionType_T aType) +{ + std::list vsd; + + list::iterator it = m->llDescriptions.begin(); + while (it != m->llDescriptions.end()) + { + if (it->type == aType) + it = m->llDescriptions.erase(it); + else + ++it; + } +} + /** * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with * the given reference ID. Useful when needing the controller for a particular @@ -1437,7 +1622,7 @@ const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFro * @param elmMachine element with attributes and subelements from some * DOM tree. */ -void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine) +void VirtualSystemDescription::importVBoxMachineXML(const xml::ElementNode &elmMachine) { settings::MachineConfigFile *pConfig = NULL; @@ -1459,7 +1644,7 @@ void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmM } /** - * Returns the machine config created by importVboxMachineXML() or NULL if there's none. + * Returns the machine config created by importVBoxMachineXML() or NULL if there's none. * @return */ const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp index cc47b4d1..c8c5718f 100644 --- a/src/VBox/Main/src-server/ApplianceImplExport.cpp +++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp @@ -1,11 +1,10 @@ /* $Id: ApplianceImplExport.cpp $ */ /** @file - * * IAppliance and IVirtualSystem COM class implementations. */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,7 +56,7 @@ using namespace std; * @param appliance * @return */ -STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription) +STDMETHODIMP Machine::ExportTo(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription) { HRESULT rc = S_OK; @@ -86,32 +85,32 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // store the machine object so we can dump the XML in Appliance::Write() pNewDesc->m->pMachine = this; - // now fill it with description items - Bstr bstrName1; - Bstr bstrDescription; - Bstr bstrGuestOSType; - uint32_t cCPUs; - uint32_t ulMemSizeMB; - BOOL fUSBEnabled; - BOOL fAudioEnabled; - AudioControllerType_T audioController; + // first, call the COM methods, as they request locks + BOOL fUSBEnabled = FALSE; + com::SafeIfaceArray usbControllers; + rc = COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbControllers)); + if (SUCCEEDED(rc)) + { + for (unsigned i = 0; i < usbControllers.size(); i++) + { + USBControllerType_T enmType; - ComPtr pUsbController; - ComPtr pAudioAdapter; + rc = usbControllers[i]->COMGETTER(Type)(&enmType); + if (FAILED(rc)) throw rc; - // first, call the COM methods, as they request locks - rc = COMGETTER(USBController)(pUsbController.asOutParam()); - if (FAILED(rc)) - fUSBEnabled = false; - else - rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled); + if (enmType == USBControllerType_OHCI) + fUSBEnabled = TRUE; + } + } // request the machine lock while accessing internal members AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS); - pAudioAdapter = mAudioAdapter; + ComPtr pAudioAdapter = mAudioAdapter; + BOOL fAudioEnabled; rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled); if (FAILED(rc)) throw rc; + AudioControllerType_T audioController; rc = pAudioAdapter->COMGETTER(AudioController)(&audioController); if (FAILED(rc)) throw rc; @@ -122,9 +121,9 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // get guest OS Utf8Str strOsTypeVBox = mUserData->s.strOsType; // CPU count - cCPUs = mHWData->mCPUCount; + uint32_t cCPUs = mHWData->mCPUCount; // memory size in MB - ulMemSizeMB = mHWData->mMemorySize; + uint32_t ulMemSizeMB = mHWData->mMemorySize; // VRAM size? // BIOS settings? // 3D acceleration enabled? @@ -132,11 +131,16 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // nested paging enabled? // HWVirtExVPIDEnabled? // PAEEnabled? + // Long mode enabled? + BOOL fLongMode; + rc = GetCPUProperty(CPUPropertyType_LongMode, &fLongMode); + if (FAILED(rc)) throw rc; + // snapshotFolder? // VRDPServer? /* Guest OS type */ - ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str()); + ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str(), fLongMode); pNewDesc->addEntry(VirtualSystemDescriptionType_OS, "", Utf8StrFmt("%RI32", cim), @@ -206,41 +210,41 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // if (!pIDEController.isNull()) { - Utf8Str strVbox; + Utf8Str strVBox; StorageControllerType_T ctlr; rc = pIDEController->COMGETTER(ControllerType)(&ctlr); if (FAILED(rc)) throw rc; switch(ctlr) { - case StorageControllerType_PIIX3: strVbox = "PIIX3"; break; - case StorageControllerType_PIIX4: strVbox = "PIIX4"; break; - case StorageControllerType_ICH6: strVbox = "ICH6"; break; + case StorageControllerType_PIIX3: strVBox = "PIIX3"; break; + case StorageControllerType_PIIX4: strVBox = "PIIX4"; break; + case StorageControllerType_ICH6: strVBox = "ICH6"; break; } - if (strVbox.length()) + if (strVBox.length()) { lIDEControllerPrimaryIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, Utf8StrFmt("%d", lIDEControllerPrimaryIndex), // strRef - strVbox, // aOvfValue - strVbox); // aVboxValue + strVBox, // aOvfValue + strVBox); // aVBoxValue lIDEControllerSecondaryIndex = lIDEControllerPrimaryIndex + 1; pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, Utf8StrFmt("%d", lIDEControllerSecondaryIndex), - strVbox, - strVbox); + strVBox, + strVBox); } } // if (!pSATAController.isNull()) { - Utf8Str strVbox = "AHCI"; + Utf8Str strVBox = "AHCI"; lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA, Utf8StrFmt("%d", lSATAControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } // @@ -250,17 +254,17 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pSCSIController->COMGETTER(ControllerType)(&ctlr); if (SUCCEEDED(rc)) { - Utf8Str strVbox = "LsiLogic"; // the default in VBox + Utf8Str strVBox = "LsiLogic"; // the default in VBox switch(ctlr) { - case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break; - case StorageControllerType_BusLogic: strVbox = "BusLogic"; break; + case StorageControllerType_LsiLogic: strVBox = "LsiLogic"; break; + case StorageControllerType_BusLogic: strVBox = "BusLogic"; break; } lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI, Utf8StrFmt("%d", lSCSIControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } else throw rc; @@ -270,12 +274,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS { // VirtualBox considers the SAS controller a class of its own but in OVF // it should be a SCSI controller - Utf8Str strVbox = "LsiLogicSas"; + Utf8Str strVBox = "LsiLogicSas"; lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSAS, Utf8StrFmt("%d", lSCSIControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } // @@ -320,15 +324,15 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pHDA->COMGETTER(Device)(&lDevice); if (FAILED(rc)) throw rc; - Utf8Str strTargetVmdkName; + Utf8Str strTargetImageName; Utf8Str strLocation; LONG64 llSize = 0; - if ( deviceType == DeviceType_HardDisk - && pMedium - ) + if ( deviceType == DeviceType_HardDisk + && pMedium) { Bstr bstrLocation; + rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam()); if (FAILED(rc)) throw rc; strLocation = bstrLocation; @@ -343,12 +347,11 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // returns pMedium if there are no diff images if (FAILED(rc)) throw rc; - Bstr bstrBaseName; - rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam()); - if (FAILED(rc)) throw rc; - - Utf8Str strTargetName = Utf8Str(locInfo.strPath).stripPath().stripExt(); - strTargetVmdkName = Utf8StrFmt("%s-disk%d.vmdk", strTargetName.c_str(), ++pAppliance->m->cDisks); + Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt(); + strTargetImageName = Utf8StrFmt("%s-disk%d.vmdk", strName.c_str(), ++pAppliance->m->cDisks); + if (strTargetImageName.length() > RTTAR_NAME_MAX) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Cannot attach disk '%s' -- file name too long"), strTargetImageName.c_str()); // force reading state, or else size will be returned as 0 MediumState_T ms; @@ -358,7 +361,55 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pBaseMedium->COMGETTER(Size)(&llSize); if (FAILED(rc)) throw rc; } + else if ( deviceType == DeviceType_DVD + && pMedium) + { + /* + * check the minimal rules to grant access to export an image + * 1. no host drive CD/DVD image + * 2. the image must be accessible and readable + * 3. only ISO image is exported + */ + + //1. no host drive CD/DVD image + BOOL fHostDrive = false; + rc = pMedium->COMGETTER(HostDrive)(&fHostDrive); + if (FAILED(rc)) throw rc; + + if(fHostDrive) + continue; + + //2. the image must be accessible and readable + MediumState_T ms; + rc = pMedium->RefreshState(&ms); + if (FAILED(rc)) throw rc; + + if (ms != MediumState_Created) + continue; + //3. only ISO image is exported + Bstr bstrLocation; + rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam()); + if (FAILED(rc)) throw rc; + + strLocation = bstrLocation; + + Utf8Str ext = strLocation; + ext.assignEx(RTPathExt(ext.c_str()));//returns extension with dot (".iso") + + int eq = ext.compare(".iso", Utf8Str::CaseInsensitive); + if (eq != 0) + continue; + + Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt(); + strTargetImageName = Utf8StrFmt("%s-disk%d.iso", strName.c_str(), ++pAppliance->m->cDisks); + if (strTargetImageName.length() > RTTAR_NAME_MAX) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Cannot attach image '%s' -- file name too long"), strTargetImageName.c_str()); + + rc = pMedium->COMGETTER(Size)(&llSize); + if (FAILED(rc)) throw rc; + } // and how this translates to the virtual system int32_t lControllerVsys = 0; LONG lChannelVsys; @@ -426,19 +477,20 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS case DeviceType_HardDisk: Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", llSize)); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage, - strTargetVmdkName, // disk ID: let's use the name - strTargetVmdkName, // OVF value: + strTargetImageName, // disk ID: let's use the name + strTargetImageName, // OVF value: strLocation, // vbox value: media path (uint32_t)(llSize / _1M), strExtra); break; case DeviceType_DVD: + Log(("Adding VirtualSystemDescriptionType_CDROM, disk size: %RI64\n", llSize)); pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, - strEmpty, // disk ID - strEmpty, // OVF value - strEmpty, // vbox value - 1, // ulSize + strTargetImageName, // disk ID + strTargetImageName, // OVF value + strLocation, // vbox value + (uint32_t)(llSize / _1M),// ulSize strExtra); break; @@ -525,11 +577,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS /** * Public method implementation. * @param format + * @param options * @param path * @param aProgress * @return */ -STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IProgress **aProgress) +STDMETHODIMP Appliance::Write(IN_BSTR format, ComSafeArrayIn(ImportOptions_T, options), IN_BSTR path, IProgress **aProgress) { if (!path) return E_POINTER; CheckComArgOutPointerValid(aProgress); @@ -539,6 +592,31 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (options != NULL) + m->optListExport = com::SafeArray(ComSafeArrayInArg(options)).toList(); + +// AssertReturn(!(m->optListExport.contains(ExportOptions_CreateManifest) && m->optListExport.contains(ExportOptions_ExportDVDImages)), E_INVALIDARG); + + m->fExportISOImages = m->optListExport.contains(ExportOptions_ExportDVDImages); + + if (!m->fExportISOImages)/* remove all ISO images from VirtualSystemDescription */ + { + list< ComObjPtr >::const_iterator it; + for (it = m->virtualSystemDescriptions.begin(); + it != m->virtualSystemDescriptions.end(); + ++it) + { + ComObjPtr vsdescThis = (*it); + std::list skipped = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM); + std::list:: iterator pItSkipped = skipped.begin(); + while (pItSkipped != skipped.end()) + { + (*pItSkipped)->skipIt = true; + ++pItSkipped; + } + } + } + // do not allow entering this method if the appliance is busy reading or writing if (!isApplianceIdle()) return E_ACCESSDENIED; @@ -550,21 +628,28 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro return setError(VBOX_E_FILE_ERROR, tr("Appliance file must have .ovf or .ova extension")); - m->fManifest = !!fManifest; + m->fManifest = m->optListExport.contains(ExportOptions_CreateManifest); Utf8Str strFormat(format); - OVFFormat ovfF; + + ovf::OVFVersion_T ovfF; if (strFormat == "ovf-0.9") - ovfF = OVF_0_9; + { + ovfF = ovf::OVFVersion_0_9; + } else if (strFormat == "ovf-1.0") - ovfF = OVF_1_0; + { + ovfF = ovf::OVFVersion_1_0; + } else if (strFormat == "ovf-2.0") - ovfF = OVF_2_0; + { + ovfF = ovf::OVFVersion_2_0; + } else return setError(VBOX_E_FILE_ERROR, tr("Invalid format \"%s\" specified"), strFormat.c_str()); /* as of OVF 2.0 we have to use SHA256 */ - m->fSha256 = ovfF >= OVF_2_0; + m->fSha256 = ovfF >= ovf::OVFVersion_2_0; ComObjPtr progress; HRESULT rc = S_OK; @@ -614,7 +699,7 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro * @param aProgress * @return */ -HRESULT Appliance::writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, ComObjPtr &aProgress) +HRESULT Appliance::writeImpl(ovf::OVFVersion_T aFormat, const LocationInfo &aLocInfo, ComObjPtr &aProgress) { HRESULT rc = S_OK; try @@ -658,18 +743,30 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, xml::Document &doc, XMLStack &stack, const Utf8Str &strPath, - OVFFormat enFormat) + ovf::OVFVersion_T enFormat) { xml::ElementNode *pelmRoot = doc.createRootElement("Envelope"); - pelmRoot->setAttribute("ovf:version", enFormat == OVF_2_0 ? "2.0" - : enFormat == OVF_1_0 ? "1.0" + pelmRoot->setAttribute("ovf:version", enFormat == ovf::OVFVersion_2_0 ? "2.0" + : enFormat == ovf::OVFVersion_1_0 ? "1.0" : "0.9"); pelmRoot->setAttribute("xml:lang", "en-US"); - Utf8Str strNamespace = (enFormat == OVF_0_9) - ? "http://www.vmware.com/schema/ovf/1/envelope" // 0.9 - : "http://schemas.dmtf.org/ovf/envelope/1"; // 1.0 + Utf8Str strNamespace; + + if (enFormat == ovf::OVFVersion_0_9) + { + strNamespace = ovf::OVF09_URI_string; + } + else if (enFormat == ovf::OVFVersion_1_0) + { + strNamespace = ovf::OVF10_URI_string; + } + else + { + strNamespace = ovf::OVF20_URI_string; + } + pelmRoot->setAttribute("xmlns", strNamespace); pelmRoot->setAttribute("xmlns:ovf", strNamespace); @@ -680,6 +777,14 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, pelmRoot->setAttribute("xmlns:vbox", "http://www.virtualbox.org/ovf/machine"); // pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd"); + if (enFormat == ovf::OVFVersion_2_0) + { + pelmRoot->setAttribute("xmlns:epasd", + "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPortAllocationSettingData.xsd"); + pelmRoot->setAttribute("xmlns:sasd", + "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_StorageAllocationSettingData.xsd"); + } + // / xml::ElementNode *pelmReferences = pelmRoot->createChild("References"); // 0.9 and 1.0 @@ -689,7 +794,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, */ xml::ElementNode *pelmDiskSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmDiskSection = pelmRoot->createChild("Section"); @@ -709,7 +814,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, */ xml::ElementNode *pelmNetworkSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmNetworkSection = pelmRoot->createChild("Section"); @@ -729,7 +834,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, xml::ElementNode *pelmToAddVirtualSystemsTo; if (m->virtualSystemDescriptions.size() > 1) { - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) throw setError(VBOX_E_FILE_ERROR, tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0")); @@ -783,19 +888,46 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, const VirtualSystemDescriptionEntry *pDiskEntry = itS->second; // source path: where the VBox image is - const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent; + const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent; Bstr bstrSrcFilePath(strSrcFilePath); + //skip empty Medium. There are no information to add into section or + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) + continue; + // Do NOT check here whether the file exists. FindMedium will figure // that out, and filesystem-based tests are simply wrong in the // general case (think of iSCSI). // We need some info from the source disks ComPtr pSourceDisk; + //DeviceType_T deviceType = DeviceType_HardDisk;// by default Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw())); - HRESULT rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, pSourceDisk.asOutParam()); - if (FAILED(rc)) throw rc; + + HRESULT rc; + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), + DeviceType_HardDisk, + AccessMode_ReadWrite, + FALSE /* fForceNewUuid */, + pSourceDisk.asOutParam()); + if (FAILED(rc)) + throw rc; + } + else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD + { + rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), + DeviceType_DVD, + AccessMode_ReadOnly, + FALSE, + pSourceDisk.asOutParam()); + if (FAILED(rc)) + throw rc; + } Bstr uuidSource; rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam()); @@ -811,7 +943,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, strTargetFilePath.append(strTargetFileNameOnly); // We are always exporting to VMDK stream optimized for now - Bstr bstrSrcFormat = L"VMDK"; + //Bstr bstrSrcFormat = L"VMDK";//not used diskList.push_back(strTargetFilePath); @@ -843,12 +975,22 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str()); pelmDisk->setAttribute("ovf:diskId", strDiskID); pelmDisk->setAttribute("ovf:fileRef", strFileRef); - pelmDisk->setAttribute("ovf:format", - (enFormat == OVF_0_9) - ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool chokes - : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" - // correct string as communicated to us by VMware (public bug #6612) - ); + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk + { + pelmDisk->setAttribute("ovf:format", + (enFormat == ovf::OVFVersion_0_9) + ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool ch + : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" + // correct string as communicated to us by VMware (public bug #6612) + ); + } + else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD + { + pelmDisk->setAttribute("ovf:format", + "http://www.ecma-international.org/publications/standards/Ecma-119.htm" + ); + } // add the UUID of the newly target image to the OVF disk element, but in the // vbox: namespace since it's not part of the standard @@ -891,13 +1033,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, xml::ElementNode &elmToAddVirtualSystemsTo, std::list *pllElementsWithUuidAttributes, ComObjPtr &vsdescThis, - OVFFormat enFormat, + ovf::OVFVersion_T enFormat, XMLStack &stack) { LogFlowFunc(("ENTER appliance %p\n", this)); xml::ElementNode *pelmVirtualSystem; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmVirtualSystem = elmToAddVirtualSystemsTo.createChild("Content"); @@ -909,10 +1051,9 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, /*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine"); std::list llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); - if (llName.size() != 1) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Missing VM name")); - Utf8Str &strVMName = llName.front()->strVboxCurrent; + if (!llName.size()) + throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing VM name")); + Utf8Str &strVMName = llName.back()->strVBoxCurrent; pelmVirtualSystem->setAttribute("ovf:id", strVMName); // product info @@ -921,11 +1062,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, std::list llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor); std::list llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl); std::list llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version); - bool fProduct = llProduct.size() && !llProduct.front()->strVboxCurrent.isEmpty(); - bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVboxCurrent.isEmpty(); - bool fVendor = llVendor.size() && !llVendor.front()->strVboxCurrent.isEmpty(); - bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVboxCurrent.isEmpty(); - bool fVersion = llVersion.size() && !llVersion.front()->strVboxCurrent.isEmpty(); + bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty(); + bool fProductUrl = llProductUrl.size() && !llProductUrl.back()->strVBoxCurrent.isEmpty(); + bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty(); + bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty(); + bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty(); if (fProduct || fProductUrl || fVersion || @@ -941,7 +1082,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, http://www.sun.com
*/ xml::ElementNode *pelmAnnotationSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmAnnotationSection = pelmVirtualSystem->createChild("Section"); @@ -952,28 +1093,28 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software"); if (fProduct) - pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Product")->addContent(llProduct.back()->strVBoxCurrent); if (fVendor) - pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.back()->strVBoxCurrent); if (fVersion) - pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Version")->addContent(llVersion.back()->strVBoxCurrent); if (fProductUrl) - pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVboxCurrent); + pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.back()->strVBoxCurrent); if (fVendorUrl) - pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVboxCurrent); + pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.back()->strVBoxCurrent); } // description std::list llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); if (llDescription.size() && - !llDescription.front()->strVboxCurrent.isEmpty()) + !llDescription.back()->strVBoxCurrent.isEmpty()) { /*
A human-readable annotation Plan 9
*/ xml::ElementNode *pelmAnnotationSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmAnnotationSection = pelmVirtualSystem->createChild("Section"); @@ -983,20 +1124,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection"); pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation"); - pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.back()->strVBoxCurrent); } // license std::list llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License); if (llLicense.size() && - !llLicense.front()->strVboxCurrent.isEmpty()) + !llLicense.back()->strVBoxCurrent.isEmpty()) { /* License agreement for the Virtual System. License terms can go in here. */ xml::ElementNode *pelmEulaSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { pelmEulaSection = pelmVirtualSystem->createChild("Section"); pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type"); @@ -1005,21 +1146,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmEulaSection = pelmVirtualSystem->createChild("EulaSection"); pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system"); - pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVboxCurrent); + pelmEulaSection->createChild("License")->addContent(llLicense.back()->strVBoxCurrent); } // operating system std::list llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS); - if (llOS.size() != 1) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Missing OS type")); + if (!llOS.size()) + throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing OS type")); /* Guest Operating System Linux 2.6.x */ - VirtualSystemDescriptionEntry *pvsdeOS = llOS.front(); + VirtualSystemDescriptionEntry *pvsdeOS = llOS.back(); xml::ElementNode *pelmOperatingSystemSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section"); pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type"); @@ -1035,11 +1175,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, // add the VirtualBox ostype in a custom tag in a different namespace xml::ElementNode *pelmVBoxOSType = pelmOperatingSystemSection->createChild("vbox:OSType"); pelmVBoxOSType->setAttribute("ovf:required", "false"); - pelmVBoxOSType->addContent(pvsdeOS->strVboxCurrent); + pelmVBoxOSType->addContent(pvsdeOS->strVBoxCurrent); // xml::ElementNode *pelmVirtualHardwareSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { //
pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section"); @@ -1062,7 +1202,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0 // 0 - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) pelmSystem->createChild("vssd:InstanceId")->addContent("0"); else // capitalization changed... pelmSystem->createChild("vssd:InstanceID")->addContent("0"); @@ -1071,7 +1211,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName); // vmx-4 const char *pcszHardware = "virtualbox-2.2"; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) // pretend to be vmware compatible then pcszHardware = "vmx-6"; pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware); @@ -1105,7 +1245,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { const VirtualSystemDescriptionEntry &desc = *itD; - LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVbox=%s, strExtraConfig=%s\n", + LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVBox=%s, strExtraConfig=%s\n", uLoop, desc.ulIndex, ( desc.type == VirtualSystemDescriptionType_HardDiskControllerIDE ? "HardDiskControllerIDE" @@ -1116,7 +1256,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, : Utf8StrFmt("%d", desc.type).c_str()), desc.strRef.c_str(), desc.strOvf.c_str(), - desc.strVboxCurrent.c_str(), + desc.strVBoxCurrent.c_str(), desc.strExtraConfigCurrent.c_str())); ovf::ResourceType_T type = (ovf::ResourceType_T)0; // if this becomes != 0 then we do stuff @@ -1140,6 +1280,10 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, uint64_t uTemp; + ovf::VirtualHardwareItem vhi; + ovf::StorageItem si; + ovf::EthernetPortItem epi; + switch (desc.type) { case VirtualSystemDescriptionType_CPU: @@ -1155,7 +1299,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "Number of virtual CPUs"; type = ovf::ResourceType_Processor; // 3 - desc.strVboxCurrent.toInt(uTemp); + desc.strVBoxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)uTemp; strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity); // without this ovftool won't eat the item } @@ -1175,7 +1319,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "Memory Size"; type = ovf::ResourceType_Memory; // 4 - desc.strVboxCurrent.toInt(uTemp); + desc.strVBoxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)(uTemp / _1M); strAllocationUnits = "MegaBytes"; strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity); // without this ovftool won't eat the item @@ -1195,7 +1339,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "IDE Controller"; type = ovf::ResourceType_IDEController; // 5 - strResourceSubType = desc.strVboxCurrent; + strResourceSubType = desc.strVBoxCurrent; if (!lIDEPrimaryControllerIndex) { @@ -1241,13 +1385,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, lAddress = 0; lBusNumber = 0; - if ( desc.strVboxCurrent.isEmpty() // AHCI is the default in VirtualBox - || (!desc.strVboxCurrent.compare("ahci", Utf8Str::CaseInsensitive)) + if ( desc.strVBoxCurrent.isEmpty() // AHCI is the default in VirtualBox + || (!desc.strVBoxCurrent.compare("ahci", Utf8Str::CaseInsensitive)) ) strResourceSubType = "AHCI"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SATA controller"), desc.strVboxCurrent.c_str()); + tr("Invalid config string \"%s\" in SATA controller"), desc.strVBoxCurrent.c_str()); // remember this ID idSATAController = ulInstanceID; @@ -1277,17 +1421,17 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, lAddress = 0; lBusNumber = 0; - if ( desc.strVboxCurrent.isEmpty() // LsiLogic is the default in VirtualBox - || (!desc.strVboxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive)) + if ( desc.strVBoxCurrent.isEmpty() // LsiLogic is the default in VirtualBox + || (!desc.strVBoxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive)) ) strResourceSubType = "lsilogic"; - else if (!desc.strVboxCurrent.compare("buslogic", Utf8Str::CaseInsensitive)) + else if (!desc.strVBoxCurrent.compare("buslogic", Utf8Str::CaseInsensitive)) strResourceSubType = "buslogic"; - else if (!desc.strVboxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive)) + else if (!desc.strVBoxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive)) strResourceSubType = "lsilogicsas"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVboxCurrent.c_str()); + tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVBoxCurrent.c_str()); // remember this ID idSCSIController = ulInstanceID; @@ -1360,13 +1504,32 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, break; case VirtualSystemDescriptionType_CDROM: + /* + cdrom1 + 8 + 15 + /disk/cdrom1 + 4 + 0 + */ if (uLoop == 2) { + //uint32_t cDisks = stack.mapDisks.size(); + Utf8Str strDiskID = Utf8StrFmt("iso%RI32", ++cDVDs); + strDescription = "CD-ROM Drive"; - strCaption = Utf8StrFmt("cdrom%RI32", ++cDVDs); // OVFTool starts with 1 + strCaption = Utf8StrFmt("cdrom%RI32", cDVDs); // OVFTool starts with 1 type = ovf::ResourceType_CDDrive; // 15 lAutomaticAllocation = 1; + //skip empty Medium. There are no information to add into section or + if (desc.strVBoxCurrent.isNotEmpty() && + desc.skipIt == false) + { + // the following references the "" XML block + strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str()); + } + // controller=;channel= size_t pos1 = desc.strExtraConfigCurrent.find("controller="); size_t pos2 = desc.strExtraConfigCurrent.find("channel="); @@ -1395,6 +1558,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing or bad extra config string in DVD drive medium: \"%s\""), desc.strExtraConfigCurrent.c_str()); + stack.mapDisks[strDiskID] = &desc; // there is no DVD drive map to update because it is // handled completely with this entry. } @@ -1409,7 +1573,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, 3 10 */ - if (uLoop == 1) + if (uLoop == 2) { lAutomaticAllocation = 1; strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str()); @@ -1418,7 +1582,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, * To be compatible with vmware & others we set * PCNet32 for our PCNet types & E1000 for the * E1000 cards. */ - switch (desc.strVboxCurrent.toInt32()) + switch (desc.strVBoxCurrent.toInt32()) { case NetworkAdapterType_Am79C970A: case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break; @@ -1478,65 +1642,176 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, if (type) { xml::ElementNode *pItem; + xml::ElementNode *pItemHelper; + RTCString itemElement; + RTCString itemElementHelper; - pItem = pelmVirtualHardwareSection->createChild("Item"); + if (enFormat == ovf::OVFVersion_2_0) + { + if(uLoop == 2) + { + if (desc.type == VirtualSystemDescriptionType_NetworkAdapter) + { + itemElement = "epasd:"; + pItem = pelmVirtualHardwareSection->createChild("EthernetPortItem"); + } + else if (desc.type == VirtualSystemDescriptionType_CDROM || + desc.type == VirtualSystemDescriptionType_HardDiskImage) + { + itemElement = "sasd:"; + pItem = pelmVirtualHardwareSection->createChild("StorageItem"); + } + else + pItem = NULL; + } + else + { + itemElement = "rasd:"; + pItem = pelmVirtualHardwareSection->createChild("Item"); + } + } + else + { + itemElement = "rasd:"; + pItem = pelmVirtualHardwareSection->createChild("Item"); + } // NOTE: DO NOT CHANGE THE ORDER of these items! The OVF standards prescribes that // the elements from the rasd: namespace must be sorted by letter, and VMware // actually requires this as well (see public bug #6612) if (lAddress != -1) - pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress)); + { + //pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Address").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lAddress)); + } if (lAddressOnParent != -1) - pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent)); + { + //pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AddressOnParent").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lAddressOnParent)); + } if (!strAllocationUnits.isEmpty()) - pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits); + { + //pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AllocationUnits").c_str()); + pItemHelper->addContent(strAllocationUnits); + } if (lAutomaticAllocation != -1) - pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" ); + { + //pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" ); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AutomaticAllocation").c_str()); + pItemHelper->addContent((lAutomaticAllocation) ? "true" : "false" ); + } if (lBusNumber != -1) - if (enFormat == OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility - pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber)); + { + if (enFormat == ovf::OVFVersion_0_9) + { + // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool + //pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("BusNumber").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lBusNumber)); + } + } if (!strCaption.isEmpty()) - pItem->createChild("rasd:Caption")->addContent(strCaption); + { + //pItem->createChild("rasd:Caption")->addContent(strCaption); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Caption").c_str()); + pItemHelper->addContent(strCaption); + } if (!strConnection.isEmpty()) - pItem->createChild("rasd:Connection")->addContent(strConnection); + { + //pItem->createChild("rasd:Connection")->addContent(strConnection); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Connection").c_str()); + pItemHelper->addContent(strConnection); + } if (!strDescription.isEmpty()) - pItem->createChild("rasd:Description")->addContent(strDescription); + { + //pItem->createChild("rasd:Description")->addContent(strDescription); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Description").c_str()); + pItemHelper->addContent(strDescription); + } if (!strCaption.isEmpty()) - if (enFormat == OVF_1_0) - pItem->createChild("rasd:ElementName")->addContent(strCaption); + { + if (enFormat == ovf::OVFVersion_1_0) + { + //pItem->createChild("rasd:ElementName")->addContent(strCaption); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ElementName").c_str()); + pItemHelper->addContent(strCaption); + } + } if (!strHostResource.isEmpty()) - pItem->createChild("rasd:HostResource")->addContent(strHostResource); + { + //pItem->createChild("rasd:HostResource")->addContent(strHostResource); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("HostResource").c_str()); + pItemHelper->addContent(strHostResource); + } - // 1 - xml::ElementNode *pelmInstanceID; - if (enFormat == OVF_0_9) - pelmInstanceID = pItem->createChild("rasd:InstanceId"); - else - pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed... - pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++)); + { + // 1 + itemElementHelper = itemElement; + if (enFormat == ovf::OVFVersion_0_9) + //pelmInstanceID = pItem->createChild("rasd:InstanceId"); + pItemHelper = pItem->createChild(itemElementHelper.append("InstanceId").c_str()); + else + //pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed... + pItemHelper = pItem->createChild(itemElementHelper.append("InstanceID").c_str()); + + pItemHelper->addContent(Utf8StrFmt("%d", ulInstanceID++)); + } if (ulParent) - pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent)); + { + //pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Parent").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", ulParent)); + } if (!strResourceSubType.isEmpty()) - pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType); + { + //pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ResourceSubType").c_str()); + pItemHelper->addContent(strResourceSubType); + } - // 3 - pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type)); + { + // 3 + //pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ResourceType").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", type)); + } // 1 if (lVirtualQuantity != -1) - pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + { + //pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("VirtualQuantity").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + } } } } // for (size_t uLoop = 1; uLoop <= 2; ++uLoop) @@ -1558,10 +1833,26 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, AutoWriteLock machineLock(vsdescThis->m->pMachine COMMA_LOCKVAL_SRC_POS); // fill the machine config vsdescThis->m->pMachine->copyMachineDataToSettings(*pConfig); + + // Apply export tweaks to machine settings + bool fStripAllMACs = m->optListExport.contains(ExportOptions_StripAllMACs); + bool fStripAllNonNATMACs = m->optListExport.contains(ExportOptions_StripAllNonNATMACs); + if (fStripAllMACs || fStripAllNonNATMACs) + { + for (settings::NetworkAdaptersList::iterator it = pConfig->hardwareMachine.llNetworkAdapters.begin(); + it != pConfig->hardwareMachine.llNetworkAdapters.end(); + ++it) + { + settings::NetworkAdapter &nic = *it; + if (fStripAllMACs || (fStripAllNonNATMACs && nic.mode != NetworkAttachmentType_NAT)) + nic.strMACAddress.setNull(); + } + } + // write the machine config to the vbox:Machine element pConfig->buildMachineXML(*pelmVBoxMachine, - settings::MachineConfigFile::BuildMachineXML_WriteVboxVersionAttribute - | settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia + settings::MachineConfigFile::BuildMachineXML_WriteVBoxVersionAttribute + /*| settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia*/ | settings::MachineConfigFile::BuildMachineXML_SuppressSavedState, // but not BuildMachineXML_IncludeSnapshots nor BuildMachineXML_MediaRegistry pllElementsWithUuidAttributes); @@ -1648,7 +1939,11 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) RT_ZERO(storage); storage.fCreateDigest = m->fManifest; storage.fSha256 = m->fSha256; - int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile", + + + Utf8Str name = applianceIOName(applianceIOFile); + + int vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(), VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), &storage.pVDImageIfaces); if (RT_FAILURE(vrc)) @@ -1657,7 +1952,7 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) break; } rc = writeFSImpl(pTask, writeLock, pShaIo, &storage); - }while(0); + } while (0); /* Cleanup */ if (pShaIo) @@ -1702,16 +1997,20 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) RT_ZERO(storage); storage.fCreateDigest = m->fManifest; storage.fSha256 = m->fSha256; - vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar", + + Utf8Str name = applianceIOName(applianceIOTar); + + vrc = VDInterfaceAdd(&pTarIo->Core, name.c_str(), VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO), &storage.pVDImageIfaces); + if (RT_FAILURE(vrc)) { rc = E_FAIL; break; } rc = writeFSImpl(pTask, writeLock, pShaIo, &storage); - }while(0); + } while (0); RTTarClose(tar); @@ -1722,7 +2021,7 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) RTMemFree(pTarIo); /* Delete ova file on error */ - if(FAILED(rc)) + if (FAILED(rc)) RTFileDelete(pTask->locInfo.strPath.c_str()); LogFlowFuncLeave(); @@ -1749,8 +2048,10 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD xml::Document doc; // Now fully build a valid ovf document in memory buildXML(writeLock, doc, stack, pTask->locInfo.strPath, pTask->enFormat); + /* Extract the OVA file name */ + Utf8Str strOvaFile = pTask->locInfo.strPath; /* Extract the path */ - Utf8Str strOvfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".ovf"); + Utf8Str strOvfFile = strOvaFile.stripExt().append(".ovf"); // Create a memory buffer containing the XML. */ void *pvBuf = 0; size_t cbSize; @@ -1770,12 +2071,16 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD } // We need a proper format description + ComObjPtr formatTemp; + ComObjPtr format; // Scope for the AutoReadLock { SystemProperties *pSysProps = mVirtualBox->getSystemProperties(); AutoReadLock propsLock(pSysProps COMMA_LOCKVAL_SRC_POS); // We are always exporting to VMDK stream optimized for now + formatTemp = pSysProps->mediumFormatFromExtension("iso"); + format = pSysProps->mediumFormat("VMDK"); if (format.isNull()) throw setError(VBOX_E_NOT_SUPPORTED, @@ -1791,7 +2096,12 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD const VirtualSystemDescriptionEntry *pDiskEntry = itS->second; // source path: where the VBox image is - const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent; + const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent; + + //skip empty Medium. In common, It's may be empty CD/DVD + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) + continue; // Do NOT check here whether the file exists. findHardDisk will // figure that out, and filesystem-based tests are simply wrong @@ -1801,8 +2111,21 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD ComObjPtr pSourceDisk; Log(("Finding source disk \"%s\"\n", strSrcFilePath.c_str())); - rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk); - if (FAILED(rc)) throw rc; + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk); + if (FAILED(rc)) throw rc; + } + else//may be CD or DVD + { + rc = mVirtualBox->findDVDOrFloppyImage(DeviceType_DVD, + NULL, + strSrcFilePath, + true, + &pSourceDisk); + if (FAILED(rc)) throw rc; + } Bstr uuidSource; rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam()); @@ -1821,22 +2144,118 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD writeLock.release(); try { - ComObjPtr pProgress2; - pProgress2.createObject(); - rc = pProgress2->init(mVirtualBox, static_cast(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE); - if (FAILED(rc)) throw rc; - // advance to the next operation pTask->pProgress->SetNextOperation(BstrFmt(tr("Exporting to disk image '%s'"), RTPathFilename(strTargetFilePath.c_str())).raw(), pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally // create a flat copy of the source disk image - rc = pSourceDisk->exportFile(strTargetFilePath.c_str(), format, MediumVariant_VmdkStreamOptimized, pIfIo, pStorage, pProgress2); - if (FAILED(rc)) throw rc; + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + ComObjPtr pProgress2; + pProgress2.createObject(); + rc = pProgress2->init(mVirtualBox, static_cast(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE); + if (FAILED(rc)) throw rc; + + rc = pSourceDisk->exportFile(strTargetFilePath.c_str(), + format, + MediumVariant_VmdkStreamOptimized, + pIfIo, + pStorage, + pProgress2); + if (FAILED(rc)) throw rc; + + ComPtr pProgress3(pProgress2); + // now wait for the background disk operation to complete; this throws HRESULTs on error + waitForAsyncProgress(pTask->pProgress, pProgress3); + } + else//pDiskEntry->type == VirtualSystemDescriptionType_CDROM + { + //copy/clone CD/DVD image + /* Read the ISO file and add one to OVA/OVF package */ + { + void *pvStorage; + RTFILE pFile = NULL; + void *pvUser = pStorage; + + vrc = pIfIo->pfnOpen(pvUser, strTargetFilePath.c_str(), + RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE, + 0, + &pvStorage); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("Could not create or open file '%s' (%Rrc)"), + strTargetFilePath.c_str(), vrc); + + vrc = RTFileOpen(&pFile, + strSrcFilePath.c_str(), + RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE); + + if (RT_FAILURE(vrc) || pFile == NULL) + { + pIfIo->pfnClose(pvUser, pvStorage); + throw setError(VBOX_E_FILE_ERROR, + tr("Could not create or open file '%s' (%Rrc)"), + strSrcFilePath.c_str(), vrc); + } + + void *pvTmpBuf = 0; + size_t cbTmpSize = _1M; + uint64_t cbAllWritten = 0; + uint64_t cbFile = 0; + size_t cbSize = 0; + + vrc = RTFileGetSize(pFile, &cbFile); + + do + { + pvTmpBuf = RTMemAlloc(cbTmpSize); + if (!pvTmpBuf) + { + vrc = VERR_NO_MEMORY; + break; + } - ComPtr pProgress3(pProgress2); - // now wait for the background disk operation to complete; this throws HRESULTs on error - waitForAsyncProgress(pTask->pProgress, pProgress3); + for (;;) + { + // copy raw data into the buffer pvTmpBuf + vrc = RTFileRead(pFile, pvTmpBuf, cbTmpSize, &cbSize); + + if (RT_FAILURE(vrc) || cbSize == 0) + break; + + size_t cbToWrite = cbSize; + size_t cbWritten = 0; + + vrc = pIfIo->pfnWriteSync(pvUser, + pvStorage, + cbAllWritten, + pvTmpBuf, + cbToWrite,&cbWritten); + + if (RT_FAILURE(vrc)) + break; + + cbAllWritten += cbWritten; + } + } while (0); + + pIfIo->pfnClose(pvUser, pvStorage); + RTFileClose(pFile); + + if (pvTmpBuf) + RTMemFree(pvTmpBuf); + + if (RT_FAILURE(vrc)) + { + if (vrc == VERR_EOF) + vrc = VINF_SUCCESS; + else + throw setError(VBOX_E_FILE_ERROR, + tr("Error during copy CD/DVD image '%s' (%Rrc)"), + strSrcFilePath.c_str(), vrc); + } + } + } } catch (HRESULT rc3) { diff --git a/src/VBox/Main/src-server/ApplianceImplIO.cpp b/src/VBox/Main/src-server/ApplianceImplIO.cpp index a31f93a8..1a9ac12a 100644 --- a/src/VBox/Main/src-server/ApplianceImplIO.cpp +++ b/src/VBox/Main/src-server/ApplianceImplIO.cpp @@ -1,11 +1,10 @@ /* $Id: ApplianceImplIO.cpp $ */ /** @file - * * IO helper for IAppliance COM class implementations. */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,19 +22,23 @@ #include "ProgressImpl.h" #include "ApplianceImpl.h" #include "ApplianceImplPrivate.h" +#include "VirtualBoxImpl.h" +#include #include #include #include #include #include #include +#include +#include +#include #include /****************************************************************************** * Structures and Typedefs * ******************************************************************************/ - typedef struct FILESTORAGEINTERNAL { /** File handle. */ @@ -107,13 +110,14 @@ typedef struct SHASTORAGEINTERNAL #if 0 # define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__) #else -# define DEBUG_PRINT_FLOW() do {} while(0) +# define DEBUG_PRINT_FLOW() do {} while (0) #endif /****************************************************************************** * Internal Functions * ******************************************************************************/ + /****************************************************************************** * Internal: RTFile interface ******************************************************************************/ @@ -281,7 +285,7 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen int rc = VINF_SUCCESS; - if ( fOpen & RTFILE_O_READ + if (fOpen & RTFILE_O_READ && !(fOpen & RTFILE_O_WRITE)) { /* Read only is a little bit more complicated than writing, cause we @@ -297,13 +301,20 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen * */ bool fFound = false; + for (;;) { char *pszFilename = 0; rc = RTTarCurrentFile(tar, &pszFilename); if (RT_SUCCESS(rc)) { - fFound = !strcmp(pszFilename, RTPathFilename(pszLocation)); + if (rc == VINF_TAR_DIR_PATH) + { + break; + } + + fFound = !RTStrICmp(pszFilename, pszLocation); + RTStrFree(pszFilename); if (fFound) break; @@ -311,7 +322,9 @@ static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen { rc = RTTarSeekNextFile(tar); if (RT_FAILURE(rc)) + { break; + } } } else @@ -477,7 +490,7 @@ DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser) int rc = VINF_SUCCESS; bool fLoop = true; - while(fLoop) + while (fLoop) { /* What should we do next? */ uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status); @@ -755,7 +768,7 @@ static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen rc = shaSignalManifestThread(pInt, STATUS_READ); } } - while(0); + while (0); if (RT_FAILURE(rc)) { @@ -1014,7 +1027,7 @@ static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset, if ((cbWrite - cbAllWritten) > cbAvail) { rc = shaSignalManifestThread(pInt, STATUS_WRITE); - if(RT_FAILURE(rc)) + if (RT_FAILURE(rc)) break; /* If there is _no_ free space available, we have to wait until it is. */ if (cbAvail == 0) @@ -1084,24 +1097,29 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset, AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n")); size_t cbAllRead = 0; + size_t cbAvail = 0; for (;;) { /* Finished? */ if (cbAllRead == cbRead) break; - size_t cbAvail = RTCircBufUsed(pInt->pCircBuf); + + cbAvail = RTCircBufUsed(pInt->pCircBuf); + if ( cbAvail == 0 && pInt->fEOF && !RTCircBufIsWriting(pInt->pCircBuf)) { + rc = VINF_EOF; break; } + /* If there isn't enough data make sure the worker thread is fetching * more. */ if ((cbRead - cbAllRead) > cbAvail) { rc = shaSignalManifestThread(pInt, STATUS_READ); - if(RT_FAILURE(rc)) + if (RT_FAILURE(rc)) break; /* If there is _no_ data available, we have to wait until it is. */ if (cbAvail == 0) @@ -1136,6 +1154,7 @@ static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset, /* Signal the thread to read more data in the mean time. */ if ( RT_SUCCESS(rc) + && rc != VINF_EOF && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2)) rc = shaSignalManifestThread(pInt, STATUS_READ); @@ -1164,10 +1183,6 @@ static int shaFlushSyncCallback(void *pvUser, void *pvStorage) return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage); } -/****************************************************************************** - * Public Functions * - ******************************************************************************/ - PVDINTERFACEIO ShaCreateInterface() { PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO)); @@ -1274,7 +1289,7 @@ int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTE memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead); cbAllRead += cbRead; } - }while(0); + } while (0); pIfIo->pfnClose(pvUser, pvStorage); @@ -1325,8 +1340,152 @@ int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFA cbAllWritten += cbWritten; } + rc = pIfIo->pfnClose(pvUser, pvStorage); + + return rc; +} + +int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser) +{ + /* Validate input. */ + AssertPtrReturn(pIfIo, VERR_INVALID_POINTER); + + PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser; + /* + * Open the source file. + */ + void *pvStorage; + int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn, + RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0, + &pvStorage); + if (RT_FAILURE(rc)) + return rc; + + /* Turn the source file handle/whatever into a VFS stream. */ + RTVFSIOSTREAM hVfsIosCompressedSrc; + + rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc); + if (RT_SUCCESS(rc)) + { + /* Pass the source thru gunzip. */ + RTVFSIOSTREAM hVfsIosSrc; + rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc); + if (RT_SUCCESS(rc)) + { + /* + * Create the output file, including necessary paths. + * Any existing file will be overwritten. + */ + rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/); + if (RT_SUCCESS(rc)) + { + RTVFSIOSTREAM hVfsIosDst; + rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut, + RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, + &hVfsIosDst); + if (RT_SUCCESS(rc)) + { + /* + * Pump the bytes thru. If we fail, delete the output file. + */ + RTMANIFEST hFileManifest = NIL_RTMANIFEST; + rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest); + if (RT_SUCCESS(rc)) + { + RTVFSIOSTREAM hVfsIosMfst; + + uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1; + + rc = RTManifestEntryAddPassthruIoStream(hFileManifest, + hVfsIosSrc, + "ovf import", + digestType, + true /*read*/, &hVfsIosMfst); + if (RT_SUCCESS(rc)) + { + rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0); + } + + RTVfsIoStrmRelease(hVfsIosMfst); + } + + RTVfsIoStrmRelease(hVfsIosDst); + } + } + + RTVfsIoStrmRelease(hVfsIosSrc); + } + } pIfIo->pfnClose(pvUser, pvStorage); return rc; } +int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser) +{ + /* Validate input. */ + AssertPtrReturn(pIfIo, VERR_INVALID_POINTER); + + PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser; + void *pvStorage; + + int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename, + RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0, + &pvStorage); + if (RT_FAILURE(rc)) + return rc; + + /* Turn the source file handle/whatever into a VFS stream. */ + RTVFSIOSTREAM hVfsIosSrc; + + rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc); + if (RT_SUCCESS(rc)) + { + /* + * Create the output file, including necessary paths. + * Any existing file will be overwritten. + */ + rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/); + if (RT_SUCCESS(rc)) + { + RTVFSIOSTREAM hVfsIosDst; + rc = RTVfsIoStrmOpenNormal(pcszTargetFilename, + RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, + &hVfsIosDst); + if (RT_SUCCESS(rc)) + { + /* + * Pump the bytes thru. If we fail, delete the output file. + */ + RTMANIFEST hFileManifest = NIL_RTMANIFEST; + rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest); + if (RT_SUCCESS(rc)) + { + RTVFSIOSTREAM hVfsIosMfst; + + uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1; + + rc = RTManifestEntryAddPassthruIoStream(hFileManifest, + hVfsIosSrc, + "ovf import", + digestType, + true /*read*/, &hVfsIosMfst); + if (RT_SUCCESS(rc)) + { + rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0); + } + + RTVfsIoStrmRelease(hVfsIosMfst); + } + + RTVfsIoStrmRelease(hVfsIosDst); + } + } + + RTVfsIoStrmRelease(hVfsIosSrc); + + } + + pIfIo->pfnClose(pvUser, pvStorage); + return rc; +} diff --git a/src/VBox/Main/src-server/ApplianceImplImport.cpp b/src/VBox/Main/src-server/ApplianceImplImport.cpp index 447d717f..1eada736 100644 --- a/src/VBox/Main/src-server/ApplianceImplImport.cpp +++ b/src/VBox/Main/src-server/ApplianceImplImport.cpp @@ -1,11 +1,10 @@ /* $Id: ApplianceImplImport.cpp $ */ /** @file - * * IAppliance and IVirtualSystem COM class implementations. */ /* - * Copyright (C) 2008-2012 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -47,6 +46,8 @@ #include #include +#include + using namespace std; //////////////////////////////////////////////////////////////////////////////// @@ -116,7 +117,8 @@ STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress) STDMETHODIMP Appliance::Interpret() { // @todo: - // - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk)) + // - don't use COM methods but the methods directly (faster, but needs appropriate + // locking of that objects itself (s. HardDisk)) // - Appropriate handle errors like not supported file formats AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -160,21 +162,21 @@ STDMETHODIMP Appliance::Interpret() // if the virtual system in OVF had a element, have the // VirtualBox settings code parse that XML now - if (vsysThis.pelmVboxMachine) - pNewDesc->importVboxMachineXML(*vsysThis.pelmVboxMachine); + if (vsysThis.pelmVBoxMachine) + pNewDesc->importVBoxMachineXML(*vsysThis.pelmVBoxMachine); // Guest OS type // This is taken from one of three places, in this order: Utf8Str strOsTypeVBox; Utf8StrFmt strCIMOSType("%RU32", (uint32_t)vsysThis.cimos); // 1) If there is a , then use the type from there. - if ( vsysThis.pelmVboxMachine + if ( vsysThis.pelmVBoxMachine && pNewDesc->m->pConfig->machineUserData.strOsType.isNotEmpty() ) strOsTypeVBox = pNewDesc->m->pConfig->machineUserData.strOsType; // 2) Otherwise, if there is OperatingSystemSection/vbox:OSType, use that one. - else if (vsysThis.strTypeVbox.isNotEmpty()) // OVFReader has found vbox:OSType - strOsTypeVBox = vsysThis.strTypeVbox; + else if (vsysThis.strTypeVBox.isNotEmpty()) // OVFReader has found vbox:OSType + strOsTypeVBox = vsysThis.strTypeVBox; // 3) Otherwise, make a best guess what the vbox type is from the OVF (CIM) OS type. else convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos, vsysThis.strCimosDesc); @@ -186,7 +188,7 @@ STDMETHODIMP Appliance::Interpret() /* VM name */ Utf8Str nameVBox; /* If there is a , we always prefer the setting from there. */ - if ( vsysThis.pelmVboxMachine + if ( vsysThis.pelmVBoxMachine && pNewDesc->m->pConfig->machineUserData.strName.isNotEmpty()) nameVBox = pNewDesc->m->pConfig->machineUserData.strName; else @@ -269,7 +271,7 @@ STDMETHODIMP Appliance::Interpret() /* CPU count */ ULONG cpuCountVBox; /* If there is a , we always prefer the setting from there. */ - if ( vsysThis.pelmVboxMachine + if ( vsysThis.pelmVBoxMachine && pNewDesc->m->pConfig->hardwareMachine.cCPUs) cpuCountVBox = pNewDesc->m->pConfig->hardwareMachine.cCPUs; else @@ -277,7 +279,8 @@ STDMETHODIMP Appliance::Interpret() /* Check for the constraints */ if (cpuCountVBox > SchemaDefs::MaxCPUCount) { - addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."), + addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for " + "max %u CPU's only."), vsysThis.strName.c_str(), cpuCountVBox, SchemaDefs::MaxCPUCount); cpuCountVBox = SchemaDefs::MaxCPUCount; } @@ -291,7 +294,7 @@ STDMETHODIMP Appliance::Interpret() /* RAM */ uint64_t ullMemSizeVBox; /* If there is a , we always prefer the setting from there. */ - if ( vsysThis.pelmVboxMachine + if ( vsysThis.pelmVBoxMachine && pNewDesc->m->pConfig->hardwareMachine.ulMemorySizeMB) ullMemSizeVBox = pNewDesc->m->pConfig->hardwareMachine.ulMemorySizeMB; else @@ -303,7 +306,8 @@ STDMETHODIMP Appliance::Interpret() ) ) { - addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has support for min %u & max %u MB RAM size only."), + addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has " + "support for min %u & max %u MB RAM size only."), vsysThis.strName.c_str(), ullMemSizeVBox, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB); ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, MM_RAM_MIN_IN_MB), MM_RAM_MAX_IN_MB); } @@ -325,9 +329,12 @@ STDMETHODIMP Appliance::Interpret() Utf8Str strSoundCard; Utf8Str strSoundCardOrig; /* If there is a , we always prefer the setting from there. */ - if ( vsysThis.pelmVboxMachine + if ( vsysThis.pelmVBoxMachine && pNewDesc->m->pConfig->hardwareMachine.audioAdapter.fEnabled) - strSoundCard = Utf8StrFmt("%RU32", (uint32_t)pNewDesc->m->pConfig->hardwareMachine.audioAdapter.controllerType); + { + strSoundCard = Utf8StrFmt("%RU32", + (uint32_t)pNewDesc->m->pConfig->hardwareMachine.audioAdapter.controllerType); + } else if (vsysThis.strSoundCardType.isNotEmpty()) { /* Set the AC97 always for the simple OVF case. @@ -344,22 +351,23 @@ STDMETHODIMP Appliance::Interpret() #ifdef VBOX_WITH_USB /* USB Controller */ /* If there is a , we always prefer the setting from there. */ - if ( ( vsysThis.pelmVboxMachine - && pNewDesc->m->pConfig->hardwareMachine.usbController.fEnabled) + if ( ( vsysThis.pelmVBoxMachine + && pNewDesc->m->pConfig->hardwareMachine.usbSettings.llUSBControllers.size() > 0) || vsysThis.fHasUsbController) pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", ""); #endif /* VBOX_WITH_USB */ /* Network Controller */ /* If there is a , we always prefer the setting from there. */ - if (vsysThis.pelmVboxMachine) + if (vsysThis.pelmVBoxMachine) { uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(pNewDesc->m->pConfig->hardwareMachine.chipsetType); const settings::NetworkAdaptersList &llNetworkAdapters = pNewDesc->m->pConfig->hardwareMachine.llNetworkAdapters; /* Check for the constrains */ if (llNetworkAdapters.size() > maxNetworkAdapters) - addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."), + addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox " + "has support for max %u network adapter only."), vsysThis.strName.c_str(), llNetworkAdapters.size(), maxNetworkAdapters); /* Iterate through all network adapters. */ settings::NetworkAdaptersList::const_iterator it1; @@ -387,7 +395,8 @@ STDMETHODIMP Appliance::Interpret() /* Check for the constrains */ if (cEthernetAdapters > maxNetworkAdapters) - addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."), + addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox " + "has support for max %u network adapter only."), vsysThis.strName.c_str(), cEthernetAdapters, maxNetworkAdapters); /* Get the default network adapter type for the selected guest OS */ @@ -462,7 +471,7 @@ STDMETHODIMP Appliance::Interpret() /* If there is a , we always prefer the setting from there. */ bool fFloppy = false; bool fDVD = false; - if (vsysThis.pelmVboxMachine) + if (vsysThis.pelmVBoxMachine) { settings::StorageControllersList &llControllers = pNewDesc->m->pConfig->storageMachine.llStorageControllers; settings::StorageControllersList::iterator it3; @@ -526,12 +535,13 @@ STDMETHODIMP Appliance::Interpret() pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, strControllerID, // strRef hdc.strControllerType, // aOvfValue - strType); // aVboxValue + strType); // aVBoxValue } else /* Warn only once */ if (cIDEused == 2) - addWarning(tr("The virtual \"%s\" system requests support for more than two IDE controller channels, but VirtualBox supports only two."), + addWarning(tr("The virtual \"%s\" system requests support for more than two " + "IDE controller channels, but VirtualBox supports only two."), vsysThis.strName.c_str()); ++cIDEused; @@ -552,7 +562,8 @@ STDMETHODIMP Appliance::Interpret() { /* Warn only once */ if (cSATAused == 1) - addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"), + addWarning(tr("The virtual system \"%s\" requests support for more than one " + "SATA controller, but VirtualBox has support for only one"), vsysThis.strName.c_str()); } @@ -579,7 +590,9 @@ STDMETHODIMP Appliance::Interpret() hdcController); } else - addWarning(tr("The virtual system \"%s\" requests support for an additional SCSI controller of type \"%s\" with ID %s, but VirtualBox presently supports only one SCSI controller."), + addWarning(tr("The virtual system \"%s\" requests support for an additional " + "SCSI controller of type \"%s\" with ID %s, but VirtualBox presently " + "supports only one SCSI controller."), vsysThis.strName.c_str(), hdc.strControllerType.c_str(), strControllerID.c_str()); @@ -599,22 +612,96 @@ STDMETHODIMP Appliance::Interpret() { const ovf::VirtualDisk &hd = itVD->second; /* Get the associated disk image */ - const ovf::DiskImage &di = m->pReader->m_mapDisks[hd.strDiskId]; + ovf::DiskImage di; + std::map::iterator foundDisk; + + foundDisk = m->pReader->m_mapDisks.find(hd.strDiskId); + if (foundDisk == m->pReader->m_mapDisks.end()) + continue; + else + { + di = foundDisk->second; + } + + /* + * Figure out from URI which format the image of disk has. + * URI must have inside section . + * But there aren't strong requirements about correspondence one URI for one disk virtual format. + * So possibly, we aren't able to recognize some URIs. + */ + Utf8Str vdf = typeOfVirtualDiskFormatFromURI(di.strFormat); + + /* + * fallback, if we can't determine virtual disk format using URI from the attribute ovf:format + * in the corresponding section in the OVF file. + */ + if (vdf.isEmpty()) + { + /* Figure out from extension which format the image of disk has. */ + { + char *pszExt = RTPathExt(di.strHref.c_str()); + /* Get the system properties. */ + SystemProperties *pSysProps = mVirtualBox->getSystemProperties(); + ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]); + if (trgFormat.isNull()) + { + throw setError(E_FAIL, + tr("Internal inconsistency looking up medium format for the disk image '%s'"), + di.strHref.c_str()); + } + + Bstr bstrFormatName; + rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); + if (FAILED(rc)) + throw rc; + + vdf = Utf8Str(bstrFormatName); + } + } // @todo: // - figure out all possible vmdk formats we also support // - figure out if there is a url specifier for vhd already // - we need a url specifier for the vdi format - if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive) - ) + + if (vdf.compare("VMDK", Utf8Str::CaseInsensitive) == 0) + { + /* If the href is empty use the VM name as filename */ + Utf8Str strFilename = di.strHref; + if (!strFilename.length()) + strFilename = Utf8StrFmt("%s.vmdk", hd.strDiskId.c_str()); + + Utf8Str strTargetPath = Utf8Str(strMachineFolder); + strTargetPath.append(RTPATH_DELIMITER).append(di.strHref); + searchUniqueDiskImageFilePath(strTargetPath); + + /* find the description for the hard disk controller + * that has the same ID as hd.idController */ + const VirtualSystemDescriptionEntry *pController; + if (!(pController = pNewDesc->findControllerFromID(hd.idController))) + throw setError(E_FAIL, + tr("Cannot find hard disk controller with OVF instance ID %RI32 " + "to which disk \"%s\" should be attached"), + hd.idController, + di.strHref.c_str()); + + /* controller to attach to, and the bus within that controller */ + Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16", + pController->ulIndex, + hd.ulAddressOnParent); + pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage, + hd.strDiskId, + di.strHref, + strTargetPath, + di.ulSuggestedSizeMB, + strExtraConfig); + } + else if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0) { /* If the href is empty use the VM name as filename */ Utf8Str strFilename = di.strHref; if (!strFilename.length()) - strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str()); + strFilename = Utf8StrFmt("%s.iso", hd.strDiskId.c_str()); Utf8Str strTargetPath = Utf8Str(strMachineFolder) .append(RTPATH_DELIMITER) @@ -626,7 +713,8 @@ STDMETHODIMP Appliance::Interpret() const VirtualSystemDescriptionEntry *pController; if (!(pController = pNewDesc->findControllerFromID(hd.idController))) throw setError(E_FAIL, - tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"), + tr("Cannot find disk controller with OVF instance ID %RI32 " + "to which disk \"%s\" should be attached"), hd.idController, di.strHref.c_str()); @@ -643,7 +731,9 @@ STDMETHODIMP Appliance::Interpret() } else throw setError(VBOX_E_FILE_ERROR, - tr("Unsupported format for virtual disk image in OVF: \"%s\"", di.strFormat.c_str())); + tr("Unsupported format for virtual disk image %s in OVF: \"%s\""), + di.strHref.c_str(), + di.strFormat.c_str()); } } @@ -678,12 +768,12 @@ STDMETHODIMP Appliance::ImportMachines(ComSafeArrayIn(ImportOptions_T, options), AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - if (options != NULL) - m->optList = com::SafeArray(ComSafeArrayInArg(options)).toList(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - AssertReturn(!(m->optList.contains(ImportOptions_KeepAllMACs) && m->optList.contains(ImportOptions_KeepNATMACs)), E_INVALIDARG); + if (options != NULL) + m->optListImport = com::SafeArray(ComSafeArrayInArg(options)).toList(); - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertReturn(!(m->optListImport.contains(ImportOptions_KeepAllMACs) && m->optListImport.contains(ImportOptions_KeepNATMACs)), E_INVALIDARG); // do not allow entering this method if the appliance is busy reading or writing if (!isApplianceIdle()) @@ -717,6 +807,35 @@ STDMETHODIMP Appliance::ImportMachines(ComSafeArrayIn(ImportOptions_T, options), // //////////////////////////////////////////////////////////////////////////////// +HRESULT Appliance::preCheckImageAvailability(PSHASTORAGE pSHAStorage, + RTCString &availableImage) +{ + HRESULT rc = S_OK; + RTTAR tar = (RTTAR)pSHAStorage->pVDImageIfaces->pvUser; + char *pszFilename = 0; + + int vrc = RTTarCurrentFile(tar, &pszFilename); + + if (RT_FAILURE(vrc)) + { + throw setError(VBOX_E_FILE_ERROR, + tr("Could not open the current file in the OVA package (%Rrc)"), vrc); + } + else + { + if (vrc == VINF_TAR_DIR_PATH) + { + throw setError(VBOX_E_FILE_ERROR, + tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"), + pszFilename, + vrc); + } + } + + availableImage = pszFilename; + + return rc; +} /******************************************************************************* * Read stuff @@ -818,36 +937,125 @@ HRESULT Appliance::readFSOVF(TaskOVF *pTask) LogFlowFuncEnter(); HRESULT rc = S_OK; + int vrc = VINF_SUCCESS; PVDINTERFACEIO pShaIo = 0; PVDINTERFACEIO pFileIo = 0; do { - pShaIo = ShaCreateInterface(); - if (!pShaIo) - { - rc = E_OUTOFMEMORY; - break; - } - pFileIo = FileCreateInterface(); - if (!pFileIo) + try { - rc = E_OUTOFMEMORY; - break; + /* Create the necessary file access interfaces. */ + pFileIo = FileCreateInterface(); + if (!pFileIo) + { + rc = E_OUTOFMEMORY; + break; + } + + Utf8Str strMfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".mf"); + + SHASTORAGE storage; + RT_ZERO(storage); + + if (RTFileExists(strMfFile.c_str())) + { + pShaIo = ShaCreateInterface(); + if (!pShaIo) + { + rc = E_OUTOFMEMORY; + break; + } + + //read the manifest file and find a type of used digest + RTFILE pFile = NULL; + vrc = RTFileOpen(&pFile, strMfFile.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE); + if (RT_SUCCESS(vrc) && pFile != NULL) + { + uint64_t cbFile = 0; + uint64_t maxFileSize = _1M; + size_t cbRead = 0; + void *pBuf; /** @todo r=bird: You leak this buffer! throwing stuff is evil. */ + + vrc = RTFileGetSize(pFile, &cbFile); + if (cbFile > maxFileSize) + throw setError(VBOX_E_FILE_ERROR, + tr("Size of the manifest file '%s' is bigger than 1Mb. Check it, please."), + RTPathFilename(strMfFile.c_str())); + + if (RT_SUCCESS(vrc)) + pBuf = RTMemAllocZ(cbFile); + else + throw setError(VBOX_E_FILE_ERROR, + tr("Could not get size of the manifest file '%s' "), + RTPathFilename(strMfFile.c_str())); + + vrc = RTFileRead(pFile, pBuf, cbFile, &cbRead); + + if (RT_FAILURE(vrc)) + { + if (pBuf) + RTMemFree(pBuf); + throw setError(VBOX_E_FILE_ERROR, + tr("Could not read the manifest file '%s' (%Rrc)"), + RTPathFilename(strMfFile.c_str()), vrc); + } + + RTFileClose(pFile); + + RTDIGESTTYPE digestType; + vrc = RTManifestVerifyDigestType(pBuf, cbRead, &digestType); + + if (pBuf) + RTMemFree(pBuf); + + if (RT_FAILURE(vrc)) + { + throw setError(VBOX_E_FILE_ERROR, + tr("Could not verify supported digest types in the manifest file '%s' (%Rrc)"), + RTPathFilename(strMfFile.c_str()), vrc); + } + + storage.fCreateDigest = true; + + if (digestType == RTDIGESTTYPE_SHA256) + { + storage.fSha256 = true; + } + + Utf8Str name = applianceIOName(applianceIOFile); + + vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(), + VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), + &storage.pVDImageIfaces); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); + + rc = readFSImpl(pTask, pTask->locInfo.strPath, pShaIo, &storage); + if (FAILED(rc)) + break; + } + else + { + throw setError(VBOX_E_FILE_ERROR, + tr("Could not open the manifest file '%s' (%Rrc)"), + RTPathFilename(strMfFile.c_str()), vrc); + } + } + else + { + storage.fCreateDigest = false; + rc = readFSImpl(pTask, pTask->locInfo.strPath, pFileIo, &storage); + if (FAILED(rc)) + break; + } } - SHASTORAGE storage; - RT_ZERO(storage); - int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile", - VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), - &storage.pVDImageIfaces); - if (RT_FAILURE(vrc)) + catch (HRESULT rc2) { - rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); - break; + rc = rc2; } - rc = readFSImpl(pTask, pTask->locInfo.strPath, pShaIo, &storage); - }while(0); + }while (0); /* Cleanup */ if (pShaIo) @@ -866,51 +1074,79 @@ HRESULT Appliance::readFSOVA(TaskOVF *pTask) LogFlowFuncEnter(); RTTAR tar; - int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true); - if (RT_FAILURE(vrc)) - return setError(VBOX_E_FILE_ERROR, - tr("Could not open OVA file '%s' (%Rrc)"), - pTask->locInfo.strPath.c_str(), vrc); - HRESULT rc = S_OK; - + int vrc = 0; PVDINTERFACEIO pShaIo = 0; PVDINTERFACEIO pTarIo = 0; char *pszFilename = 0; - do + SHASTORAGE storage; + + RT_ZERO(storage); + + vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true); + if (RT_FAILURE(vrc)) + rc = setError(VBOX_E_FILE_ERROR, + tr("Could not open the OVA file '%s' (%Rrc)"), + pTask->locInfo.strPath.c_str(), vrc); + else { - vrc = RTTarCurrentFile(tar, &pszFilename); - if (RT_FAILURE(vrc)) - { - rc = VBOX_E_FILE_ERROR; - break; - } - pShaIo = ShaCreateInterface(); - if (!pShaIo) - { - rc = E_OUTOFMEMORY; - break; - } - pTarIo = TarCreateInterface(); - if (!pTarIo) - { - rc = E_OUTOFMEMORY; - break; - } - SHASTORAGE storage; - RT_ZERO(storage); - vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar", - VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO), - &storage.pVDImageIfaces); - if (RT_FAILURE(vrc)) + do { - rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); - break; - } - rc = readFSImpl(pTask, pszFilename, pShaIo, &storage); - }while(0); + vrc = RTTarCurrentFile(tar, &pszFilename); + if (RT_FAILURE(vrc)) + { + rc = VBOX_E_FILE_ERROR; + break; + } + + Utf8Str extension(RTPathExt(pszFilename)); + + if (!extension.endsWith(".ovf",Utf8Str::CaseInsensitive)) + { + vrc = VERR_FILE_NOT_FOUND; + rc = setError(VBOX_E_FILE_ERROR, + tr("First file in the OVA package must have the extension 'ovf'. " + "But the file '%s' has the different extension (%Rrc)"), + pszFilename, + vrc); + break; + } + + pTarIo = TarCreateInterface(); + if (!pTarIo) + { + rc = E_OUTOFMEMORY; + break; + } + + pShaIo = ShaCreateInterface(); + if (!pShaIo) + { + rc = E_OUTOFMEMORY; + break ; + } + + Utf8Str name = applianceIOName(applianceIOTar); + + vrc = VDInterfaceAdd(&pTarIo->Core, name.c_str(), + VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO), + &storage.pVDImageIfaces); + if (RT_FAILURE(vrc)) + { + rc = setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); + break; + } + + rc = readFSImpl(pTask, pszFilename, pShaIo, &storage); + if (FAILED(rc)) + break; + + } while (0); + + RTTarClose(tar); + } + - RTTarClose(tar); /* Cleanup */ if (pszFilename) @@ -940,15 +1176,49 @@ HRESULT Appliance::readFSImpl(TaskOVF *pTask, const RTCString &strFilename, PVDI /* Read the OVF into a memory buffer */ size_t cbSize = 0; int vrc = ShaReadBuf(strFilename.c_str(), &pvTmpBuf, &cbSize, pIfIo, pStorage); - if ( RT_FAILURE(vrc) + if (RT_FAILURE(vrc) || !pvTmpBuf) throw setError(VBOX_E_FILE_ERROR, tr("Could not read OVF file '%s' (%Rrc)"), RTPathFilename(strFilename.c_str()), vrc); - /* Copy the SHA1/SHA256 sum of the OVF file for later validation */ - m->strOVFSHADigest = pStorage->strDigest; + /* Read & parse the XML structure of the OVF file */ m->pReader = new ovf::OVFReader(pvTmpBuf, cbSize, pTask->locInfo.strPath); + + if (m->pReader->m_envelopeData.getOVFVersion() == ovf::OVFVersion_2_0) + { + m->fSha256 = true; + + uint8_t digest[RTSHA256_HASH_SIZE]; + size_t cbDigest = RTSHA256_DIGEST_LEN; + char *pszDigest; + + RTSha256(pvTmpBuf, cbSize, &digest[0]); + + vrc = RTStrAllocEx(&pszDigest, cbDigest + 1); + if (RT_SUCCESS(vrc)) + vrc = RTSha256ToString(digest, pszDigest, cbDigest + 1); + else + throw setError(VBOX_E_FILE_ERROR, + tr("Could not allocate string for SHA256 digest (%Rrc)"), vrc); + + if (RT_SUCCESS(vrc)) + /* Copy the SHA256 sum of the OVF file for later validation */ + m->strOVFSHADigest = pszDigest; + else + throw setError(VBOX_E_FILE_ERROR, + tr("Converting SHA256 digest to a string was failed (%Rrc)"), vrc); + + RTStrFree(pszDigest); + + } + else + { + m->fSha256 = false; + /* Copy the SHA1 sum of the OVF file for later validation */ + m->strOVFSHADigest = pStorage->strDigest; + } + } catch (RTCError &x) // includes all XML exceptions { @@ -1017,7 +1287,11 @@ HRESULT Appliance::readS3(TaskOVF *pTask) strTmpOvf = Utf8StrFmt("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str())); /* Next we have to download the OVF */ - vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING); + vrc = RTS3Create(&hS3, + pTask->locInfo.strUsername.c_str(), + pTask->locInfo.strPassword.c_str(), + pTask->locInfo.strHostname.c_str(), + "virtualbox-agent/"VBOX_VERSION_STRING); if (RT_FAILURE(vrc)) throw setError(VBOX_E_IPRT_ERROR, tr("Cannot create S3 service handler")); @@ -1032,7 +1306,8 @@ HRESULT Appliance::readS3(TaskOVF *pTask) throw S_OK; /* todo: !!!!!!!!!!!!! */ else if (vrc == VERR_S3_ACCESS_DENIED) throw setError(E_ACCESSDENIED, - tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right." + tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that " + "your credentials are right. " "Also check that your host clock is properly synced"), pszFilename); else if (vrc == VERR_S3_NOT_FOUND) @@ -1148,9 +1423,12 @@ HRESULT Appliance::importImpl(const LocationInfo &locInfo, } /** - * Actual worker code for importing OVF data into VirtualBox. This is called from Appliance::taskThreadImportOrExport() - * and therefore runs on the OVF import worker thread. This creates one or more new machines according to the - * VirtualSystemScription instances created by Appliance::Interpret(). + * Actual worker code for importing OVF data into VirtualBox. + * + * This is called from Appliance::taskThreadImportOrExport() and therefore runs + * on the OVF import worker thread. This creates one or more new machines + * according to the VirtualSystemScription instances created by + * Appliance::Interpret(). * * This runs in three contexts: * @@ -1162,8 +1440,8 @@ HRESULT Appliance::importImpl(const LocationInfo &locInfo, * 3) in a second worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(), which * called Appliance::importS3(), which called Appliance::importImpl(), which then called this again. * - * @param pTask - * @return + * @param pTask The OVF task data. + * @return COM status code. */ HRESULT Appliance::importFS(TaskOVF *pTask) { @@ -1199,6 +1477,7 @@ HRESULT Appliance::importFS(TaskOVF *pTask) /* With _whatever_ error we've had, do a complete roll-back of * machines and disks we've created */ writeLock.release(); + ErrorInfoKeeper eik; for (list::iterator itID = m->llGuidsMachinesCreated.begin(); itID != m->llGuidsMachinesCreated.end(); ++itID) @@ -1212,7 +1491,7 @@ HRESULT Appliance::importFS(TaskOVF *pTask) SafeIfaceArray aMedia; rc2 = failedMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(aMedia)); ComPtr pProgress2; - rc2 = failedMachine->Delete(ComSafeArrayAsInParam(aMedia), pProgress2.asOutParam()); + rc2 = failedMachine->DeleteConfig(ComSafeArrayAsInParam(aMedia), pProgress2.asOutParam()); pProgress2->WaitForCompletion(-1); } } @@ -1237,6 +1516,7 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) PVDINTERFACEIO pShaIo = NULL; PVDINTERFACEIO pFileIo = NULL; void *pvMfBuf = NULL; + void *pvCertBuf = NULL; writeLock.release(); try { @@ -1246,39 +1526,69 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) throw setError(E_OUTOFMEMORY); Utf8Str strMfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".mf"); + + SHASTORAGE storage; + RT_ZERO(storage); + + Utf8Str name = applianceIOName(applianceIOFile); + + int vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(), + VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), + &storage.pVDImageIfaces); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); + /* Create the import stack for the rollback on errors. */ ImportStack stack(pTask->locInfo, m->pReader->m_mapDisks, pTask->pProgress); if (RTFileExists(strMfFile.c_str())) { - SHASTORAGE storage; - RT_ZERO(storage); - pShaIo = ShaCreateInterface(); if (!pShaIo) throw setError(E_OUTOFMEMORY); + Utf8Str nameSha = applianceIOName(applianceIOSha); + /* Fill out interface descriptor. */ + pShaIo->Core.u32Magic = VDINTERFACE_MAGIC; + pShaIo->Core.cbSize = sizeof(VDINTERFACEIO); + pShaIo->Core.pszInterfaceName = nameSha.c_str(); + pShaIo->Core.enmInterface = VDINTERFACETYPE_IO; + pShaIo->Core.pvUser = &storage; + pShaIo->Core.pNext = NULL; + storage.fCreateDigest = true; - int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile", - VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), - &storage.pVDImageIfaces); - if (RT_FAILURE(vrc)) - throw setError(VBOX_E_IPRT_ERROR, "Creation of the VD interface failed (%Rrc)", vrc); size_t cbMfSize = 0; - storage.fCreateDigest = true; + /* Now import the appliance. */ importMachines(stack, pShaIo, &storage); /* Read & verify the manifest file. */ /* Add the ovf file to the digest list. */ stack.llSrcDisksDigest.push_front(STRPAIR(pTask->locInfo.strPath, m->strOVFSHADigest)); - rc = readManifestFile(strMfFile, &pvMfBuf, &cbMfSize, pShaIo, &storage); + rc = readFileToBuf(strMfFile, &pvMfBuf, &cbMfSize, true, pShaIo, &storage); if (FAILED(rc)) throw rc; rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize); if (FAILED(rc)) throw rc; + + size_t cbCertSize = 0; + + /* Save the SHA digest of the manifest file for the next validation */ + Utf8Str manifestShaDigest = storage.strDigest; + + Utf8Str strCertFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".cert"); + if (RTFileExists(strCertFile.c_str())) + { + rc = readFileToBuf(strCertFile, &pvCertBuf, &cbCertSize, false, pShaIo, &storage); + if (FAILED(rc)) throw rc; + + /* verify Certificate */ + } } else - importMachines(stack, pFileIo, NULL); + { + storage.fCreateDigest = false; + importMachines(stack, pFileIo, &storage); + } } catch (HRESULT rc2) { @@ -1289,6 +1599,8 @@ HRESULT Appliance::importFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) /* Cleanup */ if (pvMfBuf) RTMemFree(pvMfBuf); + if (pvCertBuf) + RTMemFree(pvCertBuf); if (pShaIo) RTMemFree(pShaIo); if (pFileIo) @@ -1305,7 +1617,9 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) LogFlowFuncEnter(); RTTAR tar; - int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true); + int vrc = RTTarOpen(&tar, + pTask->locInfo.strPath.c_str(), + RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true); if (RT_FAILURE(vrc)) return setError(VBOX_E_FILE_ERROR, tr("Could not open OVA file '%s' (%Rrc)"), @@ -1317,6 +1631,9 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) PVDINTERFACEIO pTarIo = 0; char *pszFilename = 0; void *pvMfBuf = 0; + void *pvCertBuf = 0; + Utf8Str OVFfilename; + writeLock.release(); try { @@ -1330,25 +1647,66 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) SHASTORAGE storage; RT_ZERO(storage); - vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar", + + Utf8Str nameTar = applianceIOName(applianceIOTar); + + vrc = VDInterfaceAdd(&pTarIo->Core, nameTar.c_str(), VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO), &storage.pVDImageIfaces); if (RT_FAILURE(vrc)) throw setError(VBOX_E_IPRT_ERROR, tr("Creation of the VD interface failed (%Rrc)"), vrc); + Utf8Str nameSha = applianceIOName(applianceIOSha); + /* Fill out interface descriptor. */ + pShaIo->Core.u32Magic = VDINTERFACE_MAGIC; + pShaIo->Core.cbSize = sizeof(VDINTERFACEIO); + pShaIo->Core.pszInterfaceName = nameSha.c_str(); + pShaIo->Core.enmInterface = VDINTERFACETYPE_IO; + pShaIo->Core.pvUser = &storage; + pShaIo->Core.pNext = NULL; + /* Read the file name of the first file (need to be the ovf file). This * is how all internal files are named. */ vrc = RTTarCurrentFile(tar, &pszFilename); if (RT_FAILURE(vrc)) throw setError(VBOX_E_IPRT_ERROR, - tr("Getting the current file within the archive failed (%Rrc)"), vrc); - /* Skip the OVF file, cause this was read in IAppliance::Read already. */ - vrc = RTTarSeekNextFile(tar); - if ( RT_FAILURE(vrc) - && vrc != VERR_TAR_END_OF_FILE) - throw setError(VBOX_E_IPRT_ERROR, + tr("Getting the OVF file within the archive failed (%Rrc)"), vrc); + else + { + if (vrc == VINF_TAR_DIR_PATH) + { + throw setError(VBOX_E_FILE_ERROR, + tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"), + pszFilename, + vrc); + } + } + + /* save original OVF filename */ + OVFfilename = pszFilename; + size_t cbMfSize = 0; + size_t cbCertSize = 0; + Utf8Str strMfFile = (Utf8Str(pszFilename)).stripExt().append(".mf"); + Utf8Str strCertFile = (Utf8Str(pszFilename)).stripExt().append(".cert"); + + /* Skip the OVF file, cause this was read in IAppliance::Read already. */ + vrc = RTTarSeekNextFile(tar); + if ( RT_FAILURE(vrc) + && vrc != VERR_TAR_END_OF_FILE) + throw setError(VBOX_E_IPRT_ERROR, tr("Seeking within the archive failed (%Rrc)"), vrc); + else + { + RTTarCurrentFile(tar, &pszFilename); + if (vrc == VINF_TAR_DIR_PATH) + { + throw setError(VBOX_E_FILE_ERROR, + tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"), + pszFilename, + vrc); + } + } PVDINTERFACEIO pCallbacks = pShaIo; PSHASTORAGE pStorage = &storage; @@ -1357,8 +1715,6 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) * is a manifest file in the stream. */ pStorage->fCreateDigest = true; - size_t cbMfSize = 0; - Utf8Str strMfFile = Utf8Str(pszFilename).stripExt().append(".mf"); /* Create the import stack for the rollback on errors. */ ImportStack stack(pTask->locInfo, m->pReader->m_mapDisks, pTask->pProgress); /* @@ -1373,23 +1729,68 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) * searching for it. We have to try to open it on all possible places. * If it fails here, we will try it again after all disks where read. */ - rc = readTarManifestFile(tar, strMfFile, &pvMfBuf, &cbMfSize, pCallbacks, pStorage); + rc = readTarFileToBuf(tar, strMfFile, &pvMfBuf, &cbMfSize, true, pCallbacks, pStorage); if (FAILED(rc)) throw rc; + + /* + * Try to read the certificate file. First try. + * Logic is the same as with manifest file + * Only if the manifest file had been read successfully before + */ + vrc = RTTarCurrentFile(tar, &pszFilename); + if (RT_SUCCESS(vrc)) + { + if (pvMfBuf) + { + if (strCertFile.compare(pszFilename) == 0) + { + rc = readTarFileToBuf(tar, strCertFile, &pvCertBuf, &cbCertSize, false, pCallbacks, pStorage); + if (FAILED(rc)) throw rc; + + if (pvCertBuf) + { + /* verify the certificate */ + } + } + } + } + /* Now import the appliance. */ importMachines(stack, pCallbacks, pStorage); /* Try to read the manifest file. Second try. */ if (!pvMfBuf) { - rc = readTarManifestFile(tar, strMfFile, &pvMfBuf, &cbMfSize, pCallbacks, pStorage); - if (FAILED(rc)) throw rc; - } - /* If we were able to read a manifest file we can check it now. */ - if (pvMfBuf) - { - /* Add the ovf file to the digest list. */ - stack.llSrcDisksDigest.push_front(STRPAIR(Utf8Str(pszFilename).stripExt().append(".ovf"), m->strOVFSHADigest)); - rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize); + rc = readTarFileToBuf(tar, strMfFile, &pvMfBuf, &cbMfSize, true, pCallbacks, pStorage); if (FAILED(rc)) throw rc; + + /* If we were able to read a manifest file we can check it now. */ + if (pvMfBuf) + { + /* Add the ovf file to the digest list. */ + stack.llSrcDisksDigest.push_front(STRPAIR(OVFfilename, m->strOVFSHADigest)); + rc = verifyManifestFile(strMfFile, stack, pvMfBuf, cbMfSize); + if (FAILED(rc)) throw rc; + + /* + * Try to read the certificate file. Second try. + * Only if the manifest file had been read successfully before + */ + + vrc = RTTarCurrentFile(tar, &pszFilename); + if (RT_SUCCESS(vrc)) + { + if (strCertFile.compare(pszFilename) == 0) + { + rc = readTarFileToBuf(tar, strCertFile, &pvCertBuf, &cbCertSize, false, pCallbacks, pStorage); + if (FAILED(rc)) throw rc; + + if (pvCertBuf) + { + /* verify the certificate */ + } + } + } + } } } catch (HRESULT rc2) @@ -1409,6 +1810,8 @@ HRESULT Appliance::importFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) RTMemFree(pShaIo); if (pTarIo) RTMemFree(pTarIo); + if (pvCertBuf) + RTMemFree(pvCertBuf); LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); @@ -1481,7 +1884,11 @@ HRESULT Appliance::importS3(TaskOVF *pTask) } /* Next we have to download the disk images */ - vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING); + vrc = RTS3Create(&hS3, + pTask->locInfo.strUsername.c_str(), + pTask->locInfo.strPassword.c_str(), + pTask->locInfo.strHostname.c_str(), + "virtualbox-agent/"VBOX_VERSION_STRING); if (RT_FAILURE(vrc)) throw setError(VBOX_E_IPRT_ERROR, tr("Cannot create S3 service handler")); @@ -1506,7 +1913,8 @@ HRESULT Appliance::importS3(TaskOVF *pTask) else if (vrc == VERR_S3_ACCESS_DENIED) throw setError(E_ACCESSDENIED, tr("Cannot download file '%s' from S3 storage server (Access denied). " - "Make sure that your credentials are right. Also check that your host clock is properly synced"), + "Make sure that your credentials are right. Also check that your host clock is " + "properly synced"), pszFilename); else if (vrc == VERR_S3_NOT_FOUND) throw setError(VBOX_E_FILE_ERROR, @@ -1542,7 +1950,8 @@ HRESULT Appliance::importS3(TaskOVF *pTask) else if (vrc == VERR_S3_ACCESS_DENIED) throw setError(E_ACCESSDENIED, tr("Cannot download file '%s' from S3 storage server (Access denied)." - "Make sure that your credentials are right. Also check that your host clock is properly synced"), + "Make sure that your credentials are right. " + "Also check that your host clock is properly synced"), pszFilename); else throw setError(VBOX_E_IPRT_ERROR, @@ -1609,24 +2018,35 @@ HRESULT Appliance::importS3(TaskOVF *pTask) } #endif /* VBOX_WITH_S3 */ -HRESULT Appliance::readManifestFile(const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage) +HRESULT Appliance::readFileToBuf(const Utf8Str &strFile, + void **ppvBuf, + size_t *pcbSize, + bool fCreateDigest, + PVDINTERFACEIO pCallbacks, + PSHASTORAGE pStorage) { HRESULT rc = S_OK; - bool fOldDigest = pStorage->fCreateDigest; - pStorage->fCreateDigest = false; /* No digest for the manifest file */ + bool fOldDigest = pStorage->fCreateDigest;/* Save the old digest property */ + pStorage->fCreateDigest = fCreateDigest; int vrc = ShaReadBuf(strFile.c_str(), ppvBuf, pcbSize, pCallbacks, pStorage); if ( RT_FAILURE(vrc) && vrc != VERR_FILE_NOT_FOUND) rc = setError(VBOX_E_FILE_ERROR, - tr("Could not read manifest file '%s' (%Rrc)"), + tr("Could not read file '%s' (%Rrc)"), RTPathFilename(strFile.c_str()), vrc); pStorage->fCreateDigest = fOldDigest; /* Restore the old digest creation behavior again. */ return rc; } -HRESULT Appliance::readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage) +HRESULT Appliance::readTarFileToBuf(RTTAR tar, + const Utf8Str &strFile, + void **ppvBuf, + size_t *pcbSize, + bool fCreateDigest, + PVDINTERFACEIO pCallbacks, + PSHASTORAGE pStorage) { HRESULT rc = S_OK; @@ -1634,9 +2054,19 @@ HRESULT Appliance::readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void * int vrc = RTTarCurrentFile(tar, &pszCurFile); if (RT_SUCCESS(vrc)) { - if (!strcmp(pszCurFile, RTPathFilename(strFile.c_str()))) - rc = readManifestFile(strFile, ppvBuf, pcbSize, pCallbacks, pStorage); - RTStrFree(pszCurFile); + if (vrc == VINF_TAR_DIR_PATH) + { + rc = setError(VBOX_E_FILE_ERROR, + tr("Empty directory folder (%s) isn't allowed in the OVA package (%Rrc)"), + pszCurFile, + vrc); + } + else + { + if (!strcmp(pszCurFile, RTPathFilename(strFile.c_str()))) + rc = readFileToBuf(strFile, ppvBuf, pcbSize, fCreateDigest, pCallbacks, pStorage); + RTStrFree(pszCurFile); + } } else if (vrc != VERR_TAR_END_OF_FILE) rc = setError(VBOX_E_IPRT_ERROR, "Seeking within the archive failed (%Rrc)", vrc); @@ -1665,7 +2095,7 @@ HRESULT Appliance::verifyManifestFile(const Utf8Str &strFile, ImportStack &stack int vrc = RTManifestVerifyFilesBuf(pvBuf, cbSize, paTests, stack.llSrcDisksDigest.size(), &iFailed); if (RT_UNLIKELY(vrc == VERR_MANIFEST_DIGEST_MISMATCH)) rc = setError(VBOX_E_FILE_ERROR, - tr("The SHA1 digest of '%s' does not match the one in '%s' (%Rrc)"), + tr("The SHA digest of '%s' does not match the one in '%s' (%Rrc)"), RTPathFilename(paTests[iFailed].pszTestFile), RTPathFilename(strFile.c_str()), vrc); else if (RT_FAILURE(vrc)) rc = setError(VBOX_E_FILE_ERROR, @@ -1677,7 +2107,6 @@ HRESULT Appliance::verifyManifestFile(const Utf8Str &strFile, ImportStack &stack return rc; } - /** * Helper that converts VirtualSystem attachment values into VirtualBox attachment values. * Throws HRESULT values on errors! @@ -1694,7 +2123,10 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc, int32_t &lControllerPort, int32_t &lDevice) { - Log(("Appliance::convertDiskAttachmentValues: hdc.system=%d, hdc.fPrimary=%d, ulAddressOnParent=%d\n", hdc.system, hdc.fPrimary, ulAddressOnParent)); + Log(("Appliance::convertDiskAttachmentValues: hdc.system=%d, hdc.fPrimary=%d, ulAddressOnParent=%d\n", + hdc.system, + hdc.fPrimary, + ulAddressOnParent)); switch (hdc.system) { @@ -1790,31 +2222,57 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc, * This advances stack.pProgress by one operation with the disk's weight. * * @param di ovfreader.cpp structure describing the disk image from the OVF that is to be imported - * @param ulSizeMB Size of the disk image (for progress reporting) * @param strTargetPath Where to create the target image. * @param pTargetHD out: The newly created target disk. This also gets pushed on stack.llHardDisksCreated for cleanup. * @param stack */ void Appliance::importOneDiskImage(const ovf::DiskImage &di, - const Utf8Str &strTargetPath, + Utf8Str *strTargetPath, ComObjPtr &pTargetHD, ImportStack &stack, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage) { + SHASTORAGE finalStorage; + PSHASTORAGE pRealUsedStorage = pStorage;/* may be changed later to finalStorage */ + PVDINTERFACEIO pFileIo = NULL;/* used in GZIP case*/ ComObjPtr pProgress; pProgress.createObject(); - HRESULT rc = pProgress->init(mVirtualBox, static_cast(this), BstrFmt(tr("Creating medium '%s'"), strTargetPath.c_str()).raw(), TRUE); + HRESULT rc = pProgress->init(mVirtualBox, + static_cast(this), + BstrFmt(tr("Creating medium '%s'"), + strTargetPath->c_str()).raw(), + TRUE); if (FAILED(rc)) throw rc; /* Get the system properties. */ SystemProperties *pSysProps = mVirtualBox->getSystemProperties(); + /* + * we put strSourceOVF into the stack.llSrcDisksDigest in the end of this + * function like a key for a later validation of the SHA digests + */ + const Utf8Str &strSourceOVF = di.strHref; + + Utf8Str strSrcFilePath(stack.strSourceDir); + Utf8Str strTargetDir(*strTargetPath); + + /* Construct source file path */ + Utf8Str name = applianceIOName(applianceIOTar); + + if (RTStrNICmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0) + strSrcFilePath = strSourceOVF; + else + { + strSrcFilePath.append(RTPATH_SLASH_STR); + strSrcFilePath.append(strSourceOVF); + } + /* First of all check if the path is an UUID. If so, the user like to * import the disk into an existing path. This is useful for iSCSI for * example. */ RTUUID uuid; - int vrc = RTUuidFromStr(&uuid, strTargetPath.c_str()); + int vrc = RTUuidFromStr(&uuid, strTargetPath->c_str()); if (vrc == VINF_SUCCESS) { rc = mVirtualBox->findHardDiskById(Guid(uuid), true, &pTargetHD); @@ -1822,102 +2280,248 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di, } else { - Utf8Str strTrgFormat = "VMDK"; - if (RTPathHaveExt(strTargetPath.c_str())) + bool fGzipUsed = !(di.strCompression.compare("gzip",Utf8Str::CaseInsensitive)); + /* check read file to GZIP compression */ + try { - char *pszExt = RTPathExt(strTargetPath.c_str()); - /* Figure out which format the user like to have. Default is VMDK. */ - ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]); - if (trgFormat.isNull()) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Could not find a valid medium format for the target disk '%s'"), - strTargetPath.c_str()); - /* Check the capabilities. We need create capabilities. */ + if (fGzipUsed == true) + { + /* + * Create the necessary file access interfaces. + * For the next step: + * We need to replace the previously created chain of SHA-TAR or SHA-FILE interfaces + * with simple FILE interface because we don't need SHA or TAR interfaces here anymore. + * But we mustn't delete the chain of SHA-TAR or SHA-FILE interfaces. + */ + + /* Decompress the GZIP file and save a new file in the target path */ + strTargetDir = strTargetDir.stripFilename(); + strTargetDir.append("/temp_"); + + Utf8Str strTempTargetFilename(*strTargetPath); + strTempTargetFilename = strTempTargetFilename.stripPath(); + strTempTargetFilename = strTempTargetFilename.stripExt(); + Utf8Str vdf = typeOfVirtualDiskFormatFromURI(di.strFormat); + + strTargetDir.append(strTempTargetFilename); + + vrc = decompressImageAndSave(strSrcFilePath.c_str(), strTargetDir.c_str(), pCallbacks, pStorage); + + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("Could not read the file '%s' (%Rrc)"), + RTPathFilename(strSrcFilePath.c_str()), vrc); + + /* Create the necessary file access interfaces. */ + pFileIo = FileCreateInterface(); + if (!pFileIo) + throw setError(E_OUTOFMEMORY); + + name = applianceIOName(applianceIOFile); + + vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(), + VDINTERFACETYPE_IO, NULL, sizeof(VDINTERFACEIO), + &finalStorage.pVDImageIfaces); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_IPRT_ERROR, + tr("Creation of the VD interface failed (%Rrc)"), vrc); + + /* Correct the source and the target with the actual values */ + strSrcFilePath = strTargetDir; + strTargetDir = strTargetDir.stripFilename(); + strTargetDir.append(RTPATH_SLASH_STR); + strTargetDir.append(strTempTargetFilename.c_str()); + *strTargetPath = strTargetDir.c_str(); + + pRealUsedStorage = &finalStorage; + } + + Utf8Str strTrgFormat = "VMDK"; ULONG lCabs = 0; - rc = trgFormat->COMGETTER(Capabilities)(&lCabs); - if (FAILED(rc)) throw rc; - if (!( ((lCabs & MediumFormatCapabilities_CreateFixed) == MediumFormatCapabilities_CreateFixed) - || ((lCabs & MediumFormatCapabilities_CreateDynamic) == MediumFormatCapabilities_CreateDynamic))) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Could not find a valid medium format for the target disk '%s'"), - strTargetPath.c_str()); - Bstr bstrFormatName; - rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); - if (FAILED(rc)) throw rc; - strTrgFormat = Utf8Str(bstrFormatName); - } + char *pszExt = NULL; - /* Create an IMedium object. */ - pTargetHD.createObject(); - rc = pTargetHD->init(mVirtualBox, - strTrgFormat, - strTargetPath, - Guid::Empty /* media registry: none yet */); - if (FAILED(rc)) throw rc; + if (RTPathHaveExt(strTargetPath->c_str())) + { + pszExt = RTPathExt(strTargetPath->c_str()); + /* Figure out which format the user like to have. Default is VMDK. */ + ComObjPtr trgFormat = pSysProps->mediumFormatFromExtension(&pszExt[1]); + if (trgFormat.isNull()) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Could not find a valid medium format for the target disk '%s'"), + strTargetPath->c_str()); + /* Check the capabilities. We need create capabilities. */ + lCabs = 0; + com::SafeArray mediumFormatCap; + rc = trgFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); + + if (FAILED(rc)) + throw rc; + else + { + for (ULONG j = 0; j < mediumFormatCap.size(); j++) + lCabs |= mediumFormatCap[j]; + } - /* Now create an empty hard disk. */ - rc = mVirtualBox->CreateHardDisk(NULL, - Bstr(strTargetPath).raw(), - ComPtr(pTargetHD).asOutParam()); - if (FAILED(rc)) throw rc; - } + if (!( ((lCabs & MediumFormatCapabilities_CreateFixed) == MediumFormatCapabilities_CreateFixed) + || ((lCabs & MediumFormatCapabilities_CreateDynamic) == MediumFormatCapabilities_CreateDynamic))) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Could not find a valid medium format for the target disk '%s'"), + strTargetPath->c_str()); + Bstr bstrFormatName; + rc = trgFormat->COMGETTER(Name)(bstrFormatName.asOutParam()); + if (FAILED(rc)) throw rc; + strTrgFormat = Utf8Str(bstrFormatName); + } + else + { + throw setError(VBOX_E_FILE_ERROR, + tr("The target disk '%s' has no extension "), + strTargetPath->c_str(), VERR_INVALID_NAME); + } - const Utf8Str &strSourceOVF = di.strHref; - /* Construct source file path */ - Utf8StrFmt strSrcFilePath("%s%c%s", stack.strSourceDir.c_str(), RTPATH_DELIMITER, strSourceOVF.c_str()); + /* Create an IMedium object. */ + pTargetHD.createObject(); - /* If strHref is empty we have to create a new file. */ - if (strSourceOVF.isEmpty()) - { - /* Create a dynamic growing disk image with the given capacity. */ - rc = pTargetHD->CreateBaseStorage(di.iCapacity / _1M, MediumVariant_Standard, ComPtr(pProgress).asOutParam()); - if (FAILED(rc)) throw rc; + /*CD/DVD case*/ + if (strTrgFormat.compare("RAW", Utf8Str::CaseInsensitive) == 0) + { + try + { + if (fGzipUsed == true) + { + /* + * The source and target pathes are the same. + * It means that we have the needed file already. + * For example, in GZIP case, we decompress the file and save it in the target path, + * but with some prefix like "temp_". See part "check read file to GZIP compression" earlier + * in this function. + * Just rename the file by deleting "temp_" from it's name + */ + vrc = RTFileRename(strSrcFilePath.c_str(), strTargetPath->c_str(), RTPATHRENAME_FLAGS_NO_REPLACE); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("Could not rename the file '%s' (%Rrc)"), + RTPathFilename(strSourceOVF.c_str()), vrc); + } + else + { + /* Calculating SHA digest for ISO file while copying one */ + vrc = copyFileAndCalcShaDigest(strSrcFilePath.c_str(), + strTargetPath->c_str(), + pCallbacks, + pRealUsedStorage); + + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("Could not copy ISO file '%s' listed in the OVF file (%Rrc)"), + RTPathFilename(strSourceOVF.c_str()), vrc); + } + } + catch (HRESULT /*arc*/) + { + throw; + } - /* Advance to the next operation. */ - stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"), strTargetPath.c_str()).raw(), - di.ulSuggestedSizeMB); // operation's weight, as set up with the IProgress originally - } - else - { - /* We need a proper source format description */ - ComObjPtr srcFormat; - /* Which format to use? */ - Utf8Str strSrcFormat = "VDI"; - if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive) - || di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive) - ) - strSrcFormat = "VMDK"; - srcFormat = pSysProps->mediumFormat(strSrcFormat); - if (srcFormat.isNull()) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Could not find a valid medium format for the source disk '%s'"), - RTPathFilename(strSrcFilePath.c_str())); - - /* Clone the source disk image */ - ComObjPtr nullParent; - rc = pTargetHD->importFile(strSrcFilePath.c_str(), - srcFormat, - MediumVariant_Standard, - pCallbacks, pStorage, - nullParent, - pProgress); - if (FAILED(rc)) throw rc; + /* Advance to the next operation. */ + /* operation's weight, as set up with the IProgress originally */ + stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), + RTPathFilename(strSourceOVF.c_str())).raw(), + di.ulSuggestedSizeMB); + } + else/* HDD case*/ + { + rc = pTargetHD->init(mVirtualBox, + strTrgFormat, + *strTargetPath, + Guid::Empty /* media registry: none yet */); + if (FAILED(rc)) throw rc; - /* Advance to the next operation. */ - stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), RTPathFilename(strSrcFilePath.c_str())).raw(), - di.ulSuggestedSizeMB); // operation's weight, as set up with the IProgress originally); + /* Now create an empty hard disk. */ + rc = mVirtualBox->CreateHardDisk(Bstr(strTrgFormat).raw(), + Bstr(*strTargetPath).raw(), + ComPtr(pTargetHD).asOutParam()); + if (FAILED(rc)) throw rc; + + /* If strHref is empty we have to create a new file. */ + if (strSourceOVF.isEmpty()) + { + com::SafeArray mediumVariant; + mediumVariant.push_back(MediumVariant_Standard); + /* Create a dynamic growing disk image with the given capacity. */ + rc = pTargetHD->CreateBaseStorage(di.iCapacity / _1M, + ComSafeArrayAsInParam(mediumVariant), + ComPtr(pProgress).asOutParam()); + if (FAILED(rc)) throw rc; + + /* Advance to the next operation. */ + /* operation's weight, as set up with the IProgress originally */ + stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"), + strTargetPath->c_str()).raw(), + di.ulSuggestedSizeMB); + } + else + { + /* We need a proper source format description */ + /* Which format to use? */ + Utf8Str strSrcFormat = typeOfVirtualDiskFormatFromURI(di.strFormat); + + ComObjPtr srcFormat = pSysProps->mediumFormat(strSrcFormat); + if (srcFormat.isNull()) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Could not find a valid medium format for the source disk '%s' " + "Check correctness of the image format URL in the OVF description file."), + RTPathFilename(strSourceOVF.c_str())); + + /* Clone the source disk image */ + ComObjPtr nullParent; + rc = pTargetHD->importFile(strSrcFilePath.c_str(), + srcFormat, + MediumVariant_Standard, + pCallbacks, pRealUsedStorage, + nullParent, + pProgress); + if (FAILED(rc)) throw rc; + + /* Advance to the next operation. */ + /* operation's weight, as set up with the IProgress originally */ + stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), + RTPathFilename(strSourceOVF.c_str())).raw(), + di.ulSuggestedSizeMB); + } + + /* Now wait for the background disk operation to complete; this throws + * HRESULTs on error. */ + ComPtr pp(pProgress); + waitForAsyncProgress(stack.pProgress, pp); + + if (fGzipUsed == true) + { + /* + * Just delete the temporary file + */ + vrc = RTFileDelete(strSrcFilePath.c_str()); + if (RT_FAILURE(vrc)) + setWarning(VBOX_E_FILE_ERROR, + tr("Could not delete the file '%s' (%Rrc)"), + RTPathFilename(strSrcFilePath.c_str()), vrc); + } + } + } + catch (...) + { + if (pFileIo) + RTMemFree(pFileIo); + + throw; + } } - /* Now wait for the background disk operation to complete; this throws - * HRESULTs on error. */ - ComPtr pp(pProgress); - waitForAsyncProgress(stack.pProgress, pp); + if (pFileIo) + RTMemFree(pFileIo); /* Add the newly create disk path + a corresponding digest the our list for * later manifest verification. */ - stack.llSrcDisksDigest.push_back(STRPAIR(strSrcFilePath, pStorage ? pStorage->strDigest : "")); + stack.llSrcDisksDigest.push_back(STRPAIR(strSourceOVF, pStorage ? pStorage->strDigest : "")); } /** @@ -1940,6 +2544,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage) { + LogFlowFuncEnter(); HRESULT rc; // Get the instance of IGuestOSType which matches our string guest OS type so we @@ -2027,11 +2632,12 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, #ifdef VBOX_WITH_USB /* USB Controller */ - ComPtr usbController; - rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam()); - if (FAILED(rc)) throw rc; - rc = usbController->COMSETTER(Enabled)(stack.fUSBEnabled); - if (FAILED(rc)) throw rc; + if (stack.fUSBEnabled) + { + ComPtr usbController; + rc = pNewMachine->AddUSBController(Bstr("OHCI").raw(), USBControllerType_OHCI, usbController.asOutParam()); + if (FAILED(rc)) throw rc; + } #endif /* VBOX_WITH_USB */ /* Change the network adapters */ @@ -2049,7 +2655,8 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, } else if (vsdeNW.size() > maxNetworkAdapters) throw setError(VBOX_E_FILE_ERROR, - tr("Too many network adapters: OVF requests %d network adapters, but VirtualBox only supports %d"), + tr("Too many network adapters: OVF requests %d network adapters, " + "but VirtualBox only supports %d"), vsdeNW.size(), maxNetworkAdapters); else { @@ -2061,7 +2668,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, { const VirtualSystemDescriptionEntry* pvsys = *nwIt; - const Utf8Str &nwTypeVBox = pvsys->strVboxCurrent; + const Utf8Str &nwTypeVBox = pvsys->strVBoxCurrent; uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str()); ComPtr pNetworkAdapter; rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam()); @@ -2099,7 +2706,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam()); if (FAILED(rc)) throw rc; /* Set the interface name to attach to */ - pNetworkAdapter->COMSETTER(BridgedInterface)(name.raw()); + rc = pNetworkAdapter->COMSETTER(BridgedInterface)(name.raw()); if (FAILED(rc)) throw rc; break; } @@ -2132,7 +2739,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam()); if (FAILED(rc)) throw rc; /* Set the interface name to attach to */ - pNetworkAdapter->COMSETTER(HostOnlyInterface)(name.raw()); + rc = pNetworkAdapter->COMSETTER(HostOnlyInterface)(name.raw()); if (FAILED(rc)) throw rc; break; } @@ -2152,13 +2759,37 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = pNetworkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_Generic); if (FAILED(rc)) throw rc; } + /* Next test for NAT network interfaces */ + else if (pvsys->strExtraConfigCurrent.endsWith("type=NATNetwork", Utf8Str::CaseInsensitive)) + { + /* Attach to the right interface */ + rc = pNetworkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork); + if (FAILED(rc)) throw rc; + com::SafeIfaceArray nwNATNetworks; + rc = mVirtualBox->COMGETTER(NATNetworks)(ComSafeArrayAsOutParam(nwNATNetworks)); + if (FAILED(rc)) throw rc; + // Pick the first NAT network (if there is any) + if (nwNATNetworks.size()) + { + Bstr name; + rc = nwNATNetworks[0]->COMGETTER(NetworkName)(name.asOutParam()); + if (FAILED(rc)) throw rc; + /* Set the NAT network name to attach to */ + rc = pNetworkAdapter->COMSETTER(NATNetwork)(name.raw()); + if (FAILED(rc)) throw rc; + break; + } + } } } // IDE Hard disk controller std::list vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE); - // In OVF (at least VMware's version of it), an IDE controller has two ports, so VirtualBox's single IDE controller - // with two channels and two ports each counts as two OVF IDE controllers -- so we accept one or two such IDE controllers + /* + * In OVF (at least VMware's version of it), an IDE controller has two ports, + * so VirtualBox's single IDE controller with two channels and two ports each counts as + * two OVF IDE controllers -- so we accept one or two such IDE controllers + */ size_t cIDEControllers = vsdeHDCIDE.size(); if (cIDEControllers > 2) throw setError(VBOX_E_FILE_ERROR, @@ -2170,7 +2801,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = pNewMachine->AddStorageController(Bstr("IDE Controller").raw(), StorageBus_IDE, pController.asOutParam()); if (FAILED(rc)) throw rc; - const char *pcszIDEType = vsdeHDCIDE.front()->strVboxCurrent.c_str(); + const char *pcszIDEType = vsdeHDCIDE.front()->strVBoxCurrent.c_str(); if (!strcmp(pcszIDEType, "PIIX3")) rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3); else if (!strcmp(pcszIDEType, "PIIX4")) @@ -2192,10 +2823,12 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (vsdeHDCSATA.size() > 0) { ComPtr pController; - const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVboxCurrent; + const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVBoxCurrent; if (hdcVBox == "AHCI") { - rc = pNewMachine->AddStorageController(Bstr("SATA Controller").raw(), StorageBus_SATA, pController.asOutParam()); + rc = pNewMachine->AddStorageController(Bstr("SATA Controller").raw(), + StorageBus_SATA, + pController.asOutParam()); if (FAILED(rc)) throw rc; } else @@ -2215,7 +2848,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, Bstr bstrName(L"SCSI Controller"); StorageBus_T busType = StorageBus_SCSI; StorageControllerType_T controllerType; - const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVboxCurrent; + const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVBoxCurrent; if (hdcVBox == "LsiLogic") controllerType = StorageControllerType_LsiLogic; else if (hdcVBox == "LsiLogicSas") @@ -2246,7 +2879,9 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (vsdeHDCSAS.size() > 0) { ComPtr pController; - rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller").raw(), StorageBus_SAS, pController.asOutParam()); + rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller").raw(), + StorageBus_SAS, + pController.asOutParam()); if (FAILED(rc)) throw rc; rc = pController->COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas); if (FAILED(rc)) throw rc; @@ -2291,7 +2926,9 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (vsdeFloppy.size() == 1) { ComPtr pController; - rc = sMachine->AddStorageController(Bstr("Floppy Controller").raw(), StorageBus_Floppy, pController.asOutParam()); + rc = sMachine->AddStorageController(Bstr("Floppy Controller").raw(), + StorageBus_Floppy, + pController.asOutParam()); if (FAILED(rc)) throw rc; Bstr bstrName; @@ -2317,54 +2954,6 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, stack.llHardDiskAttachments.push_back(mhda); } - // CD-ROMs next - for (std::list::const_iterator jt = vsdeCDROM.begin(); - jt != vsdeCDROM.end(); - ++jt) - { - // for now always attach to secondary master on IDE controller; - // there seems to be no useful information in OVF where else to - // attach it (@todo test with latest versions of OVF software) - - // find the IDE controller - const ovf::HardDiskController *pController = NULL; - for (ovf::ControllersMap::const_iterator kt = vsysThis.mapControllers.begin(); - kt != vsysThis.mapControllers.end(); - ++kt) - { - if (kt->second.system == ovf::HardDiskController::IDE) - { - pController = &kt->second; - break; - } - } - - if (!pController) - throw setError(VBOX_E_FILE_ERROR, - tr("OVF wants a CD-ROM drive but cannot find IDE controller, which is required in this version of VirtualBox")); - - // this is for rollback later - MyHardDiskAttachment mhda; - mhda.pMachine = pNewMachine; - - convertDiskAttachmentValues(*pController, - 2, // interpreted as secondary master - mhda.controllerType, // Bstr - mhda.lControllerPort, - mhda.lDevice); - - Log(("Attaching CD-ROM to port %d on device %d\n", mhda.lControllerPort, mhda.lDevice)); - - rc = sMachine->AttachDevice(mhda.controllerType.raw(), - mhda.lControllerPort, - mhda.lDevice, - DeviceType_DVD, - NULL); - if (FAILED(rc)) throw rc; - - stack.llHardDiskAttachments.push_back(mhda); - } // end for (itHD = avsdeHDs.begin(); - rc = sMachine->SaveSettings(); if (FAILED(rc)) throw rc; @@ -2373,12 +2962,17 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (FAILED(rc)) throw rc; stack.fSessionOpen = false; } - catch(HRESULT /* aRC */) + catch(HRESULT aRC) { + com::ErrorInfo info; + if (stack.fSessionOpen) stack.pSession->UnlockMachine(); - throw; + if (info.isFullAvailable()) + throw setError(aRC, Utf8Str(info.getText()).c_str()); + else + throw setError(aRC, "Unknown error during OVF import"); } } @@ -2390,37 +2984,190 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, // we need another try/catch block. try { +#ifdef LOG_ENABLED + if (LogIsEnabled()) + { + size_t i = 0; + for (list::const_iterator itHD = avsdeHDs.begin(); itHD != avsdeHDs.end(); ++itHD, i++) + Log(("avsdeHDs[%zu]: strRef=%s\n", i, (*itHD)->strRef.c_str())); + } +#endif + // to attach things we need to open a session for the new machine rc = pNewMachine->LockMachine(stack.pSession, LockType_Write); if (FAILED(rc)) throw rc; stack.fSessionOpen = true; - /* Iterate over all given disk images */ - list::const_iterator itHD; - for (itHD = avsdeHDs.begin(); - itHD != avsdeHDs.end(); - ++itHD) + /* get VM name from virtual system description. Only one record is possible (size of list is equal 1). */ + std::list vmName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); + std::list::iterator vmNameIt = vmName.begin(); + VirtualSystemDescriptionEntry* vmNameEntry = *vmNameIt; + + ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin(); + std::set disksResolvedNames; + + uint32_t cImportedDisks = 0; + + while(oit != stack.mapDisks.end() && cImportedDisks != avsdeHDs.size()) { - VirtualSystemDescriptionEntry *vsdeHD = *itHD; + ovf::DiskImage diCurrent = oit->second; + ovf::VirtualDisksMap::const_iterator itVDisk = vsysThis.mapVirtualDisks.begin(); + + VirtualSystemDescriptionEntry *vsdeTargetHD = 0; + Log(("diCurrent.strDiskId=%s\n", diCurrent.strDiskId.c_str())); + + /* + * + * Iterate over all given disk images of the virtual system + * disks description. We need to find the target disk path, + * which could be changed by the user. + * + */ + { + list::const_iterator itHD; + for (itHD = avsdeHDs.begin(); + itHD != avsdeHDs.end(); + ++itHD) + { + VirtualSystemDescriptionEntry *vsdeHD = *itHD; + if (vsdeHD->strRef == diCurrent.strDiskId) + { + vsdeTargetHD = vsdeHD; + break; + } + } + if (!vsdeTargetHD) + { + /* possible case if a disk image belongs to other virtual system (OVF package with multiple VMs inside) */ + LogWarning(("OVA/OVF import: Disk image %s was missed during import of VM %s\n", + oit->first.c_str(), vmNameEntry->strOvf.c_str())); + ++oit; + continue; + } + + //diCurrent.strDiskId contains the disk identifier (e.g. "vmdisk1"), which should exist + //in the virtual system's disks map under that ID and also in the global images map + itVDisk = vsysThis.mapVirtualDisks.find(diCurrent.strDiskId); + if (itVDisk == vsysThis.mapVirtualDisks.end()) + throw setError(E_FAIL, + tr("Internal inconsistency looking up disk image '%s'"), + diCurrent.strHref.c_str()); + } + + /* + * preliminary check availability of the image + * This step is useful if image is placed in the OVA (TAR) package + */ + + Utf8Str name = applianceIOName(applianceIOTar); + + if (strncmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0) + { + /* It means that we possibly have imported the storage earlier on the previous loop steps*/ + std::set::const_iterator h = disksResolvedNames.find(diCurrent.strHref); + if (h != disksResolvedNames.end()) + { + /* Yes, disk name was found, we can skip it*/ + ++oit; + continue; + } + + RTCString availableImage(diCurrent.strHref); + + rc = preCheckImageAvailability(pStorage, + availableImage + ); + + if (SUCCEEDED(rc)) + { + /* current opened file isn't the same as passed one */ + if(availableImage.compare(diCurrent.strHref, Utf8Str::CaseInsensitive) != 0) + { + /* + * availableImage contains the disk file reference (e.g. "disk1.vmdk"), which should exist + * in the global images map. + * And find the disk from the OVF's disk list + * + */ + { + ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.begin(); + while (++itDiskImage != stack.mapDisks.end()) + { + if (itDiskImage->second.strHref.compare(availableImage, Utf8Str::CaseInsensitive) == 0) + break; + } + if (itDiskImage == stack.mapDisks.end()) + throw setError(E_FAIL, + tr("Internal inconsistency looking up disk image '%s'. " + "Check compliance OVA package structure and file names " + "references in the section in the OVF file"), + availableImage.c_str()); + + /* replace with a new found disk image */ + diCurrent = *(&itDiskImage->second); + } + + /* + * Again iterate over all given disk images of the virtual system + * disks description using the found disk image + */ + { + list::const_iterator itHD; + for (itHD = avsdeHDs.begin(); + itHD != avsdeHDs.end(); + ++itHD) + { + VirtualSystemDescriptionEntry *vsdeHD = *itHD; + if (vsdeHD->strRef == diCurrent.strDiskId) + { + vsdeTargetHD = vsdeHD; + break; + } + } + if (!vsdeTargetHD) + /* + * in this case it's an error because something wrong with OVF description file. + * May be VBox imports OVA package with wrong file sequence inside the archive. + */ + throw setError(E_FAIL, + tr("Internal inconsistency looking up disk image '%s'"), + diCurrent.strHref.c_str()); + + itVDisk = vsysThis.mapVirtualDisks.find(diCurrent.strDiskId); + if (itVDisk == vsysThis.mapVirtualDisks.end()) + throw setError(E_FAIL, + tr("Internal inconsistency looking up disk image '%s'"), + diCurrent.strHref.c_str()); + } + } + else + { + ++oit; + } + } + else + { + ++oit; + continue; + } + } + else + { + /* just continue with normal files*/ + ++oit; + } + + const ovf::VirtualDisk &ovfVdisk = itVDisk->second; - // vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist - // in the virtual system's disks map under that ID and also in the global images map - ovf::VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef); - // and find the disk from the OVF's disk list - ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef); - if ( (itVirtualDisk == vsysThis.mapVirtualDisks.end()) - || (itDiskImage == stack.mapDisks.end()) - ) - throw setError(E_FAIL, - tr("Internal inconsistency looking up disk image '%s'"), - vsdeHD->strRef.c_str()); - - const ovf::DiskImage &ovfDiskImage = itDiskImage->second; - const ovf::VirtualDisk &ovfVdisk = itVirtualDisk->second; + /* very important to store disk name for the next checks */ + disksResolvedNames.insert(diCurrent.strHref); ComObjPtr pTargetHD; - importOneDiskImage(ovfDiskImage, - vsdeHD->strVboxCurrent, + + Utf8Str savedVBoxCurrent = vsdeTargetHD->strVBoxCurrent; + + importOneDiskImage(diCurrent, + &vsdeTargetHD->strVBoxCurrent, pTargetHD, stack, pCallbacks, @@ -2429,7 +3176,8 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, // now use the new uuid to attach the disk image to our new machine ComPtr sMachine; rc = stack.pSession->COMGETTER(Machine)(sMachine.asOutParam()); - if (FAILED(rc)) throw rc; + if (FAILED(rc)) + throw rc; // find the hard disk controller to which we should attach ovf::HardDiskController hdc = (*vsysThis.mapControllers.find(ovfVdisk.idController)).second; @@ -2444,34 +3192,88 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, mhda.lControllerPort, mhda.lDevice); - Log(("Attaching disk %s to port %d on device %d\n", vsdeHD->strVboxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice)); + Log(("Attaching disk %s to port %d on device %d\n", + vsdeTargetHD->strVBoxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice)); - rc = sMachine->AttachDevice(mhda.controllerType.raw(), // wstring name - mhda.lControllerPort, // long controllerPort - mhda.lDevice, // long device - DeviceType_HardDisk, // DeviceType_T type - pTargetHD); - if (FAILED(rc)) throw rc; + Utf8Str vdf = typeOfVirtualDiskFormatFromURI(diCurrent.strFormat); + + if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0) + { + ComPtr dvdImage(pTargetHD); + + rc = mVirtualBox->OpenMedium(Bstr(vsdeTargetHD->strVBoxCurrent).raw(), + DeviceType_DVD, + AccessMode_ReadWrite, + false, + dvdImage.asOutParam()); + + if (FAILED(rc)) + throw rc; + + rc = sMachine->AttachDevice(mhda.controllerType.raw(),// wstring name + mhda.lControllerPort, // long controllerPort + mhda.lDevice, // long device + DeviceType_DVD, // DeviceType_T type + dvdImage); + if (FAILED(rc)) + throw rc; + } + else + { + rc = sMachine->AttachDevice(mhda.controllerType.raw(),// wstring name + mhda.lControllerPort, // long controllerPort + mhda.lDevice, // long device + DeviceType_HardDisk, // DeviceType_T type + pTargetHD); + + if (FAILED(rc)) + throw rc; + } stack.llHardDiskAttachments.push_back(mhda); rc = sMachine->SaveSettings(); - if (FAILED(rc)) throw rc; - } // end for (itHD = avsdeHDs.begin(); + if (FAILED(rc)) + throw rc; + + /* restore */ + vsdeTargetHD->strVBoxCurrent = savedVBoxCurrent; + + ++cImportedDisks; + + } // end while(oit != stack.mapDisks.end()) + + /* + * quantity of the imported disks isn't equal to the size of the avsdeHDs list. + */ + if(cImportedDisks < avsdeHDs.size()) + { + LogWarning(("Not all disk images were imported for VM %s. Check OVF description file.", + vmNameEntry->strOvf.c_str())); + } // only now that we're done with all disks, close the session rc = stack.pSession->UnlockMachine(); - if (FAILED(rc)) throw rc; + + if (FAILED(rc)) + throw rc; + stack.fSessionOpen = false; } - catch(HRESULT /* aRC */) + catch(HRESULT aRC) { + com::ErrorInfo info; + if (stack.fSessionOpen) stack.pSession->UnlockMachine(); - throw; + if (info.isFullAvailable()) + throw setError(aRC, Utf8Str(info.getText()).c_str()); + else + throw setError(aRC, "Unknown error during OVF import"); } } + LogFlowFuncLeave(); } /** @@ -2509,6 +3311,7 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage) { + LogFlowFuncEnter(); Assert(vsdescThis->m->pConfig); HRESULT rc = S_OK; @@ -2516,10 +3319,8 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi settings::MachineConfigFile &config = *vsdescThis->m->pConfig; /* - * * step 1): modify machine config according to OVF config, in case the user * has modified them using setFinalValues() - * */ /* OS Type */ @@ -2544,7 +3345,34 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi #ifdef VBOX_WITH_USB /* USB controller */ - config.hardwareMachine.usbController.fEnabled = stack.fUSBEnabled; + if (stack.fUSBEnabled) + { + /** @todo r=klaus add support for arbitrary USB controller types, this can't handle multiple controllers due to its design anyway */ + + /* usually the OHCI controller is enabled already, need to check */ + bool fOHCIEnabled = false; + settings::USBControllerList &llUSBControllers = config.hardwareMachine.usbSettings.llUSBControllers; + settings::USBControllerList::iterator it; + for (it = llUSBControllers.begin(); it != llUSBControllers.end(); ++it) + { + if (it->enmType == USBControllerType_OHCI) + { + fOHCIEnabled = true; + break; + } + } + + if (!fOHCIEnabled) + { + settings::USBController ctrl; + ctrl.strName = "OHCI"; + ctrl.enmType = USBControllerType_OHCI; + + llUSBControllers.push_back(ctrl); + } + } + else + config.hardwareMachine.usbSettings.llUSBControllers.clear(); #endif /* Audio adapter */ if (stack.strAudioAdapter.isNotEmpty()) @@ -2558,13 +3386,14 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi settings::NetworkAdaptersList &llNetworkAdapters = config.hardwareMachine.llNetworkAdapters; /* First disable all network cards, they will be enabled below again. */ settings::NetworkAdaptersList::iterator it1; - bool fKeepAllMACs = m->optList.contains(ImportOptions_KeepAllMACs); - bool fKeepNATMACs = m->optList.contains(ImportOptions_KeepNATMACs); + bool fKeepAllMACs = m->optListImport.contains(ImportOptions_KeepAllMACs); + bool fKeepNATMACs = m->optListImport.contains(ImportOptions_KeepNATMACs); for (it1 = llNetworkAdapters.begin(); it1 != llNetworkAdapters.end(); ++it1) { it1->fEnabled = false; if (!( fKeepAllMACs - || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NAT))) + || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NAT) + || (fKeepNATMACs && it1->mode == NetworkAttachmentType_NATNetwork))) Host::generateMACAddress(it1->strMACAddress); } /* Now iterate over all network entries. */ @@ -2593,7 +3422,7 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi if (it1->ulSlot == iSlot) { it1->fEnabled = true; - it1->type = (NetworkAdapterType_T)vsdeNW->strVboxCurrent.toUInt32(); + it1->type = (NetworkAdapterType_T)vsdeNW->strVBoxCurrent.toUInt32(); break; } } @@ -2612,7 +3441,7 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi * failures. A long fixed bug, however the OVF files are long lived. */ settings::StorageControllersList &llControllers = config.storageMachine.llStorageControllers; Guid hdUuid; - uint32_t cHardDisks = 0; + uint32_t cDisks = 0; bool fInconsistent = false; bool fRepairDuplicate = false; settings::StorageControllersList::iterator it3; @@ -2636,17 +3465,17 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi else if (it4->deviceType == DeviceType_HardDisk) { const Guid &thisUuid = it4->uuid; - cHardDisks++; - if (cHardDisks == 1) + cDisks++; + if (cDisks == 1) { - if (hdUuid.isEmpty()) + if (hdUuid.isZero()) hdUuid = thisUuid; else fInconsistent = true; } else { - if (thisUuid.isEmpty()) + if (thisUuid.isZero()) fInconsistent = true; else if (thisUuid == hdUuid) fRepairDuplicate = true; @@ -2656,141 +3485,290 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi } } /* paranoia... */ - if (fInconsistent || cHardDisks == 1) + if (fInconsistent || cDisks == 1) fRepairDuplicate = false; /* - * * step 2: scan the machine config for media attachments - * */ + /* get VM name from virtual system description. Only one record is possible (size of list is equal 1). */ + std::list vmName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); + std::list::iterator vmNameIt = vmName.begin(); + VirtualSystemDescriptionEntry* vmNameEntry = *vmNameIt; + /* Get all hard disk descriptions. */ std::list avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage); std::list::iterator avsdeHDsIt = avsdeHDs.begin(); /* paranoia - if there is no 1:1 match do not try to repair. */ - if (cHardDisks != avsdeHDs.size()) + if (cDisks != avsdeHDs.size()) fRepairDuplicate = false; - // for each storage controller... - for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin(); - sit != config.storageMachine.llStorageControllers.end(); - ++sit) - { - settings::StorageController &sc = *sit; + // there must be an image in the OVF disk structs with the same UUID - // find the OVF virtual system description entry for this storage controller - switch (sc.storageBus) - { - case StorageBus_SATA: - break; - case StorageBus_SCSI: - break; - case StorageBus_IDE: - break; - case StorageBus_SAS: - break; - } + ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin(); + std::set disksResolvedNames; - // for each medium attachment to this controller... - for (settings::AttachedDevicesList::iterator dit = sc.llAttachedDevices.begin(); - dit != sc.llAttachedDevices.end(); - ++dit) - { - settings::AttachedDevice &d = *dit; + uint32_t cImportedDisks = 0; - if (d.uuid.isEmpty()) - // empty DVD and floppy media - continue; + while(oit != stack.mapDisks.end() && cImportedDisks != avsdeHDs.size()) + { + ovf::DiskImage diCurrent = oit->second; + + VirtualSystemDescriptionEntry *vsdeTargetHD = 0; - // When repairing a broken VirtualBox xml config section (written - // by VirtualBox versions earlier than 3.2.10) assume the disks - // show up in the same order as in the OVF description. - if (fRepairDuplicate) + { + /* Iterate over all given disk images of the virtual system + * disks description. We need to find the target disk path, + * which could be changed by the user. */ + list::const_iterator itHD; + for (itHD = avsdeHDs.begin(); + itHD != avsdeHDs.end(); + ++itHD) { - VirtualSystemDescriptionEntry *vsdeHD = *avsdeHDsIt; - ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef); - if (itDiskImage != stack.mapDisks.end()) + VirtualSystemDescriptionEntry *vsdeHD = *itHD; + if (vsdeHD->strRef == oit->first) { - const ovf::DiskImage &di = itDiskImage->second; - d.uuid = Guid(di.uuidVbox); + vsdeTargetHD = vsdeHD; + break; } - ++avsdeHDsIt; } - // convert the Guid to string - Utf8Str strUuid = d.uuid.toString(); + if (!vsdeTargetHD) + { + /* possible case if a disk image belongs to other virtual system (OVF package with multiple VMs inside) */ + LogWarning(("OVA/OVF import: Disk image %s was missed during import of VM %s\n", + oit->first.c_str(), vmNameEntry->strOvf.c_str())); + ++oit; + continue; + } + } + + /* + * preliminary check availability of the image + * This step is useful if image is placed in the OVA (TAR) package + */ + + Utf8Str name = applianceIOName(applianceIOTar); - // there must be an image in the OVF disk structs with the same UUID - bool fFound = false; - for (ovf::DiskImagesMap::const_iterator oit = stack.mapDisks.begin(); - oit != stack.mapDisks.end(); - ++oit) + if (strncmp(pStorage->pVDImageIfaces->pszInterfaceName, name.c_str(), name.length()) == 0) + { + /* It means that we possibly have imported the storage earlier on the previous loop steps*/ + std::set::const_iterator h = disksResolvedNames.find(diCurrent.strHref); + if (h != disksResolvedNames.end()) { - const ovf::DiskImage &di = oit->second; + /* Yes, disk name was found, we can skip it*/ + ++oit; + continue; + } + + RTCString availableImage(diCurrent.strHref); + + rc = preCheckImageAvailability(pStorage, + availableImage + ); - if (di.uuidVbox == strUuid) + if (SUCCEEDED(rc)) + { + /* current opened file isn't the same as passed one */ + if(availableImage.compare(diCurrent.strHref, Utf8Str::CaseInsensitive) != 0) { - VirtualSystemDescriptionEntry *vsdeTargetHD = 0; + // availableImage contains the disk identifier (e.g. "vmdisk1"), which should exist + // in the virtual system's disks map under that ID and also in the global images map + // and find the disk from the OVF's disk list + ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.begin(); + while (++itDiskImage != stack.mapDisks.end()) + { + if(itDiskImage->second.strHref.compare(availableImage, Utf8Str::CaseInsensitive) == 0 ) + break; + } + if (itDiskImage == stack.mapDisks.end()) + { + throw setError(E_FAIL, + tr("Internal inconsistency looking up disk image '%s'. " + "Check compliance OVA package structure and file names " + "references in the section in the OVF file."), + availableImage.c_str()); + } + + /* replace with a new found disk image */ + diCurrent = *(&itDiskImage->second); - /* Iterate over all given disk images of the virtual system - * disks description. We need to find the target disk path, - * which could be changed by the user. */ + /* + * Again iterate over all given disk images of the virtual system + * disks description using the found disk image + */ list::const_iterator itHD; for (itHD = avsdeHDs.begin(); itHD != avsdeHDs.end(); ++itHD) { VirtualSystemDescriptionEntry *vsdeHD = *itHD; - if (vsdeHD->strRef == oit->first) + if (vsdeHD->strRef == diCurrent.strDiskId) { vsdeTargetHD = vsdeHD; break; } } if (!vsdeTargetHD) + /* + * in this case it's an error because something wrong with OVF description file. + * May be VBox imports OVA package with wrong file sequence inside the archive. + */ throw setError(E_FAIL, tr("Internal inconsistency looking up disk image '%s'"), - oit->first.c_str()); + diCurrent.strHref.c_str()); + } + else + { + ++oit; + } + } + else + { + ++oit; + continue; + } + } + else + { + /* just continue with normal files*/ + ++oit; + } - /* - * - * step 3: import disk - * - */ - ComObjPtr pTargetHD; - importOneDiskImage(di, - vsdeTargetHD->strVboxCurrent, - pTargetHD, - stack, - pCallbacks, - pStorage); + /* Important! to store disk name for the next checks */ + disksResolvedNames.insert(diCurrent.strHref); + + // there must be an image in the OVF disk structs with the same UUID + bool fFound = false; + Utf8Str strUuid; + + // for each storage controller... + for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin(); + sit != config.storageMachine.llStorageControllers.end(); + ++sit) + { + settings::StorageController &sc = *sit; + + // find the OVF virtual system description entry for this storage controller + switch (sc.storageBus) + { + case StorageBus_SATA: + break; + case StorageBus_SCSI: + break; + case StorageBus_IDE: + break; + case StorageBus_SAS: + break; + } + + // for each medium attachment to this controller... + for (settings::AttachedDevicesList::iterator dit = sc.llAttachedDevices.begin(); + dit != sc.llAttachedDevices.end(); + ++dit) + { + settings::AttachedDevice &d = *dit; + + if (d.uuid.isZero()) + // empty DVD and floppy media + continue; + + // When repairing a broken VirtualBox xml config section (written + // by VirtualBox versions earlier than 3.2.10) assume the disks + // show up in the same order as in the OVF description. + if (fRepairDuplicate) + { + VirtualSystemDescriptionEntry *vsdeHD = *avsdeHDsIt; + ovf::DiskImagesMap::const_iterator itDiskImage = stack.mapDisks.find(vsdeHD->strRef); + if (itDiskImage != stack.mapDisks.end()) + { + const ovf::DiskImage &di = itDiskImage->second; + d.uuid = Guid(di.uuidVBox); + } + ++avsdeHDsIt; + } + + // convert the Guid to string + strUuid = d.uuid.toString(); + + if (diCurrent.uuidVBox != strUuid) + { + continue; + } + + /* + * step 3: import disk + */ + Utf8Str savedVBoxCurrent = vsdeTargetHD->strVBoxCurrent; + ComObjPtr pTargetHD; + importOneDiskImage(diCurrent, + &vsdeTargetHD->strVBoxCurrent, + pTargetHD, + stack, + pCallbacks, + pStorage); + + Bstr hdId; + + Utf8Str vdf = typeOfVirtualDiskFormatFromURI(diCurrent.strFormat); + + if (vdf.compare("RAW", Utf8Str::CaseInsensitive) == 0) + { + ComPtr dvdImage(pTargetHD); + + rc = mVirtualBox->OpenMedium(Bstr(vsdeTargetHD->strVBoxCurrent).raw(), + DeviceType_DVD, + AccessMode_ReadWrite, + false, + dvdImage.asOutParam()); + + if (FAILED(rc)) throw rc; // ... and replace the old UUID in the machine config with the one of // the imported disk that was just created - Bstr hdId; + rc = dvdImage->COMGETTER(Id)(hdId.asOutParam()); + if (FAILED(rc)) throw rc; + } + else + { + // ... and replace the old UUID in the machine config with the one of + // the imported disk that was just created rc = pTargetHD->COMGETTER(Id)(hdId.asOutParam()); if (FAILED(rc)) throw rc; + } - d.uuid = hdId; + /* restore */ + vsdeTargetHD->strVBoxCurrent = savedVBoxCurrent; - fFound = true; - break; - } - } + d.uuid = hdId; + fFound = true; + break; + } // for (settings::AttachedDevicesList::const_iterator dit = sc.llAttachedDevices.begin(); + } // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin(); // no disk with such a UUID found: - if (!fFound) - throw setError(E_FAIL, - tr(" element in OVF contains a medium attachment for the disk image %s but the OVF describes no such image"), - strUuid.c_str()); - } // for (settings::AttachedDevicesList::const_iterator dit = sc.llAttachedDevices.begin(); - } // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin(); + if (!fFound) + throw setError(E_FAIL, + tr(" element in OVF contains a medium attachment for the disk image %s " + "but the OVF describes no such image"), + strUuid.c_str()); + + ++cImportedDisks; + + }// while(oit != stack.mapDisks.end()) + + /* + * quantity of the imported disks isn't equal to the size of the avsdeHDs list. + */ + if(cImportedDisks < avsdeHDs.size()) + { + LogWarning(("Not all disk images were imported for VM %s. Check OVF description file.", + vmNameEntry->strOvf.c_str())); + } /* - * * step 4): create the machine and have it import the config - * */ ComObjPtr pNewMachine; @@ -2800,8 +3778,8 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi // this magic constructor fills the new machine object with the MachineConfig // instance that we created from the vbox:Machine rc = pNewMachine->init(mVirtualBox, - stack.strNameVBox, // name from OVF preparations; can be suffixed to avoid duplicates, or changed by user - config); // the whole machine config + stack.strNameVBox,// name from OVF preparations; can be suffixed to avoid duplicates + config); // the whole machine config if (FAILED(rc)) throw rc; pReturnNewMachine = ComPtr(pNewMachine); @@ -2815,6 +3793,8 @@ void Appliance::importVBoxMachine(ComObjPtr &vsdescThi rc = pNewMachine->COMGETTER(Id)(bstrNewMachineId.asOutParam()); if (FAILED(rc)) throw rc; m->llGuidsMachinesCreated.push_back(Guid(bstrNewMachineId)); + + LogFlowFuncLeave(); } void Appliance::importMachines(ImportStack &stack, @@ -2824,9 +3804,14 @@ void Appliance::importMachines(ImportStack &stack, HRESULT rc = S_OK; // this is safe to access because this thread only gets started - // if pReader != NULL const ovf::OVFReader &reader = *m->pReader; + /* + * get the SHA digest version that was set in accordance with the value of attribute "xmlns:ovf" + * of the element in the OVF file during reading operation. See readFSImpl(). + */ + pStorage->fSha256 = m->fSha256; + // create a session for the machine + disks we manipulate below rc = stack.pSession.createInprocObject(CLSID_Session); if (FAILED(rc)) throw rc; @@ -2837,7 +3822,8 @@ void Appliance::importMachines(ImportStack &stack, size_t i = 0; for (it = reader.m_llVirtualSystems.begin(), it1 = m->virtualSystemDescriptions.begin(); - it != reader.m_llVirtualSystems.end(); + it != reader.m_llVirtualSystems.end(), + it1 != m->virtualSystemDescriptions.end(); ++it, ++it1, ++i) { const ovf::VirtualSystem &vsysThis = *it; @@ -2860,7 +3846,7 @@ void Appliance::importMachines(ImportStack &stack, if (vsdeName.size() < 1) throw setError(VBOX_E_FILE_ERROR, tr("Missing VM name")); - stack.strNameVBox = vsdeName.front()->strVboxCurrent; + stack.strNameVBox = vsdeName.front()->strVBoxCurrent; // have VirtualBox suggest where the filename would be placed so we can // put the disk images in the same directory @@ -2874,6 +3860,7 @@ void Appliance::importMachines(ImportStack &stack, // and determine the machine folder from that stack.strMachineFolder = bstrMachineFilename; stack.strMachineFolder.stripFilename(); + LogFunc(("i=%zu strName=%s bstrMachineFilename=%ls\n", i, stack.strNameVBox.c_str(), bstrMachineFilename.raw())); // guest OS type std::list vsdeOS; @@ -2881,14 +3868,14 @@ void Appliance::importMachines(ImportStack &stack, if (vsdeOS.size() < 1) throw setError(VBOX_E_FILE_ERROR, tr("Missing guest OS type")); - stack.strOsTypeVBox = vsdeOS.front()->strVboxCurrent; + stack.strOsTypeVBox = vsdeOS.front()->strVBoxCurrent; // CPU count std::list vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU); if (vsdeCPU.size() != 1) throw setError(VBOX_E_FILE_ERROR, tr("CPU count missing")); - stack.cCPUs = vsdeCPU.front()->strVboxCurrent.toUInt32(); + stack.cCPUs = vsdeCPU.front()->strVBoxCurrent.toUInt32(); // We need HWVirt & IO-APIC if more than one CPU is requested if (stack.cCPUs > 1) { @@ -2900,7 +3887,7 @@ void Appliance::importMachines(ImportStack &stack, std::list vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory); if (vsdeRAM.size() != 1) throw setError(VBOX_E_FILE_ERROR, tr("RAM size missing")); - stack.ulMemorySizeMB = (ULONG)vsdeRAM.front()->strVboxCurrent.toUInt64(); + stack.ulMemorySizeMB = (ULONG)vsdeRAM.front()->strVBoxCurrent.toUInt64(); #ifdef VBOX_WITH_USB // USB controller @@ -2913,12 +3900,12 @@ void Appliance::importMachines(ImportStack &stack, std::list vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard); /* @todo: we support one audio adapter only */ if (vsdeAudioAdapter.size() > 0) - stack.strAudioAdapter = vsdeAudioAdapter.front()->strVboxCurrent; + stack.strAudioAdapter = vsdeAudioAdapter.front()->strVBoxCurrent; // for the description of the new machine, always use the OVF entry, the user may have changed it in the import config std::list vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); if (vsdeDescription.size()) - stack.strDescription = vsdeDescription.front()->strVboxCurrent; + stack.strDescription = vsdeDescription.front()->strVBoxCurrent; // import vbox:machine or OVF now if (vsdescThis->m->pConfig) diff --git a/src/VBox/Main/src-server/AudioAdapterImpl.cpp b/src/VBox/Main/src-server/AudioAdapterImpl.cpp index 9b6dbf17..089359b2 100644 --- a/src/VBox/Main/src-server/AudioAdapterImpl.cpp +++ b/src/VBox/Main/src-server/AudioAdapterImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/BIOSSettingsImpl.cpp b/src/VBox/Main/src-server/BIOSSettingsImpl.cpp index bc40820b..1cc0a5e2 100644 --- a/src/VBox/Main/src-server/BIOSSettingsImpl.cpp +++ b/src/VBox/Main/src-server/BIOSSettingsImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -507,6 +507,23 @@ STDMETHODIMP BIOSSettings::COMSETTER(TimeOffset)(LONG64 offset) return S_OK; } +STDMETHODIMP BIOSSettings::COMGETTER(NonVolatileStorageFile)(BSTR *pbstrPath) +{ + CheckComArgOutPointerValid(pbstrPath); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + Bstr bstrEmpty(""); + hrc = bstrEmpty.cloneToEx(pbstrPath); + } + + return hrc; +} + + // IBIOSSettings methods ///////////////////////////////////////////////////////////////////////////// diff --git a/src/VBox/Main/src-server/BandwidthControlImpl.cpp b/src/VBox/Main/src-server/BandwidthControlImpl.cpp index 70e2d243..5235bb6b 100644 --- a/src/VBox/Main/src-server/BandwidthControlImpl.cpp +++ b/src/VBox/Main/src-server/BandwidthControlImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -25,6 +25,8 @@ #include "Logging.h" #include +#include +#include // defines ///////////////////////////////////////////////////////////////////////////// @@ -72,8 +74,6 @@ void BandwidthControl::FinalRelease() * * @returns COM result indicator. * @param aParent Pointer to our parent object. - * @param aName Name of the storage controller. - * @param aInstance Instance number of the storage controller. */ HRESULT BandwidthControl::init(Machine *aParent) { @@ -147,7 +147,7 @@ HRESULT BandwidthControl::init(Machine *aParent, } /** - * Initializes the storage controller object given another guest object + * Initializes the bandwidth control object given another guest object * (a kind of copy constructor). This object makes a private copy of data * of the original object passed as an argument. */ @@ -176,7 +176,7 @@ HRESULT BandwidthControl::initCopy(Machine *aParent, BandwidthControl *aThat) { ComObjPtr group; group.createObject(); - group->init(this, *it); + group->initCopy(this, *it); m->llBandwidthGroups->push_back(group); ++ it; } @@ -215,7 +215,7 @@ void BandwidthControl::copyFrom (BandwidthControl *aThat) AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS); AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS); - /* create private copies of all filters */ + /* create private copies of all bandwidth groups */ m->llBandwidthGroups.backup(); m->llBandwidthGroups->clear(); for (BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin(); @@ -285,7 +285,7 @@ void BandwidthControl::commit() { AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS); - /* Commit all changes to new controllers (this will reshare data with + /* Commit all changes to new groups (this will reshare data with * peers for those who have peers) */ BandwidthGroupList *newList = new BandwidthGroupList(); BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin(); @@ -313,7 +313,7 @@ void BandwidthControl::commit() ++it; } - /* uninit old peer's controllers that are left */ + /* uninit old peer's groups that are left */ it = m->pPeer->m->llBandwidthGroups->begin(); while (it != m->pPeer->m->llBandwidthGroups->end()) { @@ -321,7 +321,7 @@ void BandwidthControl::commit() ++it; } - /* attach new list of controllers to our peer */ + /* attach new list of groups to our peer */ m->pPeer->m->llBandwidthGroups.attach(newList); } else @@ -334,7 +334,7 @@ void BandwidthControl::commit() else { /* the list of groups itself is not changed, - * just commit changes to controllers themselves */ + * just commit changes to groups themselves */ commitBandwidthGroups = true; } @@ -379,10 +379,10 @@ void BandwidthControl::uninit() } /** - * Returns a storage controller object with the given name. + * Returns a bandwidth group object with the given name. * - * @param aName storage controller name to find - * @param aStorageController where to return the found storage controller + * @param aName bandwidth group name to find + * @param aBandwidthGroup where to return the found bandwidth group * @param aSetError true to set extended error info on failure */ HRESULT BandwidthControl::getBandwidthGroupByName(const Utf8Str &aName, diff --git a/src/VBox/Main/src-server/BandwidthGroupImpl.cpp b/src/VBox/Main/src-server/BandwidthGroupImpl.cpp index aef8f4c1..22ba0c1b 100644 --- a/src/VBox/Main/src-server/BandwidthGroupImpl.cpp +++ b/src/VBox/Main/src-server/BandwidthGroupImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -80,8 +80,9 @@ void BandwidthGroup::FinalRelease() * * @returns COM result indicator. * @param aParent Pointer to our parent object. - * @param aName Name of the storage controller. - * @param aInstance Instance number of the storage controller. + * @param aName Name of the bandwidth group. + * @param aType Type of the bandwidth group (net, disk). + * @param aMaxBytesPerSec Maximum bandwidth for the bandwidth group. */ HRESULT BandwidthGroup::init(BandwidthControl *aParent, const Utf8Str &aName, @@ -175,7 +176,7 @@ HRESULT BandwidthGroup::init(BandwidthControl *aParent, } /** - * Initializes the storage controller object given another guest object + * Initializes the bandwidth group object given another guest object * (a kind of copy constructor). This object makes a private copy of data * of the original object passed as an argument. */ diff --git a/src/VBox/Main/src-server/ClientToken.cpp b/src/VBox/Main/src-server/ClientToken.cpp new file mode 100644 index 00000000..be0afb8a --- /dev/null +++ b/src/VBox/Main/src-server/ClientToken.cpp @@ -0,0 +1,262 @@ +/** @file + * + * VirtualBox API client session crash token handling + */ + +/* + * Copyright (C) 2004-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include +#include +#include + +#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER +# include +# include +# include +# include +# include +#endif + +#include + +#include + +#include "VirtualBoxBase.h" +#include "AutoCaller.h" +#include "ClientToken.h" +#include "MachineImpl.h" + +Machine::ClientToken::ClientToken() +{ + AssertReleaseFailed(); +} + +Machine::ClientToken::~ClientToken() +{ +#if defined(RT_OS_WINDOWS) + if (mClientToken) + ::CloseHandle(mClientToken); +#elif defined(RT_OS_OS2) + if (mClientToken != NULLHANDLE) + ::DosCloseMutexSem(mClientToken); +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + if (mClientToken >= 0) + ::semctl(mClientToken, 0, IPC_RMID); +# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN + mClientTokenId = "0"; +# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */ +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + /* release the token, uses reference counting */ + if (mClientToken) + { + if (!mClientTokenPassed) + mClientToken->Release(); + mClientToken = NULL; + } +#else +# error "Port me!" +#endif + mClientToken = CTTOKENARG; +} + +Machine::ClientToken::ClientToken(const ComObjPtr &pMachine, + SessionMachine *pSessionMachine) : + mMachine(pMachine) +{ +#if defined(RT_OS_WINDOWS) + NOREF(pSessionMachine); + Bstr tokenId = pMachine->mData->m_strConfigFileFull; + for (size_t i = 0; i < tokenId.length(); i++) + if (tokenId.raw()[i] == '\\') + tokenId.raw()[i] = '/'; + mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw()); + mClientTokenId = tokenId; + AssertMsg(mClientToken, + ("Cannot create token '%s', err=%d", + mClientTokenId.c_str(), ::GetLastError())); +#elif defined(RT_OS_OS2) + NOREF(pSessionMachine); + Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}", + pMachine->mData->mUuid.raw()); + mClientTokenId = ipcSem; + APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mClientToken, 0, FALSE); + AssertMsg(arc == NO_ERROR, + ("Cannot create token '%s', arc=%ld", + ipcSem.c_str(), arc)); +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + NOREF(pSessionMachine); +# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN +# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64) + /** @todo Check that this still works correctly. */ + AssertCompileSize(key_t, 8); +# else + AssertCompileSize(key_t, 4); +# endif + key_t key; + mClientToken = -1; + mClientTokenId = "0"; + for (uint32_t i = 0; i < 1 << 24; i++) + { + key = ((uint32_t)'V' << 24) | i; + int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL); + if (sem >= 0 || (errno != EEXIST && errno != EACCES)) + { + mClientToken = sem; + if (sem >= 0) + mClientTokenId = BstrFmt("%u", key); + break; + } + } +# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ + Utf8Str semName = pMachine->mData->m_strConfigFileFull; + char *pszSemName = NULL; + RTStrUtf8ToCurrentCP(&pszSemName, semName); + key_t key = ::ftok(pszSemName, 'V'); + RTStrFree(pszSemName); + + mClientToken = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT); +# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ + + int errnoSave = errno; + if (mClientToken < 0 && errnoSave == ENOSYS) + { + mMachine->setError(E_FAIL, + tr("Cannot create IPC semaphore. Most likely your host kernel lacks " + "support for SysV IPC. Check the host kernel configuration for " + "CONFIG_SYSVIPC=y")); + mClientToken = CTTOKENARG; + return; + } + /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing + * the token */ + if (mClientToken < 0 && errnoSave == ENOSPC) + { +#ifdef RT_OS_LINUX + mMachine->setError(E_FAIL, + tr("Cannot create IPC semaphore because the system limit for the " + "maximum number of semaphore sets (SEMMNI), or the system wide " + "maximum number of semaphores (SEMMNS) would be exceeded. The " + "current set of SysV IPC semaphores can be determined from " + "the file /proc/sysvipc/sem")); +#else + mMachine->setError(E_FAIL, + tr("Cannot create IPC semaphore because the system-imposed limit " + "on the maximum number of allowed semaphores or semaphore " + "identifiers system-wide would be exceeded")); +#endif + mClientToken = CTTOKENARG; + return; + } + AssertMsgReturnVoid(mClientToken >= 0, ("Cannot create token, errno=%d", errnoSave)); + /* set the initial value to 1 */ + int rv = ::semctl(mClientToken, 0, SETVAL, 1); + errnoSave = errno; + if (rv != 0) + { + ::semctl(mClientToken, 0, IPC_RMID); + mClientToken = CTTOKENARG; + AssertMsgFailedReturnVoid(("Cannot init token, errno=%d", errnoSave)); + } +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + ComObjPtr pToken; + HRESULT rc = pToken.createObject(); + if (SUCCEEDED(rc)) + { + rc = pToken->init(pSessionMachine); + if (SUCCEEDED(rc)) + { + mClientToken = pToken; + if (mClientToken) + { + rc = mClientToken->AddRef(); + if (FAILED(rc)) + mClientToken = NULL; + } + } + } + pToken.setNull(); + mClientTokenPassed = false; + /* mClientTokenId isn't really used */ + mClientTokenId = pMachine->mData->m_strConfigFileFull; + AssertMsg(mClientToken, + ("Cannot create token '%s', rc=%Rhrc", + mClientTokenId.c_str(), rc)); +#else +# error "Port me!" +#endif +} + +bool Machine::ClientToken::isReady() +{ + return mClientToken != CTTOKENARG; +} + +void Machine::ClientToken::getId(Utf8Str &strId) +{ + strId = mClientTokenId; +} + +CTTOKENTYPE Machine::ClientToken::getToken() +{ +#ifdef VBOX_WITH_GENERIC_SESSION_WATCHER + mClientTokenPassed = true; +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + return mClientToken; +} + +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER +bool Machine::ClientToken::release() +{ + bool terminated = false; + +#if defined(RT_OS_WINDOWS) + AssertMsg(mClientToken, ("semaphore must be created")); + + /* release the token */ + ::ReleaseMutex(mClientToken); + terminated = true; +#elif defined(RT_OS_OS2) + AssertMsg(mClientToken, ("semaphore must be created")); + + /* release the token */ + ::DosReleaseMutexSem(mClientToken); + terminated = true; +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + AssertMsg(mClientToken >= 0, ("semaphore must be created")); + int val = ::semctl(mClientToken, 0, GETVAL); + if (val > 0) + { + /* the semaphore is signaled, meaning the session is terminated */ + terminated = true; + } +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + /** @todo r=klaus never tested, this code is not reached */ + AssertMsg(mClientToken, ("token must be created")); + /* release the token, uses reference counting */ + if (mClientToken) + { + if (!mClientTokenPassed) + mClientToken->Release(); + mClientToken = NULL; + } + terminated = true; +#else +# error "Port me!" +#endif + return terminated; +} +#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/ClientWatcher.cpp b/src/VBox/Main/src-server/ClientWatcher.cpp new file mode 100644 index 00000000..6d2cd3f1 --- /dev/null +++ b/src/VBox/Main/src-server/ClientWatcher.cpp @@ -0,0 +1,849 @@ +/** @file + * + * VirtualBox API client session crash watcher + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include "VirtualBoxBase.h" +#include "AutoCaller.h" +#include "ClientWatcher.h" +#include "ClientToken.h" +#include "VirtualBoxImpl.h" +#include "MachineImpl.h" + +#if defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER) +/** Table for adaptive timeouts. After an update the counter starts at the + * maximum value and decreases to 0, i.e. first the short timeouts are used + * and then the longer ones. This minimizes the detection latency in the + * cases where a change is expected, for crashes. */ +static const RTMSINTERVAL s_aUpdateTimeoutSteps[] = { 500, 200, 100, 50, 20, 10, 5 }; +#endif + + + +VirtualBox::ClientWatcher::ClientWatcher() : + mLock(LOCKCLASS_OBJECTSTATE) +{ + AssertReleaseFailed(); +} + +VirtualBox::ClientWatcher::~ClientWatcher() +{ + if (mThread != NIL_RTTHREAD) + { + /* signal the client watcher thread, should be exiting now */ + update(); + /* wait for termination */ + RTThreadWait(mThread, RT_INDEFINITE_WAIT, NULL); + mThread = NIL_RTTHREAD; + } + mProcesses.clear(); +#if defined(RT_OS_WINDOWS) + if (mUpdateReq != NULL) + { + ::CloseHandle(mUpdateReq); + mUpdateReq = NULL; + } +#elif defined(RT_OS_OS2) || defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + if (mUpdateReq != NIL_RTSEMEVENT) + { + RTSemEventDestroy(mUpdateReq); + mUpdateReq = NIL_RTSEMEVENT; + } +#else +# error "Port me!" +#endif +} + +VirtualBox::ClientWatcher::ClientWatcher(const ComObjPtr &pVirtualBox) : + mVirtualBox(pVirtualBox), + mThread(NIL_RTTHREAD), + mUpdateReq(CWUPDATEREQARG), + mLock(LOCKCLASS_OBJECTSTATE) +{ +#if defined(RT_OS_WINDOWS) + mUpdateReq = ::CreateEvent(NULL, FALSE, FALSE, NULL); +#elif defined(RT_OS_OS2) + RTSemEventCreate(&mUpdateReq); +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) || defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + RTSemEventCreate(&mUpdateReq); + /* start with high timeouts, nothing to do */ + ASMAtomicUoWriteU8(&mUpdateAdaptCtr, 0); +#else +# error "Port me!" +#endif + + int vrc = RTThreadCreate(&mThread, + worker, + (void *)this, + 0, + RTTHREADTYPE_MAIN_WORKER, + RTTHREADFLAGS_WAITABLE, + "Watcher"); + AssertRC(vrc); +} + +bool VirtualBox::ClientWatcher::isReady() +{ + return mThread != NIL_RTTHREAD; +} + +/** + * Sends a signal to the thread to rescan the clients/VMs having open sessions. + */ +void VirtualBox::ClientWatcher::update() +{ + AssertReturnVoid(mThread != NIL_RTTHREAD); + + /* sent an update request */ +#if defined(RT_OS_WINDOWS) + ::SetEvent(mUpdateReq); +#elif defined(RT_OS_OS2) + RTSemEventSignal(mUpdateReq); +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + /* use short timeouts, as we expect changes */ + ASMAtomicUoWriteU8(&mUpdateAdaptCtr, RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1); + RTSemEventSignal(mUpdateReq); +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + RTSemEventSignal(mUpdateReq); +#else +# error "Port me!" +#endif +} + +/** + * Adds a process to the list of processes to be reaped. This call should be + * followed by a call to update() to cause the necessary actions immediately, + * in case the process crashes straight away. + */ +void VirtualBox::ClientWatcher::addProcess(RTPROCESS pid) +{ + AssertReturnVoid(mThread != NIL_RTTHREAD); + /* @todo r=klaus, do the reaping on all platforms! */ +#ifndef RT_OS_WINDOWS + AutoWriteLock alock(mLock COMMA_LOCKVAL_SRC_POS); + mProcesses.push_back(pid); +#endif +} + +/** + * Thread worker function that watches the termination of all client processes + * that have open sessions using IMachine::LockMachine() + */ +/*static*/ +DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD /* thread */, void *pvUser) +{ + LogFlowFuncEnter(); + + VirtualBox::ClientWatcher *that = (VirtualBox::ClientWatcher *)pvUser; + Assert(that); + + typedef std::vector > MachineVector; + typedef std::vector > SessionMachineVector; + + SessionMachineVector machines; + MachineVector spawnedMachines; + + size_t cnt = 0; + size_t cntSpawned = 0; + + VirtualBoxBase::initializeComForThread(); + +#if defined(RT_OS_WINDOWS) + + /// @todo (dmik) processes reaping! + + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + handles[0] = that->mUpdateReq; + + do + { + AutoCaller autoCaller(that->mVirtualBox); + /* VirtualBox has been early uninitialized, terminate */ + if (!autoCaller.isOk()) + break; + + do + { + /* release the caller to let uninit() ever proceed */ + autoCaller.release(); + + DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned), + handles, + FALSE, + INFINITE); + + /* Restore the caller before using VirtualBox. If it fails, this + * means VirtualBox is being uninitialized and we must terminate. */ + autoCaller.add(); + if (!autoCaller.isOk()) + break; + + bool update = false; + + if (rc == WAIT_OBJECT_0) + { + /* update event is signaled */ + update = true; + } + else if (rc > WAIT_OBJECT_0 && rc <= (WAIT_OBJECT_0 + cnt)) + { + /* machine mutex is released */ + (machines[rc - WAIT_OBJECT_0 - 1])->checkForDeath(); + update = true; + } + else if (rc > WAIT_ABANDONED_0 && rc <= (WAIT_ABANDONED_0 + cnt)) + { + /* machine mutex is abandoned due to client process termination */ + (machines[rc - WAIT_ABANDONED_0 - 1])->checkForDeath(); + update = true; + } + else if (rc > WAIT_OBJECT_0 + cnt && rc <= (WAIT_OBJECT_0 + cntSpawned)) + { + /* spawned VM process has terminated (normally or abnormally) */ + (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])-> + checkForSpawnFailure(); + update = true; + } + + if (update) + { + /* close old process handles */ + for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i) + CloseHandle(handles[i]); + + // get reference to the machines list in VirtualBox + VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList(); + + // lock the machines list for reading + AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); + + /* obtain a new set of opened machines */ + cnt = 0; + machines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); + ++it) + { + /// @todo handle situations with more than 64 objects + AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS, + ("MAXIMUM_WAIT_OBJECTS reached")); + + ComObjPtr sm; + if ((*it)->isSessionOpenOrClosing(sm)) + { + AutoCaller smCaller(sm); + if (smCaller.isOk()) + { + AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS); + Machine::ClientToken *ct = sm->getClientToken(); + if (ct) + { + HANDLE ipcSem = ct->getToken(); + machines.push_back(sm); + handles[1 + cnt] = ipcSem; + ++cnt; + } + } + } + } + + LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); + + /* obtain a new set of spawned machines */ + cntSpawned = 0; + spawnedMachines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); + ++it) + { + /// @todo handle situations with more than 64 objects + AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS, + ("MAXIMUM_WAIT_OBJECTS reached")); + + if ((*it)->isSessionSpawning()) + { + ULONG pid; + HRESULT hrc = (*it)->COMGETTER(SessionPID)(&pid); + if (SUCCEEDED(hrc)) + { + HANDLE ph = OpenProcess(SYNCHRONIZE, FALSE, pid); + AssertMsg(ph != NULL, ("OpenProcess (pid=%d) failed with %d\n", + pid, GetLastError())); + if (ph != NULL) + { + spawnedMachines.push_back(*it); + handles[1 + cnt + cntSpawned] = ph; + ++cntSpawned; + } + } + } + } + + LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); + + // machines lock unwinds here + } + } + while (true); + } + while (0); + + /* close old process handles */ + for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i) + CloseHandle(handles[i]); + + /* release sets of machines if any */ + machines.clear(); + spawnedMachines.clear(); + + ::CoUninitialize(); + +#elif defined(RT_OS_OS2) + + /// @todo (dmik) processes reaping! + + /* according to PMREF, 64 is the maximum for the muxwait list */ + SEMRECORD handles[64]; + + HMUX muxSem = NULLHANDLE; + + do + { + AutoCaller autoCaller(that->mVirtualBox); + /* VirtualBox has been early uninitialized, terminate */ + if (!autoCaller.isOk()) + break; + + do + { + /* release the caller to let uninit() ever proceed */ + autoCaller.release(); + + int vrc = RTSemEventWait(that->mUpdateReq, 500); + + /* Restore the caller before using VirtualBox. If it fails, this + * means VirtualBox is being uninitialized and we must terminate. */ + autoCaller.add(); + if (!autoCaller.isOk()) + break; + + bool update = false; + bool updateSpawned = false; + + if (RT_SUCCESS(vrc)) + { + /* update event is signaled */ + update = true; + updateSpawned = true; + } + else + { + AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED, + ("RTSemEventWait returned %Rrc\n", vrc)); + + /* are there any mutexes? */ + if (cnt > 0) + { + /* figure out what's going on with machines */ + + unsigned long semId = 0; + APIRET arc = ::DosWaitMuxWaitSem(muxSem, + SEM_IMMEDIATE_RETURN, &semId); + + if (arc == NO_ERROR) + { + /* machine mutex is normally released */ + Assert(semId >= 0 && semId < cnt); + if (semId >= 0 && semId < cnt) + { +#if 0//def DEBUG + { + AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); + LogFlowFunc(("released mutex: machine='%ls'\n", + machines[semId]->name().raw())); + } +#endif + machines[semId]->checkForDeath(); + } + update = true; + } + else if (arc == ERROR_SEM_OWNER_DIED) + { + /* machine mutex is abandoned due to client process + * termination; find which mutex is in the Owner Died + * state */ + for (size_t i = 0; i < cnt; ++i) + { + PID pid; TID tid; + unsigned long reqCnt; + arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt); + if (arc == ERROR_SEM_OWNER_DIED) + { + /* close the dead mutex as asked by PMREF */ + ::DosCloseMutexSem((HMTX)handles[i].hsemCur); + + Assert(i >= 0 && i < cnt); + if (i >= 0 && i < cnt) + { +#if 0//def DEBUG + { + AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); + LogFlowFunc(("mutex owner dead: machine='%ls'\n", + machines[i]->name().raw())); + } +#endif + machines[i]->checkForDeath(); + } + } + } + update = true; + } + else + AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT, + ("DosWaitMuxWaitSem returned %d\n", arc)); + } + + /* are there any spawning sessions? */ + if (cntSpawned > 0) + { + for (size_t i = 0; i < cntSpawned; ++i) + updateSpawned |= (spawnedMachines[i])-> + checkForSpawnFailure(); + } + } + + if (update || updateSpawned) + { + // get reference to the machines list in VirtualBox + VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList(); + + // lock the machines list for reading + AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); + + if (update) + { + /* close the old muxsem */ + if (muxSem != NULLHANDLE) + ::DosCloseMuxWaitSem(muxSem); + + /* obtain a new set of opened machines */ + cnt = 0; + machines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); ++it) + { + /// @todo handle situations with more than 64 objects + AssertMsg(cnt <= 64 /* according to PMREF */, + ("maximum of 64 mutex semaphores reached (%d)", + cnt)); + + ComObjPtr sm; + if ((*it)->isSessionOpenOrClosing(sm)) + { + AutoCaller smCaller(sm); + if (smCaller.isOk()) + { + AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS); + ClientToken *ct = sm->getClientToken(); + if (ct) + { + HMTX ipcSem = ct->getToken(); + machines.push_back(sm); + handles[cnt].hsemCur = (HSEM)ipcSem; + handles[cnt].ulUser = cnt; + ++cnt; + } + } + } + } + + LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); + + if (cnt > 0) + { + /* create a new muxsem */ + APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt, + handles, + DCMW_WAIT_ANY); + AssertMsg(arc == NO_ERROR, + ("DosCreateMuxWaitSem returned %d\n", arc)); + NOREF(arc); + } + } + + if (updateSpawned) + { + /* obtain a new set of spawned machines */ + spawnedMachines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); ++it) + { + if ((*it)->isSessionSpawning()) + spawnedMachines.push_back(*it); + } + + cntSpawned = spawnedMachines.size(); + LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); + } + } + } + while (true); + } + while (0); + + /* close the muxsem */ + if (muxSem != NULLHANDLE) + ::DosCloseMuxWaitSem(muxSem); + + /* release sets of machines if any */ + machines.clear(); + spawnedMachines.clear(); + +#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + + bool update = false; + bool updateSpawned = false; + + do + { + AutoCaller autoCaller(that->mVirtualBox); + if (!autoCaller.isOk()) + break; + + do + { + /* release the caller to let uninit() ever proceed */ + autoCaller.release(); + + /* determine wait timeout adaptively: after updating information + * relevant to the client watcher, check a few times more + * frequently. This ensures good reaction time when the signalling + * has to be done a bit before the actual change for technical + * reasons, and saves CPU cycles when no activities are expected. */ + RTMSINTERVAL cMillies; + { + uint8_t uOld, uNew; + do + { + uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr); + uNew = uOld ? uOld - 1 : uOld; + } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld)); + Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1); + cMillies = s_aUpdateTimeoutSteps[uOld]; + } + + int rc = RTSemEventWait(that->mUpdateReq, cMillies); + + /* + * Restore the caller before using VirtualBox. If it fails, this + * means VirtualBox is being uninitialized and we must terminate. + */ + autoCaller.add(); + if (!autoCaller.isOk()) + break; + + if (RT_SUCCESS(rc) || update || updateSpawned) + { + /* RT_SUCCESS(rc) means an update event is signaled */ + + // get reference to the machines list in VirtualBox + VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList(); + + // lock the machines list for reading + AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); + + if (RT_SUCCESS(rc) || update) + { + /* obtain a new set of opened machines */ + machines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); + ++it) + { + ComObjPtr sm; + if ((*it)->isSessionOpenOrClosing(sm)) + machines.push_back(sm); + } + + cnt = machines.size(); + LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); + } + + if (RT_SUCCESS(rc) || updateSpawned) + { + /* obtain a new set of spawned machines */ + spawnedMachines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); + ++it) + { + if ((*it)->isSessionSpawning()) + spawnedMachines.push_back(*it); + } + + cntSpawned = spawnedMachines.size(); + LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); + } + + // machines lock unwinds here + } + + update = false; + for (size_t i = 0; i < cnt; ++i) + update |= (machines[i])->checkForDeath(); + + updateSpawned = false; + for (size_t i = 0; i < cntSpawned; ++i) + updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure(); + + /* reap child processes */ + { + AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS); + if (that->mProcesses.size()) + { + LogFlowFunc(("UPDATE: child process count = %d\n", + that->mProcesses.size())); + VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin(); + while (it != that->mProcesses.end()) + { + RTPROCESS pid = *it; + RTPROCSTATUS status; + int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status); + if (vrc == VINF_SUCCESS) + { + if ( status.enmReason != RTPROCEXITREASON_NORMAL + || status.iStatus != RTEXITCODE_SUCCESS) + { + switch (status.enmReason) + { + default: + case RTPROCEXITREASON_NORMAL: + LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + case RTPROCEXITREASON_ABEND: + LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + case RTPROCEXITREASON_SIGNAL: + LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + } + } + else + LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n", + pid, pid, status.iStatus, + status.enmReason)); + it = that->mProcesses.erase(it); + } + else + { + LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n", + pid, pid, vrc)); + if (vrc != VERR_PROCESS_RUNNING) + { + /* remove the process if it is not already running */ + it = that->mProcesses.erase(it); + } + else + ++it; + } + } + } + } + } + while (true); + } + while (0); + + /* release sets of machines if any */ + machines.clear(); + spawnedMachines.clear(); + +#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) + + bool updateSpawned = false; + + do + { + AutoCaller autoCaller(that->mVirtualBox); + if (!autoCaller.isOk()) + break; + + do + { + /* release the caller to let uninit() ever proceed */ + autoCaller.release(); + + /* determine wait timeout adaptively: after updating information + * relevant to the client watcher, check a few times more + * frequently. This ensures good reaction time when the signalling + * has to be done a bit before the actual change for technical + * reasons, and saves CPU cycles when no activities are expected. */ + RTMSINTERVAL cMillies; + { + uint8_t uOld, uNew; + do + { + uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr); + uNew = uOld ? uOld - 1 : uOld; + } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld)); + Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1); + cMillies = s_aUpdateTimeoutSteps[uOld]; + } + + int rc = RTSemEventWait(that->mUpdateReq, cMillies); + + /* + * Restore the caller before using VirtualBox. If it fails, this + * means VirtualBox is being uninitialized and we must terminate. + */ + autoCaller.add(); + if (!autoCaller.isOk()) + break; + + /** @todo this quite big effort for catching machines in spawning + * state which can't be caught by the token mechanism (as the token + * can't be in the other process yet) could be eliminated if the + * reaping is made smarter, having cross-reference information + * from the pid to the corresponding machine object. Both cases do + * more or less the same thing anyway. */ + if (RT_SUCCESS(rc) || updateSpawned) + { + /* RT_SUCCESS(rc) means an update event is signaled */ + + // get reference to the machines list in VirtualBox + VirtualBox::MachinesOList &allMachines = that->mVirtualBox->getMachinesList(); + + // lock the machines list for reading + AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); + + if (RT_SUCCESS(rc) || updateSpawned) + { + /* obtain a new set of spawned machines */ + spawnedMachines.clear(); + + for (MachinesOList::iterator it = allMachines.begin(); + it != allMachines.end(); + ++it) + { + if ((*it)->isSessionSpawning()) + spawnedMachines.push_back(*it); + } + + cntSpawned = spawnedMachines.size(); + LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); + } + + NOREF(cnt); + // machines lock unwinds here + } + + updateSpawned = false; + for (size_t i = 0; i < cntSpawned; ++i) + updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure(); + + /* reap child processes */ + { + AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS); + if (that->mProcesses.size()) + { + LogFlowFunc(("UPDATE: child process count = %d\n", + that->mProcesses.size())); + VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin(); + while (it != that->mProcesses.end()) + { + RTPROCESS pid = *it; + RTPROCSTATUS status; + int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status); + if (vrc == VINF_SUCCESS) + { + if ( status.enmReason != RTPROCEXITREASON_NORMAL + || status.iStatus != RTEXITCODE_SUCCESS) + { + switch (status.enmReason) + { + default: + case RTPROCEXITREASON_NORMAL: + LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + case RTPROCEXITREASON_ABEND: + LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + case RTPROCEXITREASON_SIGNAL: + LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n", + pid, pid, status.iStatus, status.iStatus)); + break; + } + } + else + LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n", + pid, pid, status.iStatus, + status.enmReason)); + it = that->mProcesses.erase(it); + } + else + { + LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n", + pid, pid, vrc)); + if (vrc != VERR_PROCESS_RUNNING) + { + /* remove the process if it is not already running */ + it = that->mProcesses.erase(it); + } + else + ++it; + } + } + } + } + } + while (true); + } + while (0); + + /* release sets of machines if any */ + machines.clear(); + spawnedMachines.clear(); + +#else +# error "Port me!" +#endif + + VirtualBoxBase::uninitializeComForThread(); + + LogFlowFuncLeave(); + return 0; +} +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/DHCPServerImpl.cpp b/src/VBox/Main/src-server/DHCPServerImpl.cpp index 45f21370..1cd7ce78 100644 --- a/src/VBox/Main/src-server/DHCPServerImpl.cpp +++ b/src/VBox/Main/src-server/DHCPServerImpl.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -17,34 +17,65 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -#include "DHCPServerRunner.h" +#include +#include "NetworkServiceRunner.h" #include "DHCPServerImpl.h" #include "AutoCaller.h" #include "Logging.h" #include +#include #include #include "VirtualBoxImpl.h" // constructor / destructor ///////////////////////////////////////////////////////////////////////////// +const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway"; +const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip"; +const std::string DHCPServerRunner::kDsrKeyUpperIp = "--upper-ip"; + + +struct DHCPServer::Data +{ + Data() : enabled(FALSE) {} + + Bstr IPAddress; + Bstr lowerIP; + Bstr upperIP; + + BOOL enabled; + DHCPServerRunner dhcp; + + DhcpOptionMap GlobalDhcpOptions; + VmSlot2OptionsMap VmSlot2Options; +}; + DHCPServer::DHCPServer() - : mVirtualBox(NULL) + : m(NULL), mVirtualBox(NULL) { + m = new DHCPServer::Data(); } + DHCPServer::~DHCPServer() { + if (m) + { + delete m; + m = NULL; + } } + HRESULT DHCPServer::FinalConstruct() { return BaseFinalConstruct(); } + void DHCPServer::FinalRelease() { uninit (); @@ -52,6 +83,7 @@ void DHCPServer::FinalRelease() BaseFinalRelease(); } + void DHCPServer::uninit() { /* Enclose the state transition Ready->InUninit->NotReady */ @@ -62,6 +94,7 @@ void DHCPServer::uninit() unconst(mVirtualBox) = NULL; } + HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName) { AssertReturn(aName != NULL, E_INVALIDARG); @@ -73,11 +106,12 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName) unconst(mVirtualBox) = aVirtualBox; unconst(mName) = aName; - m.IPAddress = "0.0.0.0"; - m.networkMask = "0.0.0.0"; - m.enabled = FALSE; - m.lowerIP = "0.0.0.0"; - m.upperIP = "0.0.0.0"; + m->IPAddress = "0.0.0.0"; + m->GlobalDhcpOptions.insert(DhcpOptValuePair(DhcpOpt_SubnetMask, Bstr("0.0.0.0"))); + m->enabled = FALSE; + + m->lowerIP = "0.0.0.0"; + m->upperIP = "0.0.0.0"; /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -85,6 +119,7 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName) return S_OK; } + HRESULT DHCPServer::init(VirtualBox *aVirtualBox, const settings::DHCPServer &data) { @@ -96,17 +131,25 @@ HRESULT DHCPServer::init(VirtualBox *aVirtualBox, unconst(mVirtualBox) = aVirtualBox; unconst(mName) = data.strNetworkName; - m.IPAddress = data.strIPAddress; - m.networkMask = data.strIPNetworkMask; - m.enabled = data.fEnabled; - m.lowerIP = data.strIPLower; - m.upperIP = data.strIPUpper; + m->IPAddress = data.strIPAddress; + m->enabled = data.fEnabled; + m->lowerIP = data.strIPLower; + m->upperIP = data.strIPUpper; + + m->GlobalDhcpOptions.clear(); + m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(), + data.GlobalDhcpOptions.end()); + + m->VmSlot2Options.clear(); + m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(), + data.VmSlot2OptionsM.end()); autoInitSpan.setSucceeded(); return S_OK; } + HRESULT DHCPServer::saveSettings(settings::DHCPServer &data) { AutoCaller autoCaller(this); @@ -115,15 +158,24 @@ HRESULT DHCPServer::saveSettings(settings::DHCPServer &data) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); data.strNetworkName = mName; - data.strIPAddress = m.IPAddress; - data.strIPNetworkMask = m.networkMask; - data.fEnabled = !!m.enabled; - data.strIPLower = m.lowerIP; - data.strIPUpper = m.upperIP; + data.strIPAddress = m->IPAddress; + + data.fEnabled = !!m->enabled; + data.strIPLower = m->lowerIP; + data.strIPUpper = m->upperIP; + + data.GlobalDhcpOptions.clear(); + data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(), + m->GlobalDhcpOptions.end()); + + data.VmSlot2OptionsM.clear(); + data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(), + m->VmSlot2Options.end()); return S_OK; } + STDMETHODIMP DHCPServer::COMGETTER(NetworkName) (BSTR *aName) { CheckComArgOutPointerValid(aName); @@ -136,6 +188,7 @@ STDMETHODIMP DHCPServer::COMGETTER(NetworkName) (BSTR *aName) return S_OK; } + STDMETHODIMP DHCPServer::COMGETTER(Enabled) (BOOL *aEnabled) { CheckComArgOutPointerValid(aEnabled); @@ -143,18 +196,19 @@ STDMETHODIMP DHCPServer::COMGETTER(Enabled) (BOOL *aEnabled) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - *aEnabled = m.enabled; + *aEnabled = m->enabled; return S_OK; } + STDMETHODIMP DHCPServer::COMSETTER(Enabled) (BOOL aEnabled) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - m.enabled = aEnabled; + m->enabled = aEnabled; // save the global settings; for that we should hold only the VirtualBox lock alock.release(); @@ -164,6 +218,7 @@ STDMETHODIMP DHCPServer::COMSETTER(Enabled) (BOOL aEnabled) return rc; } + STDMETHODIMP DHCPServer::COMGETTER(IPAddress) (BSTR *aIPAddress) { CheckComArgOutPointerValid(aIPAddress); @@ -171,11 +226,12 @@ STDMETHODIMP DHCPServer::COMGETTER(IPAddress) (BSTR *aIPAddress) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - m.IPAddress.cloneTo(aIPAddress); + m->IPAddress.cloneTo(aIPAddress); return S_OK; } + STDMETHODIMP DHCPServer::COMGETTER(NetworkMask) (BSTR *aNetworkMask) { CheckComArgOutPointerValid(aNetworkMask); @@ -183,11 +239,12 @@ STDMETHODIMP DHCPServer::COMGETTER(NetworkMask) (BSTR *aNetworkMask) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - m.networkMask.cloneTo(aNetworkMask); + m->GlobalDhcpOptions[DhcpOpt_SubnetMask].cloneTo(aNetworkMask); return S_OK; } + STDMETHODIMP DHCPServer::COMGETTER(LowerIP) (BSTR *aIPAddress) { CheckComArgOutPointerValid(aIPAddress); @@ -195,11 +252,12 @@ STDMETHODIMP DHCPServer::COMGETTER(LowerIP) (BSTR *aIPAddress) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - m.lowerIP.cloneTo(aIPAddress); + m->lowerIP.cloneTo(aIPAddress); return S_OK; } + STDMETHODIMP DHCPServer::COMGETTER(UpperIP) (BSTR *aIPAddress) { CheckComArgOutPointerValid(aIPAddress); @@ -207,11 +265,12 @@ STDMETHODIMP DHCPServer::COMGETTER(UpperIP) (BSTR *aIPAddress) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - m.upperIP.cloneTo(aIPAddress); + m->upperIP.cloneTo(aIPAddress); return S_OK; } + STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkMask, IN_BSTR aLowerIP, IN_BSTR aUpperIP) { AssertReturn(aIPAddress != NULL, E_INVALIDARG); @@ -223,10 +282,11 @@ STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkM if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - m.IPAddress = aIPAddress; - m.networkMask = aNetworkMask; - m.lowerIP = aLowerIP; - m.upperIP = aUpperIP; + m->IPAddress = aIPAddress; + m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask; + + m->lowerIP = aLowerIP; + m->upperIP = aUpperIP; // save the global settings; for that we should hold only the VirtualBox lock alock.release(); @@ -234,43 +294,251 @@ STDMETHODIMP DHCPServer::SetConfiguration (IN_BSTR aIPAddress, IN_BSTR aNetworkM return mVirtualBox->saveSettings(); } + +STDMETHODIMP DHCPServer::AddGlobalOption(DhcpOpt_T aOption, IN_BSTR aValue) +{ + CheckComArgStr(aValue); + /* store global option */ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + m->GlobalDhcpOptions.insert( + DhcpOptValuePair(aOption, Utf8Str(aValue))); + + /* Indirect way to understand that we're on NAT network */ + if (aOption == DhcpOpt_Router) + m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on"); + + alock.release(); + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); +} + + +STDMETHODIMP DHCPServer::COMGETTER(GlobalOptions)(ComSafeArrayOut(BSTR, aValue)) +{ + CheckComArgOutSafeArrayPointerValid(aValue); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + SafeArray sf(m->GlobalDhcpOptions.size()); + int i = 0; + + for (DhcpOptIterator it = m->GlobalDhcpOptions.begin(); + it != m->GlobalDhcpOptions.end(); ++it) + { + Bstr(Utf8StrFmt("%d:%s", (*it).first, (*it).second.c_str())).detachTo(&sf[i]); + i++; + } + + sf.detachTo(ComSafeArrayOutArg(aValue)); + + return S_OK; +} + + +STDMETHODIMP DHCPServer::COMGETTER(VmConfigs)(ComSafeArrayOut(BSTR, aValue)) +{ + CheckComArgOutSafeArrayPointerValid(aValue); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + SafeArray sf(m->VmSlot2Options.size()); + VmSlot2OptionsIterator it = m->VmSlot2Options.begin(); + int i = 0; + for (;it != m->VmSlot2Options.end(); ++it) + { + Bstr(Utf8StrFmt("[%s]:%d", + it->first.VmName.c_str(), + it->first.Slot)).detachTo(&sf[i]); + i++; + } + + sf.detachTo(ComSafeArrayOutArg(aValue)); + + return S_OK; +} + + +STDMETHODIMP DHCPServer::AddVmSlotOption(IN_BSTR aVmName, LONG aSlot, DhcpOpt_T aOption, IN_BSTR aValue) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + m->VmSlot2Options[settings::VmNameSlotKey( + com::Utf8Str(aVmName), + aSlot)][aOption] = com::Utf8Str(aValue); + + + alock.release(); + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); +} + + +STDMETHODIMP DHCPServer::RemoveVmSlotOptions(IN_BSTR aVmName, LONG aSlot) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + DhcpOptionMap& map = findOptMapByVmNameSlot(com::Utf8Str(aVmName), aSlot); + + map.clear(); + + alock.release(); + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); +} + + +/** + * this is mapping (vm, slot) + */ +STDMETHODIMP DHCPServer::GetVmSlotOptions(IN_BSTR aVmName, + LONG aSlot, + ComSafeArrayOut(BSTR, aValues)) +{ + CheckComArgOutSafeArrayPointerValid(aValues); + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + DhcpOptionMap& map = findOptMapByVmNameSlot(com::Utf8Str(aVmName), aSlot); + + SafeArray sf(map.size()); + int i = 0; + + for (DhcpOptIterator it = map.begin(); + it != map.end(); ++it) + { + Bstr(Utf8StrFmt("%d:%s", (*it).first, (*it).second.c_str())).detachTo(&sf[i]); + i++; + } + + sf.detachTo(ComSafeArrayOutArg(aValues)); + + return S_OK; +} + + +STDMETHODIMP DHCPServer::GetMacOptions(IN_BSTR aMAC, ComSafeArrayOut(BSTR, aValues)) +{ + CheckComArgOutSafeArrayPointerValid(aValues); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + HRESULT hrc = S_OK; + + ComPtr machine; + ComPtr nic; + + VmSlot2OptionsIterator it; + for(it = m->VmSlot2Options.begin(); + it != m->VmSlot2Options.end(); + ++it) + { + + alock.release(); + hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam()); + alock.acquire(); + + if (FAILED(hrc)) + continue; + + alock.release(); + hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam()); + alock.acquire(); + + if (FAILED(hrc)) + continue; + + com::Bstr mac; + + alock.release(); + hrc = nic->COMGETTER(MACAddress)(mac.asOutParam()); + alock.acquire(); + + if (FAILED(hrc)) /* no MAC address ??? */ + break; + + if (!RTStrICmp(com::Utf8Str(mac).c_str(), com::Utf8Str(aMAC).c_str())) + return GetVmSlotOptions(Bstr(it->first.VmName).raw(), + it->first.Slot, + ComSafeArrayOutArg(aValues)); + } /* end of for */ + + return hrc; +} + + +STDMETHODIMP DHCPServer::COMGETTER(EventSource)(IEventSource **aEventSource) +{ + NOREF(aEventSource); + ReturnComNotImplemented(); +} + + STDMETHODIMP DHCPServer::Start(IN_BSTR aNetworkName, IN_BSTR aTrunkName, IN_BSTR aTrunkType) { /* Silently ignore attempts to run disabled servers. */ - if (!m.enabled) + if (!m->enabled) return S_OK; - m.dhcp.setOption(DHCPCFG_NETNAME, Utf8Str(aNetworkName), true); + /* Commmon Network Settings */ + m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(aNetworkName).c_str()); + Bstr tmp(aTrunkName); + if (!tmp.isEmpty()) - m.dhcp.setOption(DHCPCFG_TRUNKNAME, Utf8Str(tmp), true); - m.dhcp.setOption(DHCPCFG_TRUNKTYPE, Utf8Str(aTrunkType), true); - //temporary hack for testing - // DHCPCFG_NAME + m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, Utf8Str(tmp).c_str()); + m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str()); + + /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */ char strMAC[32]; Guid guid; guid.create(); RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X", - guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]); - m.dhcp.setOption(DHCPCFG_MACADDRESS, strMAC, true); - m.dhcp.setOption(DHCPCFG_IPADDRESS, Utf8Str(m.IPAddress), true); - // DHCPCFG_LEASEDB, - // DHCPCFG_VERBOSE, - // DHCPCFG_GATEWAY, - m.dhcp.setOption(DHCPCFG_LOWERIP, Utf8Str(m.lowerIP), true); - m.dhcp.setOption(DHCPCFG_UPPERIP, Utf8Str(m.upperIP), true); - m.dhcp.setOption(DHCPCFG_NETMASK, Utf8Str(m.networkMask), true); - - // DHCPCFG_HELP, - // DHCPCFG_VERSION, - // DHCPCFG_NOTOPT_MAXVAL - m.dhcp.setOption(DHCPCFG_BEGINCONFIG, "", true); - - return RT_FAILURE(m.dhcp.start()) ? E_FAIL : S_OK; - //m.dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */ + guid.raw()->au8[0], + guid.raw()->au8[1], + guid.raw()->au8[2]); + m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC); + m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str()); + m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask]).c_str()); + m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str()); + m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str()); + + /* XXX: This parameters Dhcp Server will fetch via API */ + return RT_FAILURE(m->dhcp.start()) ? E_FAIL : S_OK; + //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */ } + STDMETHODIMP DHCPServer::Stop (void) { - return RT_FAILURE(m.dhcp.stop()) ? E_FAIL : S_OK; + return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK; +} + + +DhcpOptionMap& DHCPServer::findOptMapByVmNameSlot(const com::Utf8Str& aVmName, + LONG aSlot) +{ + return m->VmSlot2Options[settings::VmNameSlotKey( + com::Utf8Str(aVmName), + aSlot)]; } diff --git a/src/VBox/Main/src-server/DHCPServerRunner.cpp b/src/VBox/Main/src-server/DHCPServerRunner.cpp deleted file mode 100644 index aab7c8a9..00000000 --- a/src/VBox/Main/src-server/DHCPServerRunner.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* $Id: DHCPServerRunner.cpp $ */ -/** @file - * VirtualBox Main - interface for VBox DHCP server - */ - -/* - * Copyright (C) 2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ -#include "DHCPServerRunner.h" -#include -#include -#include - -struct ARGDEF -{ - DHCPCFG Type; - const char * Name; -}; - -#ifdef RT_OS_WINDOWS -# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP.exe" -#else -# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP" -#endif - -static const ARGDEF g_aArgDefs[] = -{ - {DHCPCFG_NAME, "--name"}, - {DHCPCFG_NETNAME, "--network"}, - {DHCPCFG_TRUNKTYPE, "--trunk-type"}, - {DHCPCFG_TRUNKNAME, "--trunk-name"}, - {DHCPCFG_MACADDRESS, "--mac-address"}, - {DHCPCFG_IPADDRESS, "--ip-address"}, - {DHCPCFG_LEASEDB, "--lease-db"}, - {DHCPCFG_VERBOSE, "--verbose"}, - {DHCPCFG_BEGINCONFIG, "--begin-config"}, - {DHCPCFG_GATEWAY, "--gateway"}, - {DHCPCFG_LOWERIP, "--lower-ip"}, - {DHCPCFG_UPPERIP, "--upper-ip"}, - {DHCPCFG_NETMASK, "--netmask"}, - {DHCPCFG_HELP, "--help"}, - {DHCPCFG_VERSION, "--version"} -}; - -static const ARGDEF * getArgDef(DHCPCFG type) -{ - for (unsigned i = 0; i < RT_ELEMENTS(g_aArgDefs); i++) - if (g_aArgDefs[i].Type == type) - return &g_aArgDefs[i]; - - return NULL; -} - -DHCPServerRunner::DHCPServerRunner() -{ - mProcess = NIL_RTPROCESS; - for (unsigned i = 0; i < DHCPCFG_NOTOPT_MAXVAL; i++) - { - mOptionEnabled[i] = false; - } -} - -void DHCPServerRunner::detachFromServer() -{ - mProcess = NIL_RTPROCESS; -} - -int DHCPServerRunner::start() -{ - if (isRunning()) - return VINF_ALREADY_INITIALIZED; - - const char * args[DHCPCFG_NOTOPT_MAXVAL * 2]; - - /* get the path to the executable */ - char exePathBuf[RTPATH_MAX]; - const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX); - char *substrSl = strrchr(exePathBuf, '/'); - char *substrBs = strrchr(exePathBuf, '\\'); - char *suffix = substrSl ? substrSl : substrBs; - - if (suffix) - { - suffix++; - strcpy(suffix, DHCP_EXECUTABLE_NAME); - } - else - exePath = DHCP_EXECUTABLE_NAME; - - int index = 0; - - args[index++] = exePath; - - for (unsigned i = 0; i < DHCPCFG_NOTOPT_MAXVAL; i++) - { - if (mOptionEnabled[i]) - { - const ARGDEF *pArgDef = getArgDef((DHCPCFG)i); - if (!pArgDef) - continue; - args[index++] = pArgDef->Name; // e.g. "--network" - - /* value can be null for e.g. --begin-config has no value - * and thus check the mOptions string length here - */ - if (mOptions[i].length()) - args[index++] = mOptions[i].c_str(); // value - } - } - - args[index++] = NULL; - - int rc = RTProcCreate(exePath, args, RTENV_DEFAULT, 0, &mProcess); - if (RT_FAILURE(rc)) - mProcess = NIL_RTPROCESS; - - return rc; -} - -int DHCPServerRunner::stop() -{ - if (!isRunning()) - return VINF_OBJECT_DESTROYED; - - int rc = RTProcTerminate(mProcess); - mProcess = NIL_RTPROCESS; - return rc; -} - -bool DHCPServerRunner::isRunning() -{ - if (mProcess == NIL_RTPROCESS) - return false; - - RTPROCSTATUS status; - int rc = RTProcWait(mProcess, RTPROCWAIT_FLAGS_NOBLOCK, &status); - - if (rc == VERR_PROCESS_RUNNING) - return true; - - mProcess = NIL_RTPROCESS; - return false; -} diff --git a/src/VBox/Main/src-server/HostDnsService.cpp b/src/VBox/Main/src-server/HostDnsService.cpp new file mode 100644 index 00000000..011528fb --- /dev/null +++ b/src/VBox/Main/src-server/HostDnsService.cpp @@ -0,0 +1,363 @@ +/* $Id: HostDnsService.cpp $ */ +/** @file + * Base class fo Host DNS & Co services. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include + +#include + +#include "Logging.h" +#include "VirtualBoxImpl.h" +#include +#include +#include + +#include +#include +#include "HostDnsService.h" + + +static HostDnsMonitor *g_monitor; + +static void dumpHostDnsInformation(const HostDnsInformation&); +static void dumpHostDnsStrVector(const std::string&, const std::vector&); + +/* Lockee */ +Lockee::Lockee() +{ + RTCritSectInit(&mLock); +} + +Lockee::~Lockee() +{ + RTCritSectDelete(&mLock); +} + +const RTCRITSECT* Lockee::lock() const +{ + return &mLock; +} + +/* ALock */ +ALock::ALock(const Lockee *aLockee) + : lockee(aLockee) +{ + RTCritSectEnter(const_cast(lockee->lock())); +} + +ALock::~ALock() +{ + RTCritSectLeave(const_cast(lockee->lock())); +} + +inline static void detachVectorOfString(const std::vector& v, + ComSafeArrayOut(BSTR, aBstrArray)) +{ + com::SafeArray aBstr(v.size()); + + std::vector::const_iterator it; + + int i = 0; + it = v.begin(); + for (; it != v.end(); ++it, ++i) + Utf8Str(it->c_str()).cloneTo(&aBstr[i]); + + aBstr.detachTo(ComSafeArrayOutArg(aBstrArray)); +} + +struct HostDnsMonitor::Data +{ + Data(bool aThreaded):fThreaded(aThreaded){} + + std::vector proxies; + HostDnsInformation info; + const bool fThreaded; + RTTHREAD hMonitoringThread; + RTSEMEVENT hDnsInitEvent; +}; + +struct HostDnsMonitorProxy::Data +{ + Data(const HostDnsMonitor *aMonitor, const VirtualBox *aParent) + : info(NULL) + , virtualbox(aParent) + , monitor(aMonitor) + , fModified(true) + {} + + virtual ~Data() + { + if (info) + { + delete info; + info = NULL; + } + } + + HostDnsInformation *info; + const VirtualBox *virtualbox; + const HostDnsMonitor *monitor; + bool fModified; +}; + + +HostDnsMonitor::HostDnsMonitor(bool fThreaded) + : m(NULL) +{ + m = new HostDnsMonitor::Data(fThreaded); +} + +HostDnsMonitor::~HostDnsMonitor() +{ + if (m) + { + delete m; + m = NULL; + } +} + +const HostDnsMonitor *HostDnsMonitor::getHostDnsMonitor() +{ + /* XXX: Moved initialization from HostImpl.cpp */ + if (!g_monitor) + { +# if defined (RT_OS_DARWIN) + g_monitor = new HostDnsServiceDarwin(); +# elif defined(RT_OS_WINDOWS) + g_monitor = new HostDnsServiceWin(); +# elif defined(RT_OS_LINUX) + g_monitor = new HostDnsServiceLinux(); +# elif defined(RT_OS_SOLARIS) + g_monitor = new HostDnsServiceSolaris(); +# elif defined(RT_OS_FREEBSD) + g_monitor = new HostDnsServiceFreebsd(); +# elif defined(RT_OS_OS2) + g_monitor = new HostDnsServiceOs2(); +# else + g_monitor = new HostDnsService(); +# endif + g_monitor->init(); + } + + return g_monitor; +} + +void HostDnsMonitor::addMonitorProxy(PCHostDnsMonitorProxy proxy) const +{ + ALock l(this); + m->proxies.push_back(proxy); + proxy->notify(); +} + +void HostDnsMonitor::releaseMonitorProxy(PCHostDnsMonitorProxy proxy) const +{ + ALock l(this); + std::vector::iterator it; + it = std::find(m->proxies.begin(), m->proxies.end(), proxy); + + if (it == m->proxies.end()) + return; + + m->proxies.erase(it); +} + +void HostDnsMonitor::shutdown() +{ + if (g_monitor) + { + delete g_monitor; + g_monitor = NULL; + } +} + +const HostDnsInformation &HostDnsMonitor::getInfo() const +{ + return m->info; +} + +void HostDnsMonitor::notifyAll() const +{ + ALock l(this); + std::vector::const_iterator it; + for (it = m->proxies.begin(); it != m->proxies.end(); ++it) + (*it)->notify(); +} + +void HostDnsMonitor::setInfo(const HostDnsInformation &info) +{ + ALock l(this); + m->info = info; +} + +HRESULT HostDnsMonitor::init() +{ + if (m->fThreaded) + { + int rc = RTSemEventCreate(&m->hDnsInitEvent); + AssertRCReturn(rc, E_FAIL); + + rc = RTThreadCreate(&m->hMonitoringThread, + HostDnsMonitor::threadMonitoringRoutine, + this, 128 * _1K, RTTHREADTYPE_IO, 0, "dns-monitor"); + AssertRCReturn(rc, E_FAIL); + + RTSemEventWait(m->hDnsInitEvent, RT_INDEFINITE_WAIT); + } + return S_OK; +} + + +void HostDnsMonitor::monitorThreadInitializationDone() +{ + RTSemEventSignal(m->hDnsInitEvent); +} + + +int HostDnsMonitor::threadMonitoringRoutine(RTTHREAD, void *pvUser) +{ + HostDnsMonitor *pThis = static_cast(pvUser); + return pThis->monitorWorker(); +} + +/* HostDnsMonitorProxy */ +HostDnsMonitorProxy::HostDnsMonitorProxy() + : m(NULL) +{ +} + +HostDnsMonitorProxy::~HostDnsMonitorProxy() +{ + if (m) + { + if (m->monitor) + m->monitor->releaseMonitorProxy(this); + delete m; + m = NULL; + } +} + +void HostDnsMonitorProxy::init(const HostDnsMonitor *mon, const VirtualBox* aParent) +{ + m = new HostDnsMonitorProxy::Data(mon, aParent); + m->monitor->addMonitorProxy(this); + updateInfo(); +} + +void HostDnsMonitorProxy::notify() const +{ + m->fModified = true; + const_cast(m->virtualbox)->onHostNameResolutionConfigurationChange(); +} + +HRESULT HostDnsMonitorProxy::GetNameServers(ComSafeArrayOut(BSTR, aNameServers)) +{ + AssertReturn(m && m->info, E_FAIL); + ALock l(this); + + if (m->fModified) + updateInfo(); + + LogRel(("HostDnsMonitorProxy::GetNameServers:\n")); + dumpHostDnsStrVector("Name Server", m->info->servers); + + detachVectorOfString(m->info->servers, ComSafeArrayOutArg(aNameServers)); + + return S_OK; +} + +HRESULT HostDnsMonitorProxy::GetDomainName(BSTR *aDomainName) +{ + AssertReturn(m && m->info, E_FAIL); + ALock l(this); + + if (m->fModified) + updateInfo(); + + LogRel(("HostDnsMonitorProxy::GetDomainName: %s\n", m->info->domain.c_str())); + + Utf8Str(m->info->domain.c_str()).cloneTo(aDomainName); + + return S_OK; +} + +HRESULT HostDnsMonitorProxy::GetSearchStrings(ComSafeArrayOut(BSTR, aSearchStrings)) +{ + AssertReturn(m && m->info, E_FAIL); + ALock l(this); + + if (m->fModified) + updateInfo(); + + LogRel(("HostDnsMonitorProxy::GetSearchStrings:\n")); + dumpHostDnsStrVector("Search String", m->info->searchList); + + detachVectorOfString(m->info->searchList, ComSafeArrayOutArg(aSearchStrings)); + + return S_OK; +} + +bool HostDnsMonitorProxy::operator==(PCHostDnsMonitorProxy& rhs) +{ + if (!m || !rhs->m) + return false; + + /** + * we've assigned to the same instance of VirtualBox. + */ + return m->virtualbox == rhs->m->virtualbox; +} + +void HostDnsMonitorProxy::updateInfo() +{ + HostDnsInformation *info = new HostDnsInformation(m->monitor->getInfo()); + HostDnsInformation *old = m->info; + + LogRel(("HostDnsMonitorProxy: Host's DNS information updated:\n")); + dumpHostDnsInformation(*info); + + m->info = info; + if (old) + { + LogRel(("HostDnsMonitorProxy: Old host information:\n")); + dumpHostDnsInformation(*old); + + delete old; + } + + m->fModified = false; +} + + +static void dumpHostDnsInformation(const HostDnsInformation& info) +{ + dumpHostDnsStrVector("DNS server", info.servers); + dumpHostDnsStrVector("SearchString", info.searchList); + + if (!info.domain.empty()) + LogRel(("DNS domain: %s\n", info.domain.c_str())); +} + + +static void dumpHostDnsStrVector(const std::string& prefix, const std::vector& v) +{ + int i = 1; + for (std::vector::const_iterator it = v.begin(); + it != v.end(); + ++it, ++i) + LogRel(("%s %d: %s\n", prefix.c_str(), i, it->c_str())); +} diff --git a/src/VBox/Main/src-server/HostDnsService.h b/src/VBox/Main/src-server/HostDnsService.h new file mode 100644 index 00000000..56da78d0 --- /dev/null +++ b/src/VBox/Main/src-server/HostDnsService.h @@ -0,0 +1,236 @@ +/* $Id: HostDnsService.h $ */ +/** @file + * Host DNS listener. + */ + +/* + * Copyright (C) 2005-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ___H_DNSHOSTSERVICE +#define ___H_DNSHOSTSERVICE +#include "VirtualBoxBase.h" + +#include +#include +#include + +#include +#include + +typedef std::list Utf8StrList; +typedef Utf8StrList::iterator Utf8StrListIterator; + +class HostDnsMonitorProxy; +typedef const HostDnsMonitorProxy *PCHostDnsMonitorProxy; + +class Lockee +{ + public: + Lockee(); + virtual ~Lockee(); + const RTCRITSECT* lock() const; + + private: + RTCRITSECT mLock; +}; + +class ALock +{ + public: + explicit ALock(const Lockee *l); + ~ALock(); + + private: + const Lockee *lockee; +}; + +class HostDnsInformation +{ + public: + std::vector servers; + std::string domain; + std::vector searchList; +}; + +/** + * This class supposed to be a real DNS monitor object it should be singleton, + * it lifecycle starts and ends together with VBoxSVC. + */ +class HostDnsMonitor : public Lockee +{ + public: + static const HostDnsMonitor *getHostDnsMonitor(); + static void shutdown(); + + void addMonitorProxy(PCHostDnsMonitorProxy) const; + void releaseMonitorProxy(PCHostDnsMonitorProxy) const; + const HostDnsInformation &getInfo() const; + /* @note: method will wait till client call + HostDnsService::monitorThreadInitializationDone() */ + virtual HRESULT init(); + + protected: + explicit HostDnsMonitor(bool fThreaded = false); + virtual ~HostDnsMonitor(); + + void notifyAll() const; + void setInfo(const HostDnsInformation &); + + /* this function used only if HostDnsMonitor::HostDnsMonitor(true) */ + void monitorThreadInitializationDone(); + virtual void monitorThreadShutdown() = 0; + virtual int monitorWorker() = 0; + + private: + HostDnsMonitor(const HostDnsMonitor &); + HostDnsMonitor& operator= (const HostDnsMonitor &); + static int threadMonitoringRoutine(RTTHREAD, void *); + + public: + struct Data; + Data *m; +}; + +/** + * This class supposed to be a proxy for events on changing Host Name Resolving configurations. + */ +class HostDnsMonitorProxy : public Lockee +{ + public: + HostDnsMonitorProxy(); + ~HostDnsMonitorProxy(); + void init(const HostDnsMonitor *aMonitor, const VirtualBox *aParent); + void notify() const; + + HRESULT GetNameServers(ComSafeArrayOut(BSTR, aNameServers)); + HRESULT GetDomainName(BSTR *aDomainName); + HRESULT GetSearchStrings(ComSafeArrayOut(BSTR, aSearchStrings)); + + bool operator==(PCHostDnsMonitorProxy&); + + private: + void updateInfo(); + + private: + struct Data; + Data *m; +}; + +# ifdef RT_OS_DARWIN +class HostDnsServiceDarwin : public HostDnsMonitor +{ + public: + HostDnsServiceDarwin(); + ~HostDnsServiceDarwin(); + HRESULT init(); + + protected: + virtual void monitorThreadShutdown(); + virtual int monitorWorker(); + + private: + HRESULT updateInfo(); + static void hostDnsServiceStoreCallback(void *store, void *arrayRef, void *info); + struct Data; + Data *m; +}; +# endif +# ifdef RT_OS_WINDOWS +class HostDnsServiceWin : public HostDnsMonitor +{ + public: + HostDnsServiceWin(); + ~HostDnsServiceWin(); + HRESULT init(); + + protected: + virtual void monitorThreadShutdown(); + virtual int monitorWorker(); + + private: + void strList2List(std::vector& lst, char *strLst); + HRESULT updateInfo(); + + private: + struct Data; + Data *m; +}; +# endif +# if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_OS2) || defined(RT_OS_FREEBSD) +class HostDnsServiceResolvConf: public HostDnsMonitor +{ + public: + explicit HostDnsServiceResolvConf(bool fThreaded = false) : HostDnsMonitor(fThreaded), m(NULL) {} + virtual ~HostDnsServiceResolvConf(); + virtual HRESULT init(const char *aResolvConfFileName); + const std::string& resolvConf() const; + + protected: + HRESULT readResolvConf(); + /* While not all hosts supports Hosts DNS change notifiaction + * default implementation offers return VERR_IGNORE. + */ + virtual void monitorThreadShutdown() {} + virtual int monitorWorker() {return VERR_IGNORED;} + + protected: + struct Data; + Data *m; +}; +# if defined(RT_OS_SOLARIS) +/** + * XXX: https://blogs.oracle.com/praks/entry/file_events_notification + */ +class HostDnsServiceSolaris : public HostDnsServiceResolvConf +{ + public: + HostDnsServiceSolaris(){} + ~HostDnsServiceSolaris(){} + HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");} +}; + +# elif defined(RT_OS_LINUX) +class HostDnsServiceLinux : public HostDnsServiceResolvConf +{ + public: + HostDnsServiceLinux():HostDnsServiceResolvConf(true){} + virtual ~HostDnsServiceLinux(); + virtual HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");} + + protected: + virtual void monitorThreadShutdown(); + virtual int monitorWorker(); +}; + +# elif defined(RT_OS_FREEBSD) +class HostDnsServiceFreebsd: public HostDnsServiceResolvConf +{ + public: + HostDnsServiceFreebsd(){} + ~HostDnsServiceFreebsd(){} + HRESULT init(){ return HostDnsServiceResolvConf::init("/etc/resolv.conf");} +}; + +# elif defined(RT_OS_OS2) +class HostDnsServiceOs2 : public HostDnsServiceResolvConf +{ + public: + HostDnsServiceOs2(){} + ~HostDnsServiceOs2(){} + /* XXX: \\MPTN\\ETC should be taken from environment variable ETC */ + HRESULT init(){ return init("\\MPTN\\ETC\\RESOLV2");} +}; + +# endif +# endif + +#endif /* !___H_DNSHOSTSERVICE */ diff --git a/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp b/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp new file mode 100644 index 00000000..3b2ceeb8 --- /dev/null +++ b/src/VBox/Main/src-server/HostDnsServiceResolvConf.cpp @@ -0,0 +1,91 @@ +/* -*- indent-tabs-mode: nil; -*- */ +#include +#include + + +#ifdef RT_OS_OS2 +# include +typedef int socklen_t; +#endif + +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include + +#include + +#include "HostDnsService.h" +#include "../../Devices/Network/slirp/resolv_conf_parser.h" + + +struct HostDnsServiceResolvConf::Data +{ + Data(const char *fileName):resolvConfFilename(fileName){}; + + std::string resolvConfFilename; +}; + +const std::string& HostDnsServiceResolvConf::resolvConf() const +{ + return m->resolvConfFilename; +} + + +HostDnsServiceResolvConf::~HostDnsServiceResolvConf() +{ + if (m) + { + delete m; + m = NULL; + } +} + +HRESULT HostDnsServiceResolvConf::init(const char *aResolvConfFileName) +{ + m = new Data(aResolvConfFileName); + + HostDnsMonitor::init(); + + readResolvConf(); + + return S_OK; +} + + +HRESULT HostDnsServiceResolvConf::readResolvConf() +{ + struct rcp_state st; + + st.rcps_flags = RCPSF_NO_STR2IPCONV; + int rc = rcp_parse(&st, m->resolvConfFilename.c_str()); + if (rc == -1) + return S_OK; + + HostDnsInformation info; + for (unsigned i = 0; i != st.rcps_num_nameserver; ++i) + { + AssertBreak(st.rcps_str_nameserver[i]); + info.servers.push_back(st.rcps_str_nameserver[i]); + } + + if (st.rcps_domain) + info.domain = st.rcps_domain; + + for (unsigned i = 0; i != st.rcps_num_searchlist; ++i) + { + AssertBreak(st.rcps_searchlist[i]); + info.searchList.push_back(st.rcps_searchlist[i]); + } + setInfo(info); + + return S_OK; +} diff --git a/src/VBox/Main/src-server/HostImpl.cpp b/src/VBox/Main/src-server/HostImpl.cpp index 03f056c6..bb94c241 100644 --- a/src/VBox/Main/src-server/HostImpl.cpp +++ b/src/VBox/Main/src-server/HostImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2004-2012 Oracle Corporation + * Copyright (C) 2004-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,6 +30,7 @@ #endif // VBOX_WITH_USB #include "HostNetworkInterfaceImpl.h" +#include "HostVideoInputDeviceImpl.h" #include "MachineImpl.h" #include "AutoCaller.h" #include "Logging.h" @@ -54,6 +55,11 @@ # include #endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */ +#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 +# include +# include +#endif + #ifdef RT_OS_LINUX # include # include @@ -133,15 +139,17 @@ typedef SOLARISDVD *PSOLARISDVD; #include #include #include -#ifdef RT_OS_SOLARIS +#ifndef RT_OS_WINDOWS # include +#endif +#ifdef RT_OS_SOLARIS # include #endif #ifdef VBOX_WITH_HOSTNETIF_API # include "netif.h" #endif -/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */ +/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hm_svm.h */ #undef DS #undef ES #undef CS @@ -150,17 +158,22 @@ typedef SOLARISDVD *PSOLARISDVD; #undef GS #include -#include +#include #include #include #include #include #include "VBox/com/MultiResult.h" +#include "VBox/com/array.h" #include #include +#include +#include + +#include "HostDnsService.h" //////////////////////////////////////////////////////////////////////////////// // @@ -199,19 +212,24 @@ struct Host::Data /** Object with information about host drives */ VBoxMainDriveInfo hostDrives; #endif - /* Features that can be queried with GetProcessorFeature */ - BOOL fVTSupported, + /** @name Features that can be queried with GetProcessorFeature. + * @{ */ + bool fVTSupported, fLongModeSupported, fPAESupported, - fNestedPagingSupported; + fNestedPagingSupported, + fRecheckVTSupported; - /* 3D hardware acceleration supported? */ - BOOL f3DAccelerationSupported; + /** @} */ + + /** 3D hardware acceleration supported? Tristate, -1 meaning not probed. */ + int f3DAccelerationSupported; HostPowerService *pHostPowerService; + /** Host's DNS informaton fetching */ + HostDnsMonitorProxy hostDnsMonitorProxy; }; - //////////////////////////////////////////////////////////////////////////////// // // Constructor / destructor @@ -276,6 +294,8 @@ HRESULT Host::init(VirtualBox *aParent) /* Create the list of network interfaces so their metrics get registered. */ updateNetIfList(); + m->hostDnsMonitorProxy.init(HostDnsMonitor::getHostDnsMonitor(), m->pParent); + #if defined (RT_OS_WINDOWS) m->pHostPowerService = new HostPowerServiceWin(m->pParent); #elif defined (RT_OS_DARWIN) @@ -289,100 +309,104 @@ HRESULT Host::init(VirtualBox *aParent) m->fLongModeSupported = false; m->fPAESupported = false; m->fNestedPagingSupported = false; + m->fRecheckVTSupported = false; if (ASMHasCpuId()) { - uint32_t u32FeaturesECX; - uint32_t u32Dummy; - uint32_t u32FeaturesEDX; - uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32ExtFeatureEDX, u32ExtFeatureECX; - - ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX); - ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX); - /* Query Extended features. */ - ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32ExtFeatureECX, &u32ExtFeatureEDX); - - m->fLongModeSupported = !!(u32ExtFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE); - m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE); - - if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX - && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX - && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX - ) + /* Note! This code is duplicated in SUPDrv.c and other places! */ + uint32_t uMaxId, uVendorEBX, uVendorECX, uVendorEDX; + ASMCpuId(0, &uMaxId, &uVendorEBX, &uVendorECX, &uVendorEDX); + if (ASMIsValidStdRange(uMaxId)) { - /* Intel. */ - if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) - ) - { - int rc = SUPR3QueryVTxSupported(); - if (RT_SUCCESS(rc)) - m->fVTSupported = true; - } - } - else - if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX - && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX - && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX - ) - { - /* AMD. */ - if ( (u32ExtFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) - ) - { - uint32_t u32SVMFeatureEDX; - - m->fVTSupported = true; + /* PAE? */ + uint32_t uDummy, fFeaturesEcx, fFeaturesEdx; + ASMCpuId(1, &uDummy, &uDummy, &fFeaturesEcx, &fFeaturesEdx); + m->fPAESupported = RT_BOOL(fFeaturesEdx & X86_CPUID_FEATURE_EDX_PAE); + + /* Long Mode? */ + uint32_t uExtMaxId, fExtFeaturesEcx, fExtFeaturesEdx; + ASMCpuId(0x80000000, &uExtMaxId, &uDummy, &uDummy, &uDummy); + ASMCpuId(0x80000001, &uDummy, &uDummy, &fExtFeaturesEcx, &fExtFeaturesEdx); + m->fLongModeSupported = ASMIsValidExtRange(uExtMaxId) + && (fExtFeaturesEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE); + +#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 /* darwin.x86 has some optimizations of 64-bit on 32-bit. */ + int f64bitCapable = 0; + size_t cbParameter = sizeof(f64bitCapable); + if (sysctlbyname("hw.cpu64bit_capable", &f64bitCapable, &cbParameter, NULL, NULL) != -1) + m->fLongModeSupported = f64bitCapable != 0; +#endif - /* Query AMD features. */ - ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX); - if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING) - m->fNestedPagingSupported = true; + /* VT-x? */ + if ( ASMIsIntelCpuEx(uVendorEBX, uVendorECX, uVendorEDX) + || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX)) + { + if ( (fFeaturesEcx & X86_CPUID_FEATURE_ECX_VMX) + && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR) + && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR) + ) + { + int rc = SUPR3QueryVTxSupported(); + if (RT_SUCCESS(rc)) + m->fVTSupported = true; + } } - } - else - if ( u32VendorEBX == X86_CPUID_VENDOR_VIA_EBX - && u32VendorECX == X86_CPUID_VENDOR_VIA_ECX - && u32VendorEDX == X86_CPUID_VENDOR_VIA_EDX - ) - { - /* VIA. */ - if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) - ) + /* AMD-V */ + else if (ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX)) { - int rc = SUPR3QueryVTxSupported(); - if (RT_SUCCESS(rc)) + if ( (fExtFeaturesEcx & X86_CPUID_AMD_FEATURE_ECX_SVM) + && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR) + && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR) + && ASMIsValidExtRange(uExtMaxId) + ) + { m->fVTSupported = true; + + /* Query AMD features. */ + if (uExtMaxId >= 0x8000000a) + { + uint32_t fSVMFeaturesEdx; + ASMCpuId(0x8000000a, &uDummy, &uDummy, &uDummy, &fSVMFeaturesEdx); + if (fSVMFeaturesEdx & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING) + m->fNestedPagingSupported = true; + } + } } } } -#if 0 /* needs testing */ + /* Check with SUPDrv if VT-x and AMD-V are really supported (may fail). */ if (m->fVTSupported) { - uint32_t u32Caps = 0; - - int rc = SUPR3QueryVTCaps(&u32Caps); + int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL); if (RT_SUCCESS(rc)) { - if (u32Caps & SUPVTCAPS_NESTED_PAGING) - m->fNestedPagingSupported = true; + uint32_t fVTCaps; + rc = SUPR3QueryVTCaps(&fVTCaps); + if (RT_SUCCESS(rc)) + { + Assert(fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)); + if (fVTCaps & SUPVTCAPS_NESTED_PAGING) + m->fNestedPagingSupported = true; + else + Assert(m->fNestedPagingSupported == false); + } + else + { + LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc)); + m->fVTSupported = m->fNestedPagingSupported = false; + } } - /* else @todo; report BIOS trouble in some way. */ + else + m->fRecheckVTSupported = true; /* Try again later when the driver is loaded. */ } -#endif - - /* Test for 3D hardware acceleration support */ - m->f3DAccelerationSupported = false; #ifdef VBOX_WITH_CROGL - m->f3DAccelerationSupported = VBoxOglIs3DAccelerationSupported(); -#endif /* VBOX_WITH_CROGL */ + /* Test for 3D hardware acceleration support later when (if ever) need. */ + m->f3DAccelerationSupported = -1; +#else + m->f3DAccelerationSupported = false; +#endif #if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) /* Extract the list of configured host-only interfaces */ @@ -547,7 +571,7 @@ static int vboxNetWinAddComponent(std::list< ComObjPtr > * HRESULT hr; int rc = VERR_GENERAL_FAILURE; - hr = pncc->GetDisplayName( &lpszName ); + hr = pncc->GetDisplayName(&lpszName); Assert(hr == S_OK); if (hr == S_OK) { @@ -640,10 +664,10 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte INetCfgBindingInterface *pBi; /* we are using the INetCfg API for getting the list of miniports */ - hr = VBoxNetCfgWinQueryINetCfg( FALSE, - VBOX_APP_NAME, - &pNc, - &lpszApp ); + hr = VBoxNetCfgWinQueryINetCfg(FALSE, + VBOX_APP_NAME, + &pNc, + &lpszApp); Assert(hr == S_OK); if (hr == S_OK) { @@ -666,24 +690,24 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte { hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp); Assert(hr == S_OK); - if ( hr == S_OK ) + if (hr == S_OK) { hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp); Assert(hr == S_OK || hr == S_FALSE); - while( hr == S_OK ) + while (hr == S_OK) { /* S_OK == enabled, S_FALSE == disabled */ if (pBp->IsEnabled() == S_OK) { hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi); Assert(hr == S_OK); - if ( hr == S_OK ) + if (hr == S_OK) { hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi); Assert(hr == S_OK); - while(hr == S_OK) + while (hr == S_OK) { - hr = pBi->GetLowerComponent( &pMpNcc ); + hr = pBi->GetLowerComponent(&pMpNcc); Assert(hr == S_OK); if (hr == S_OK) { @@ -697,7 +721,7 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte vboxNetWinAddComponent(&list, pMpNcc); } } - VBoxNetCfgWinReleaseRef( pMpNcc ); + VBoxNetCfgWinReleaseRef(pMpNcc); } VBoxNetCfgWinReleaseRef(pBi); @@ -795,6 +819,54 @@ STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDe #endif } + +/** + * This method return the list of registered name servers + */ +STDMETHODIMP Host::COMGETTER(NameServers)(ComSafeArrayOut(BSTR, aNameServers)) +{ + CheckComArgOutSafeArrayPointerValid(aNameServers); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + return m->hostDnsMonitorProxy.GetNameServers(ComSafeArrayOutArg(aNameServers)); +} + + +/** + * This method returns the domain name of the host + */ +STDMETHODIMP Host::COMGETTER(DomainName)(BSTR *aDomainName) +{ + /* XXX: note here should be synchronization with thread polling state + * changes in name resoving system on host */ + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + return m->hostDnsMonitorProxy.GetDomainName(aDomainName); +} + + +/** + * This method returns the search string. + */ +STDMETHODIMP Host::COMGETTER(SearchStrings)(ComSafeArrayOut(BSTR, aSearchStrings)) +{ + CheckComArgOutSafeArrayPointerValid(aSearchStrings); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + return m->hostDnsMonitorProxy.GetSearchStrings(ComSafeArrayOutArg(aSearchStrings)); +} + + STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters)) { #ifdef VBOX_WITH_USB @@ -865,7 +937,23 @@ STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount) CheckComArgOutPointerValid(aCount); // no locking required - return E_NOTIMPL; + *aCount = RTMpGetPresentCoreCount(); + return S_OK; +} + +/** + * Returns the number of installed physical processor cores. + * + * @returns COM status code + * @param count address of result variable + */ +STDMETHODIMP Host::COMGETTER(ProcessorOnlineCoreCount)(ULONG *aCount) +{ + CheckComArgOutPointerValid(aCount); + // no locking required + + *aCount = RTMpGetOnlineCoreCount(); + return S_OK; } /** @@ -913,34 +1001,82 @@ STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription) */ STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported) { + /* Validate input. */ CheckComArgOutPointerValid(aSupported); - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - switch (aFeature) { case ProcessorFeature_HWVirtEx: - *aSupported = m->fVTSupported; - break; - case ProcessorFeature_PAE: - *aSupported = m->fPAESupported; - break; - case ProcessorFeature_LongMode: - *aSupported = m->fLongModeSupported; - break; - case ProcessorFeature_NestedPaging: - *aSupported = m->fNestedPagingSupported; break; - default: - ReturnComNotImplemented(); + return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature); } - return S_OK; + + /* Do the job. */ + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + if ( m->fRecheckVTSupported + && ( aFeature == ProcessorFeature_HWVirtEx + || aFeature == ProcessorFeature_NestedPaging) + ) + { + alock.release(); + + /* Perhaps the driver is available now... */ + int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL); + if (RT_SUCCESS(rc)) + { + uint32_t fVTCaps; + rc = SUPR3QueryVTCaps(&fVTCaps); + + AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS); + if (RT_SUCCESS(rc)) + { + Assert(fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)); + if (fVTCaps & SUPVTCAPS_NESTED_PAGING) + m->fNestedPagingSupported = true; + else + Assert(m->fNestedPagingSupported == false); + } + else + { + LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc)); + m->fVTSupported = m->fNestedPagingSupported = true; + } + } + + alock.acquire(); + } + + switch (aFeature) + { + case ProcessorFeature_HWVirtEx: + *aSupported = m->fVTSupported; + break; + + case ProcessorFeature_PAE: + *aSupported = m->fPAESupported; + break; + + case ProcessorFeature_LongMode: + *aSupported = m->fLongModeSupported; + break; + + case ProcessorFeature_NestedPaging: + *aSupported = m->fNestedPagingSupported; + break; + + default: + AssertFailed(); + } + } + return hrc; } /** @@ -992,15 +1128,12 @@ STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize) CheckComArgOutPointerValid(aSize); // no locking required - /* @todo This is an ugly hack. There must be a function in IPRT for that. */ - pm::CollectorHAL *hal = pm::createHAL(); - if (!hal) + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) return E_FAIL; - ULONG tmp; - int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp); - *aSize /= 1024; - delete hal; - return rc; + *aSize = (ULONG)(cb / _1M); + return S_OK; } /** @@ -1014,15 +1147,12 @@ STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable) CheckComArgOutPointerValid(aAvailable); // no locking required - /* @todo This is an ugly hack. There must be a function in IPRT for that. */ - pm::CollectorHAL *hal = pm::createHAL(); - if (!hal) + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_FAILURE(rc)) return E_FAIL; - ULONG tmp; - int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable); - *aAvailable /= 1024; - delete hal; - return rc; + *aAvailable = (ULONG)(cb / _1M); + return S_OK; } /** @@ -1101,17 +1231,33 @@ STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported) { CheckComArgOutPointerValid(aSupported); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->f3DAccelerationSupported != -1) + *aSupported = m->f3DAccelerationSupported; + else + { + alock.release(); +#ifdef VBOX_WITH_CROGL + bool fSupported = VBoxOglIs3DAccelerationSupported(); +#else + bool fSupported = false; /* shoudn't get here, but just in case. */ +#endif + AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS); + m->f3DAccelerationSupported = fSupported; + alock2.release(); - *aSupported = m->f3DAccelerationSupported; + *aSupported = fSupported; + } + } #ifdef DEBUG_misha AssertMsgFailed(("should not be here any more!\n")); #endif - return S_OK; + return hrc; } STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface, @@ -1433,7 +1579,7 @@ STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterfac #ifndef VBOX_WITH_HOSTNETIF_API return E_NOTIMPL; #else - if (Guid(id).isEmpty()) + if (!Guid(id).isValid()) return E_INVALIDARG; if (!networkInterface) return E_POINTER; @@ -1537,7 +1683,7 @@ STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId, IHostUSBDevice **aDevice) { #ifdef VBOX_WITH_USB - CheckComArgExpr(aId, Guid (aId).isEmpty() == false); + CheckComArgExpr(aId, Guid (aId).isValid()); CheckComArgOutPointerValid(aDevice); *aDevice = NULL; @@ -1578,6 +1724,34 @@ STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress) return S_OK; } +/** + * Returns a list of host video capture devices (webcams, etc). + * + * @returns COM status code + * @param aVideoInputDevices Array of interface pointers to be filled. + */ +STDMETHODIMP Host::COMGETTER(VideoInputDevices)(ComSafeArrayOut(IHostVideoInputDevice*, aVideoInputDevices)) +{ + if (ComSafeArrayOutIsNull(aVideoInputDevices)) + return E_POINTER; + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + HostVideoInputDeviceList list; + + HRESULT hr = HostVideoInputDevice::queryHostDevices(m->pParent, &list); + + if (SUCCEEDED(hr)) + { + SafeIfaceArray devices(list); + devices.detachTo(ComSafeArrayOutArg(aVideoInputDevices)); + } + + return hr; +} + // public methods only for internal purposes //////////////////////////////////////////////////////////////////////////////// @@ -1868,7 +2042,7 @@ HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType, AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); Guid uuid(strNameOrId); - if (!uuid.isEmpty()) + if (uuid.isValid() && !uuid.isZero()) return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium); // string is not a syntactically valid UUID: try a name then @@ -2228,7 +2402,7 @@ static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg) { char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath); if ( pszSlice && !strcmp(pszSlice, "s2") - && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */ + && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */ { /* * We've got a fully qualified DVD drive. Add it to the list. @@ -2680,9 +2854,9 @@ void Host::parseMountTable(char *mountTable, std::list< ComObjPtr > &lis { // skip devices we are not interested in if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap) - (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices) - strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev) - strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs) + (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs (i.e. /devices) + strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev) + strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs) { char *rawDevName = getfullrawname((char *)mountName); if (validateDevice(rawDevName, true)) @@ -2834,7 +3008,9 @@ HRESULT Host::updateNetIfList() /* Make a copy as the original may be partially destroyed later. */ listCopy = list; HostNetworkInterfaceList::iterator itOld, itNew; +# ifdef VBOX_WITH_RESOURCE_USAGE_API PerformanceCollector *aCollector = m->pParent->performanceCollector(); +# endif for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld) { bool fGone = true; @@ -2852,7 +3028,11 @@ HRESULT Host::updateNetIfList() } } if (fGone) + { +# ifdef VBOX_WITH_RESOURCE_USAGE_API (*itOld)->unregisterMetrics(aCollector, this); +# endif + } } /* * Need to set the references to VirtualBox object in all interface objects @@ -2872,7 +3052,11 @@ HRESULT Host::updateNetIfList() LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw())); } else if (t == HostNetworkInterfaceType_Bridged) + { +# ifdef VBOX_WITH_RESOURCE_USAGE_API (*itNew)->registerMetrics(aCollector, this); +# endif + } } m->llNetIfs = list; return S_OK; @@ -2928,17 +3112,17 @@ void Host::registerDiskMetrics(PerformanceCollector *aCollector) new pm::AggregateMax())); /* For now we are concerned with the root file system only. */ - pm::DiskList disks; - int rc = pm::getDiskListByFs("/", disks); - if (RT_FAILURE(rc) || disks.empty()) + pm::DiskList disksUsage, disksLoad; + int rc = hal->getDiskListByFs("/", disksUsage, disksLoad); + if (RT_FAILURE(rc)) return; pm::DiskList::iterator it; - for (it = disks.begin(); it != disks.end(); ++it) + for (it = disksLoad.begin(); it != disksLoad.end(); ++it) { - Utf8StrFmt strName("Disk/%s/Load", it->c_str()); - pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Util", + Utf8StrFmt strName("Disk/%s", it->c_str()); + pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util", "Percentage of time disk was busy serving I/O requests."); - pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName, + pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load", *it, fsLoadUtil); aCollector->registerBaseMetric (fsLoad); @@ -2950,6 +3134,23 @@ void Host::registerDiskMetrics(PerformanceCollector *aCollector) aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, new pm::AggregateMax())); } + for (it = disksUsage.begin(); it != disksUsage.end(); ++it) + { + Utf8StrFmt strName("Disk/%s", it->c_str()); + pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total", + "Disk size."); + pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage", + *it, fsUsageTotal); + aCollector->registerBaseMetric (fsUsage); + + aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0)); + aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, + new pm::AggregateAvg())); + aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, + new pm::AggregateMin())); + aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, + new pm::AggregateMax())); + } } void Host::registerMetrics(PerformanceCollector *aCollector) @@ -3094,6 +3295,8 @@ void Host::unregisterMetrics (PerformanceCollector *aCollector) aCollector->unregisterBaseMetricsFor(this); } +#endif /* VBOX_WITH_RESOURCE_USAGE_API */ + /* static */ void Host::generateMACAddress(Utf8Str &mac) @@ -3109,6 +3312,4 @@ void Host::generateMACAddress(Utf8Str &mac) guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]); } -#endif /* VBOX_WITH_RESOURCE_USAGE_API */ - /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp b/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp index 1eeef5b5..58c5fd3b 100644 --- a/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp +++ b/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,8 +21,10 @@ #include "AutoCaller.h" #include "Logging.h" #include "netif.h" -#include "Performance.h" -#include "PerformanceImpl.h" +#ifdef VBOX_WITH_RESOURCE_USAGE_API +# include "Performance.h" +# include "PerformanceImpl.h" +#endif #include @@ -69,7 +71,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG aInterfaceName.raw(), aGuid.toString().c_str())); ComAssertRet(!aInterfaceName.isEmpty(), E_INVALIDARG); - ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG); + ComAssertRet(aGuid.isValid(), E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -77,6 +79,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG unconst(mInterfaceName) = aInterfaceName; unconst(mNetworkName) = composeNetworkName(aShortName); + unconst(mShortName) = aShortName; unconst(mGuid) = aGuid; mIfType = ifType; @@ -86,22 +89,36 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Bstr aShortName, Guid aG return S_OK; } +#ifdef VBOX_WITH_RESOURCE_USAGE_API + void HostNetworkInterface::registerMetrics(PerformanceCollector *aCollector, ComPtr objptr) { LogFlowThisFunc(("mShortName={%ls}, mInterfaceName={%ls}, mGuid={%s}, mSpeedMbits=%u\n", mShortName.raw(), mInterfaceName.raw(), mGuid.toString().c_str(), m.speedMbits)); pm::CollectorHAL *hal = aCollector->getHAL(); /* Create sub metrics */ - Utf8StrFmt strName("Net/%ls/Load", mShortName.raw()); - pm::SubMetric *networkLoadRx = new pm::SubMetric(strName + "/Rx", + Utf8StrFmt strName("Net/%ls", mShortName.raw()); + pm::SubMetric *networkLoadRx = new pm::SubMetric(strName + "/Load/Rx", "Percentage of network interface receive bandwidth used."); - pm::SubMetric *networkLoadTx = new pm::SubMetric(strName + "/Tx", + pm::SubMetric *networkLoadTx = new pm::SubMetric(strName + "/Load/Tx", "Percentage of network interface transmit bandwidth used."); + pm::SubMetric *networkLinkSpeed = new pm::SubMetric(strName + "/LinkSpeed", + "Physical link speed."); /* Create and register base metrics */ - pm::BaseMetric *networkLoad = new pm::HostNetworkLoadRaw(hal, objptr, strName, Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLoadRx, networkLoadTx); + pm::BaseMetric *networkSpeed = new pm::HostNetworkSpeed(hal, objptr, strName + "/LinkSpeed", Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLinkSpeed); + aCollector->registerBaseMetric(networkSpeed); + pm::BaseMetric *networkLoad = new pm::HostNetworkLoadRaw(hal, objptr, strName + "/Load", Utf8Str(mShortName), Utf8Str(mInterfaceName), m.speedMbits, networkLoadRx, networkLoadTx); aCollector->registerBaseMetric(networkLoad); + aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed, 0)); + aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed, + new pm::AggregateAvg())); + aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed, + new pm::AggregateMin())); + aCollector->registerMetric(new pm::Metric(networkSpeed, networkLinkSpeed, + new pm::AggregateMax())); + aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx, 0)); aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx, new pm::AggregateAvg())); @@ -123,11 +140,13 @@ void HostNetworkInterface::unregisterMetrics(PerformanceCollector *aCollector, C { LogFlowThisFunc(("mShortName={%ls}, mInterfaceName={%ls}, mGuid={%s}\n", mShortName.raw(), mInterfaceName.raw(), mGuid.toString().c_str())); - Utf8StrFmt name("Net/%ls/Load", mShortName.raw()); + Utf8StrFmt name("Net/%ls", mShortName.raw()); aCollector->unregisterMetricsFor(objptr, name + "/*"); aCollector->unregisterBaseMetricsFor(objptr, name); } +#endif /* VBOX_WITH_RESOURCE_USAGE_API */ + #ifdef VBOX_WITH_HOSTNETIF_API HRESULT HostNetworkInterface::updateConfig() @@ -172,7 +191,7 @@ HRESULT HostNetworkInterface::init(Bstr aInterfaceName, HostNetworkInterfaceType // aInterfaceName.raw(), aGuid.toString().raw())); // ComAssertRet(aInterfaceName, E_INVALIDARG); -// ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG); +// ComAssertRet(aGuid.isValid(), E_INVALIDARG); ComAssertRet(pIf, E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ @@ -236,6 +255,24 @@ STDMETHODIMP HostNetworkInterface::COMGETTER(Name)(BSTR *aInterfaceName) return S_OK; } +/** + * Returns the short name of the host network interface. + * + * @returns COM status code + * @param aShortName address of result pointer + */ +STDMETHODIMP HostNetworkInterface::COMGETTER(ShortName)(BSTR *aShortName) +{ + CheckComArgOutPointerValid(aShortName); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + mShortName.cloneTo(aShortName); + + return S_OK; +} + /** * Returns the GUID of the host network interface. * diff --git a/src/VBox/Main/src-server/HostPower.cpp b/src/VBox/Main/src-server/HostPower.cpp index 830729a0..3146a7ae 100644 --- a/src/VBox/Main/src-server/HostPower.cpp +++ b/src/VBox/Main/src-server/HostPower.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,10 +26,11 @@ #include #include "VirtualBoxImpl.h" +#include "MachineImpl.h" #include -HostPowerService::HostPowerService (VirtualBox *aVirtualBox) +HostPowerService::HostPowerService(VirtualBox *aVirtualBox) { Assert(aVirtualBox != NULL); mVirtualBox = aVirtualBox; @@ -39,18 +40,18 @@ HostPowerService::~HostPowerService() { } -void HostPowerService::notify(HostPowerEvent aEvent) +void HostPowerService::notify(Reason_T aReason) { SessionMachinesList machines; VirtualBox::InternalControlList controls; HRESULT rc = S_OK; - switch (aEvent) + switch (aReason) { - case HostPowerEvent_Suspend: + case Reason_HostSuspend: { - LogFunc (("SUSPEND\n")); + LogFunc(("HOST SUSPEND\n")); #ifdef VBOX_WITH_RESOURCE_USAGE_API /* Suspend performance sampling to avoid unnecessary callbacks due to jumps in time. */ @@ -68,49 +69,41 @@ void HostPowerService::notify(HostPowerEvent aEvent) { ComPtr pControl = *it; - /* get the remote console */ - ComPtr console; - rc = pControl->GetRemoteConsole(console.asOutParam()); - /* the VM could have been powered down and closed or whatever */ - if (FAILED(rc)) - continue; - - /* note that Pause() will simply return a failure if the VM is - * in an inappropriate state */ - rc = console->Pause(); + /* PauseWithReason() will simply return a failure if + * the VM is in an inappropriate state */ + rc = pControl->PauseWithReason(Reason_HostSuspend); if (FAILED(rc)) continue; /* save the control to un-pause the VM later */ - mConsoles.push_back(console); + mSessionControls.push_back(pControl); } - LogFunc (("Suspended %d VMs\n", mConsoles.size())); - + LogRel(("Host suspending: Paused %d VMs\n", mSessionControls.size())); break; } - case HostPowerEvent_Resume: + case Reason_HostResume: { - LogFunc (("RESUME\n")); + LogFunc(("HOST RESUME\n")); size_t resumed = 0; /* go through VMs we paused on Suspend */ - for (size_t i = 0; i < mConsoles.size(); ++i) + for (size_t i = 0; i < mSessionControls.size(); ++i) { /* note that Resume() will simply return a failure if the VM is * in an inappropriate state (it will also fail if the VM has * been somehow closed by this time already so that the * console reference we have is dead) */ - rc = mConsoles[i]->Resume(); + rc = mSessionControls[i]->ResumeWithReason(Reason_HostResume); if (FAILED(rc)) continue; - ++ resumed; + ++resumed; } - LogFunc (("Resumed %d VMs\n", resumed)); + LogRel(("Host resumed: Resumed %d VMs\n", resumed)); #ifdef VBOX_WITH_RESOURCE_USAGE_API /* Resume the performance sampling. */ @@ -120,60 +113,87 @@ void HostPowerService::notify(HostPowerEvent aEvent) perfcollector->resumeSampling(); #endif - mConsoles.clear(); - + mSessionControls.clear(); break; } - case HostPowerEvent_BatteryLow: + case Reason_HostBatteryLow: { - LogFunc (("BATTERY LOW\n")); + LogFunc(("BATTERY LOW\n")); - mVirtualBox->getOpenedMachines(machines, &controls); + Bstr value; + rc = mVirtualBox->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(), + value.asOutParam()); + int fGlobal = 0; + if (SUCCEEDED(rc) && !value.isEmpty()) + { + if (value != "0") + fGlobal = 1; + else if (value == "0") + fGlobal = -1; + } + mVirtualBox->getOpenedMachines(machines, &controls); size_t saved = 0; /* save running VMs */ + SessionMachinesList::const_iterator it2 = machines.begin(); for (VirtualBox::InternalControlList::const_iterator it = controls.begin(); - it != controls.end(); - ++it) + it != controls.end() && it2 != machines.end(); + ++it, ++it2) { - ComPtr pControl = *it; - /* get the remote console */ - ComPtr console; - rc = pControl->GetRemoteConsole (console.asOutParam()); - /* the VM could have been powered down and closed or whatever */ - if (FAILED(rc)) - continue; - - ComPtr progress; - - /* note that SaveState() will simply return a failure if the VM - * is in an inappropriate state */ - rc = console->SaveState (progress.asOutParam()); - if (FAILED(rc)) - continue; - - /* Wait until the operation has been completed. */ - rc = progress->WaitForCompletion(-1); - if (SUCCEEDED(rc)) + ComPtr pMachine = *it2; + rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(), + value.asOutParam()); + int fPerVM = 0; + if (SUCCEEDED(rc) && !value.isEmpty()) { - LONG iRc; - progress->COMGETTER(ResultCode)(&iRc); - rc = iRc; + /* per-VM overrides global */ + if (value != "0") + fPerVM = 2; + else if (value == "0") + fPerVM = -2; } - AssertMsg (SUCCEEDED(rc), ("SaveState WaitForCompletion " - "failed with %Rhrc (%#08X)\n", rc, rc)); - - if (SUCCEEDED(rc)) - ++ saved; + /* default is true */ + if (fGlobal + fPerVM >= 0) + { + ComPtr pControl = *it; + ComPtr progress; + + /* note that SaveStateWithReason() will simply return a failure + * if the VM is in an inappropriate state */ + rc = pControl->SaveStateWithReason(Reason_HostBatteryLow, progress.asOutParam()); + if (FAILED(rc)) + { + LogRel(("SaveState '%s' failed with %Rhrc\n", pMachine->getName().c_str(), rc)); + continue; + } + + /* Wait until the operation has been completed. */ + rc = progress->WaitForCompletion(-1); + if (SUCCEEDED(rc)) + { + LONG iRc; + progress->COMGETTER(ResultCode)(&iRc); + rc = iRc; + } + + AssertMsg(SUCCEEDED(rc), ("SaveState WaitForCompletion failed with %Rhrc (%#08X)\n", rc, rc)); + + if (SUCCEEDED(rc)) + { + LogRel(("SaveState '%s' succeeded\n", pMachine->getName().c_str())); + ++saved; + } + } } - - LogFunc (("Saved %d VMs\n", saved)); - + LogRel(("Battery Low: saved %d VMs\n", saved)); break; } + + default: + /* nothing */; } } /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp b/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp new file mode 100644 index 00000000..1e7a53d2 --- /dev/null +++ b/src/VBox/Main/src-server/HostVideoInputDeviceImpl.cpp @@ -0,0 +1,235 @@ +/* $Id: HostVideoInputDeviceImpl.cpp $ */ +/** @file + * + * Host video capture device implementation. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "HostVideoInputDeviceImpl.h" +#include "Logging.h" +#include "VirtualBoxImpl.h" +#ifdef VBOX_WITH_EXTPACK +# include "ExtPackManagerImpl.h" +#endif + +#include +#include + +#include + +/* + * HostVideoInputDevice implementation. + */ +DEFINE_EMPTY_CTOR_DTOR(HostVideoInputDevice) + +HRESULT HostVideoInputDevice::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void HostVideoInputDevice::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + +/* + * Initializes the instance. + */ +HRESULT HostVideoInputDevice::init(const com::Utf8Str &name, const com::Utf8Str &path, const com::Utf8Str &alias) +{ + LogFlowThisFunc(("\n")); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m.name = name; + m.path = path; + m.alias = alias; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + +/* + * Uninitializes the instance. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void HostVideoInputDevice::uninit() +{ + LogFlowThisFunc(("\n")); + + m.name.setNull(); + m.path.setNull(); + m.alias.setNull(); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; +} + +static HRESULT hostVideoInputDeviceAdd(HostVideoInputDeviceList *pList, + const com::Utf8Str &name, + const com::Utf8Str &path, + const com::Utf8Str &alias) +{ + ComObjPtr obj; + HRESULT hr = obj.createObject(); + if (SUCCEEDED(hr)) + { + hr = obj->init(name, path, alias); + if (SUCCEEDED(hr)) + pList->push_back(obj); + } + return hr; +} + +static DECLCALLBACK(int) hostWebcamAdd(void *pvUser, + const char *pszName, + const char *pszPath, + const char *pszAlias, + uint64_t *pu64Result) +{ + HostVideoInputDeviceList *pList = (HostVideoInputDeviceList *)pvUser; + HRESULT hr = hostVideoInputDeviceAdd(pList, pszName, pszPath, pszAlias); + if (FAILED(hr)) + { + *pu64Result = (uint64_t)hr; + return VERR_NOT_SUPPORTED; + } + return VINF_SUCCESS; +} + +/** @todo These typedefs must be in a header. */ +typedef DECLCALLBACK(int) FNVBOXHOSTWEBCAMADD(void *pvUser, + const char *pszName, + const char *pszPath, + const char *pszAlias, + uint64_t *pu64Result); +typedef FNVBOXHOSTWEBCAMADD *PFNVBOXHOSTWEBCAMADD; + +typedef DECLCALLBACK(int) FNVBOXHOSTWEBCAMLIST(PFNVBOXHOSTWEBCAMADD pfnWebcamAdd, + void *pvUser, + uint64_t *pu64WebcamAddResult); +typedef FNVBOXHOSTWEBCAMLIST *PFNVBOXHOSTWEBCAMLIST; + +static int loadHostWebcamLibrary(const char *pszPath, RTLDRMOD *phmod, PFNVBOXHOSTWEBCAMLIST *ppfn) +{ + int rc = VINF_SUCCESS; + RTLDRMOD hmod = NIL_RTLDRMOD; + + RTERRINFOSTATIC ErrInfo; + RTErrInfoInitStatic(&ErrInfo); + if (RTPathHavePath(pszPath)) + rc = SUPR3HardenedLdrLoadPlugIn(pszPath, &hmod, &ErrInfo.Core); + else + rc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(rc)) + { + static const char *pszSymbol = "VBoxHostWebcamList"; + rc = RTLdrGetSymbol(hmod, pszSymbol, (void **)ppfn); + + if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND) + LogRel(("Resolving symbol '%s': %Rrc\n", pszSymbol, rc)); + } + else + { + LogRel(("Loading the library '%s': %Rrc\n", pszPath, rc)); + if (RTErrInfoIsSet(&ErrInfo.Core)) + LogRel((" %s\n", ErrInfo.Core.pszMsg)); + + hmod = NIL_RTLDRMOD; + } + + if (RT_SUCCESS(rc)) + { + *phmod = hmod; + } + else + { + if (hmod != NIL_RTLDRMOD) + { + RTLdrClose(hmod); + hmod = NIL_RTLDRMOD; + } + } + + return rc; +} + +static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack"); + +static HRESULT fillDeviceList(VirtualBox *pVirtualBox, HostVideoInputDeviceList *pList) +{ + HRESULT hr; + Utf8Str strLibrary; + +#ifdef VBOX_WITH_EXTPACK + ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager(); + hr = pExtPackMgr->getLibraryPathForExtPack("VBoxHostWebcam", &strExtPackPuel, &strLibrary); +#else + hr = E_NOTIMPL; +#endif + + if (SUCCEEDED(hr)) + { + PFNVBOXHOSTWEBCAMLIST pfn = NULL; + RTLDRMOD hmod = NIL_RTLDRMOD; + int rc = loadHostWebcamLibrary(strLibrary.c_str(), &hmod, &pfn); + + LogRel(("Load [%s] rc %Rrc\n", strLibrary.c_str(), rc)); + + if (RT_SUCCESS(rc)) + { + uint64_t u64Result = S_OK; + rc = pfn(hostWebcamAdd, pList, &u64Result); + Log(("VBoxHostWebcamList rc %Rrc, result 0x%08X\n", rc, u64Result)); + if (RT_FAILURE(rc)) + { + hr = (HRESULT)u64Result; + } + + RTLdrClose(hmod); + hmod = NIL_RTLDRMOD; + } + + if (SUCCEEDED(hr)) + { + if (RT_FAILURE(rc)) + hr = pVirtualBox->setError(VBOX_E_IPRT_ERROR, + "Failed to get webcam list: %Rrc", rc); + } + } + + return hr; +} + +/* static */ HRESULT HostVideoInputDevice::queryHostDevices(VirtualBox *pVirtualBox, HostVideoInputDeviceList *pList) +{ + HRESULT hr = fillDeviceList(pVirtualBox, pList); + + if (FAILED(hr)) + { + pList->clear(); + } + + return hr; +} + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp index 2ffa9b51..d7905917 100644 --- a/src/VBox/Main/src-server/MachineImpl.cpp +++ b/src/VBox/Main/src-server/MachineImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2004-2012 Oracle Corporation + * Copyright (C) 2004-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,23 +23,17 @@ # define __STDC_CONSTANT_MACROS #endif -#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER -# include -# include -# include -# include -# include -#endif - #include "Logging.h" #include "VirtualBoxImpl.h" #include "MachineImpl.h" +#include "ClientToken.h" #include "ProgressImpl.h" #include "ProgressProxyImpl.h" #include "MediumAttachmentImpl.h" #include "MediumImpl.h" #include "MediumLock.h" #include "USBControllerImpl.h" +#include "USBDeviceFiltersImpl.h" #include "HostImpl.h" #include "SharedFolderImpl.h" #include "GuestOSTypeImpl.h" @@ -48,9 +42,9 @@ #include "StorageControllerImpl.h" #include "DisplayImpl.h" #include "DisplayUtils.h" -#include "BandwidthControlImpl.h" #include "MachineImplCloneVM.h" #include "AutostartDb.h" +#include "SystemPropertiesImpl.h" // generated header #include "VBoxEvents.h" @@ -73,6 +67,7 @@ #include /* xml::XmlFileWriter::s_psz*Suff. */ #include #include +#include #include #include @@ -161,14 +156,18 @@ Machine::HWData::HWData() mCPUHotPlugEnabled = false; mMemoryBalloonSize = 0; mPageFusionEnabled = false; + mGraphicsControllerType = GraphicsControllerType_VBoxVGA; mVRAMSize = 8; mAccelerate3DEnabled = false; mAccelerate2DVideoEnabled = false; mMonitorCount = 1; - mVideoCaptureFile = "Test.webm"; - mVideoCaptureWidth = 640; - mVideoCaptureHeight = 480; - mVideoCaptureEnabled = true; + mVideoCaptureWidth = 1024; + mVideoCaptureHeight = 768; + mVideoCaptureRate = 512; + mVideoCaptureFPS = 25; + mVideoCaptureEnabled = false; + for (unsigned i = 0; i < RT_ELEMENTS(maVideoCaptureScreens); i++) + maVideoCaptureScreens[i] = true; mHWVirtExEnabled = true; mHWVirtExNestedPagingEnabled = true; @@ -179,18 +178,16 @@ Machine::HWData::HWData() mHWVirtExLargePagesEnabled = false; #endif mHWVirtExVPIDEnabled = true; + mHWVirtExUXEnabled = true; mHWVirtExForceEnabled = false; -#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) - mHWVirtExExclusive = false; -#else - mHWVirtExExclusive = true; -#endif #if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN) mPAEEnabled = true; #else mPAEEnabled = false; #endif + mLongMode = HC_ARCH_BITS == 64 ? settings::Hardware::LongMode_Enabled : settings::Hardware::LongMode_Disabled; mSyntheticCpu = false; + mTripleFaultReset = false; mHPETEnabled = false; /* default boot order: floppy - DVD - HDD */ @@ -243,13 +240,15 @@ Machine::MediaData::~MediaData() // constructor / destructor ///////////////////////////////////////////////////////////////////////////// -Machine::Machine() - : mCollectorGuest(NULL), - mPeer(NULL), - mParent(NULL), - mSerialPorts(), - mParallelPorts(), - uRegistryNeedsSaving(0) +Machine::Machine() : +#ifdef VBOX_WITH_RESOURCE_USAGE_API + mCollectorGuest(NULL), +#endif + mPeer(NULL), + mParent(NULL), + mSerialPorts(), + mParallelPorts(), + uRegistryNeedsSaving(0) {} Machine::~Machine() @@ -349,6 +348,10 @@ HRESULT Machine::init(VirtualBox *aParent, /* Apply serial port defaults */ for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); ++slot) mSerialPorts[slot]->applyDefaults(aOsType); + + /* Let the OS type select 64-bit ness. */ + mHWData->mLongMode = aOsType->is64Bit() + ? settings::Hardware::LongMode_Enabled : settings::Hardware::LongMode_Disabled; } /* At this point the changing of the current state modification @@ -568,6 +571,10 @@ HRESULT Machine::init(VirtualBox *aParent, autoInitSpan.setSucceeded(); else { + /* Ignore all errors from unregistering, they would destroy + * the more interesting error information we already have, + * pinpointing the issue with the VM config. */ + ErrorInfoKeeper eik; autoInitSpan.setLimited(); // uninit media from this machine's media registry, or else @@ -684,7 +691,7 @@ HRESULT Machine::registeredInit() { AssertReturn(!isSessionMachine(), E_FAIL); AssertReturn(!isSnapshotMachine(), E_FAIL); - AssertReturn(!mData->mUuid.isEmpty(), E_FAIL); + AssertReturn(mData->mUuid.isValid(), E_FAIL); AssertReturn(!mData->mAccessible, E_FAIL); HRESULT rc = initDataAndChildObjects(); @@ -853,7 +860,8 @@ void Machine::uninit() * "cannot be closed because it is still attached to 1 virtual machines" * because at this point we did not call uninitDataAndChildObjects() yet * and therefore also removeBackReference() for all these mediums was not called! */ - if (!uuidMachine.isEmpty()) // can be empty if we're called from a failure of Machine::init + + if (uuidMachine.isValid() && !uuidMachine.isZero()) // can be empty if we're called from a failure of Machine::init mParent->unregisterMachineMedia(uuidMachine); // has machine been modified? @@ -898,6 +906,10 @@ STDMETHODIMP Machine::COMGETTER(Accessible)(BOOL *aAccessible) LogFlowThisFunc(("ENTER\n")); + /* In some cases (medium registry related), it is necessary to be able to + * go through the list of all machines. Happens when an inaccessible VM + * has a sensible medium registry. */ + AutoReadLock mllock(mParent->getMachinesListLockHandle() COMMA_LOCKVAL_SRC_POS); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); HRESULT rc = S_OK; @@ -999,8 +1011,9 @@ STDMETHODIMP Machine::COMSETTER(Name)(IN_BSTR aName) // prohibit setting a UUID only as the machine name, or else it can // never be found by findMachine() Guid test(aName); - if (test.isNotEmpty()) - return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name")); + + if (test.isValid()) + return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name")); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -1274,8 +1287,8 @@ STDMETHODIMP Machine::COMSETTER(ChipsetType)(ChipsetType_T aChipsetType) // Resize network adapter array, to be finalized on commit/rollback. // We must not throw away entries yet, otherwise settings are lost // without a way to roll back. - uint32_t newCount = Global::getMaxNetworkAdapters(aChipsetType); - uint32_t oldCount = mNetworkAdapters.size(); + size_t newCount = Global::getMaxNetworkAdapters(aChipsetType); + size_t oldCount = mNetworkAdapters.size(); if (newCount > oldCount) { mNetworkAdapters.resize(newCount); @@ -1337,7 +1350,7 @@ STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - if (!mHWData->mHardwareUUID.isEmpty()) + if (!mHWData->mHardwareUUID.isZero()) mHWData->mHardwareUUID.toUtf16().cloneTo(aUUID); else mData->mUuid.toUtf16().cloneTo(aUUID); @@ -1348,7 +1361,7 @@ STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID) STDMETHODIMP Machine::COMSETTER(HardwareUUID)(IN_BSTR aUUID) { Guid hardwareUUID(aUUID); - if (hardwareUUID.isEmpty()) + if (!hardwareUUID.isValid()) return E_INVALIDARG; AutoCaller autoCaller(this); @@ -1500,7 +1513,7 @@ STDMETHODIMP Machine::COMSETTER(CPUExecutionCap)(ULONG aExecutionCap) mHWData.backup(); mHWData->mCpuExecutionCap = aExecutionCap; - /* Save settings if online - todo why is this required?? */ + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ if (Global::IsOnline(mData->mMachineState)) saveSettings(NULL); @@ -1508,21 +1521,21 @@ STDMETHODIMP Machine::COMSETTER(CPUExecutionCap)(ULONG aExecutionCap) } -STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *aEnabled) { - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mCPUHotPlugEnabled; + *aEnabled = mHWData->mCPUHotPlugEnabled; return S_OK; } -STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled) +STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL aEnabled) { HRESULT rc = S_OK; @@ -1534,9 +1547,9 @@ STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled) rc = checkStateDependency(MutableStateDep); if (FAILED(rc)) return rc; - if (mHWData->mCPUHotPlugEnabled != enabled) + if (mHWData->mCPUHotPlugEnabled != aEnabled) { - if (enabled) + if (aEnabled) { setModified(IsModified_MachineData); mHWData.backup(); @@ -1575,31 +1588,31 @@ STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled) } } - mHWData->mCPUHotPlugEnabled = enabled; + mHWData->mCPUHotPlugEnabled = aEnabled; return rc; } -STDMETHODIMP Machine::COMGETTER(EmulatedUSBCardReaderEnabled)(BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(EmulatedUSBCardReaderEnabled)(BOOL *aEnabled) { #ifdef VBOX_WITH_USB_CARDREADER - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mEmulatedUSBCardReaderEnabled; + *aEnabled = mHWData->mEmulatedUSBCardReaderEnabled; return S_OK; #else - NOREF(enabled); + NOREF(aEnabled); return E_NOTIMPL; #endif } -STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL enabled) +STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL aEnabled) { #ifdef VBOX_WITH_USB_CARDREADER AutoCaller autoCaller(this); @@ -1611,41 +1624,29 @@ STDMETHODIMP Machine::COMSETTER(EmulatedUSBCardReaderEnabled)(BOOL enabled) setModified(IsModified_MachineData); mHWData.backup(); - mHWData->mEmulatedUSBCardReaderEnabled = enabled; + mHWData->mEmulatedUSBCardReaderEnabled = aEnabled; return S_OK; #else - NOREF(enabled); + NOREF(aEnabled); return E_NOTIMPL; #endif } -STDMETHODIMP Machine::COMGETTER(EmulatedUSBWebcameraEnabled)(BOOL *enabled) -{ - NOREF(enabled); - return E_NOTIMPL; -} - -STDMETHODIMP Machine::COMSETTER(EmulatedUSBWebcameraEnabled)(BOOL enabled) -{ - NOREF(enabled); - return E_NOTIMPL; -} - -STDMETHODIMP Machine::COMGETTER(HPETEnabled)(BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(HPETEnabled)(BOOL *aEnabled) { - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mHPETEnabled; + *aEnabled = mHWData->mHPETEnabled; return S_OK; } -STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL enabled) +STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL aEnabled) { HRESULT rc = S_OK; @@ -1659,12 +1660,12 @@ STDMETHODIMP Machine::COMSETTER(HPETEnabled)(BOOL enabled) setModified(IsModified_MachineData); mHWData.backup(); - mHWData->mHPETEnabled = enabled; + mHWData->mHPETEnabled = aEnabled; return rc; } -STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL * fEnabled) +STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL *fEnabled) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -1675,23 +1676,102 @@ STDMETHODIMP Machine::COMGETTER(VideoCaptureEnabled)(BOOL * fEnabled) return S_OK; } -STDMETHODIMP Machine::COMSETTER(VideoCaptureEnabled)(BOOL fEnabled) +STDMETHODIMP Machine::COMSETTER(VideoCaptureEnabled)(BOOL fEnabled) { + HRESULT rc = S_OK; + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + setModified(IsModified_MachineData); + mHWData.backup(); mHWData->mVideoCaptureEnabled = fEnabled; + + alock.release(); + rc = onVideoCaptureChange(); + alock.acquire(); + if (FAILED(rc)) + { + /* + * Normally we would do the actual change _after_ onVideoCaptureChange() succeeded. + * We cannot do this because that function uses Machine::GetVideoCaptureEnabled to + * determine if it should start or stop capturing. Therefore we need to manually + * undo change. + */ + mHWData->mVideoCaptureEnabled = mHWData.backedUpData()->mVideoCaptureEnabled; + return rc; + } + + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ + if (Global::IsOnline(mData->mMachineState)) + saveSettings(NULL); + + return rc; +} + +STDMETHODIMP Machine::COMGETTER(VideoCaptureScreens)(ComSafeArrayOut(BOOL, aScreens)) +{ + CheckComArgOutSafeArrayPointerValid(aScreens); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + SafeArray screens(mHWData->mMonitorCount); + for (unsigned i = 0; i < screens.size(); i++) + screens[i] = mHWData->maVideoCaptureScreens[i]; + screens.detachTo(ComSafeArrayOutArg(aScreens)); + return S_OK; +} + +STDMETHODIMP Machine::COMSETTER(VideoCaptureScreens)(ComSafeArrayIn(BOOL, aScreens)) +{ + SafeArray screens(ComSafeArrayInArg(aScreens)); + AssertReturn(screens.size() <= RT_ELEMENTS(mHWData->maVideoCaptureScreens), E_INVALIDARG); + bool fChanged = false; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + for (unsigned i = 0; i < screens.size(); i++) + { + if (mHWData->maVideoCaptureScreens[i] != RT_BOOL(screens[i])) + { + mHWData->maVideoCaptureScreens[i] = RT_BOOL(screens[i]); + fChanged = true; + } + } + if (fChanged) + { + alock.release(); + HRESULT rc = onVideoCaptureChange(); + alock.acquire(); + if (FAILED(rc)) return rc; + setModified(IsModified_MachineData); + + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ + if (Global::IsOnline(mData->mMachineState)) + saveSettings(NULL); + } + return S_OK; } -STDMETHODIMP Machine::COMGETTER(VideoCaptureFile)(BSTR * apFile) +STDMETHODIMP Machine::COMGETTER(VideoCaptureFile)(BSTR *apFile) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mHWData->mVideoCaptureFile.cloneTo(apFile); + if (mHWData->mVideoCaptureFile.isEmpty()) + { + Utf8Str defaultFile; + getDefaultVideoCaptureFile(defaultFile); + defaultFile.cloneTo(apFile); + } + else + mHWData->mVideoCaptureFile.cloneTo(apFile); return S_OK; } @@ -1702,54 +1782,181 @@ STDMETHODIMP Machine::COMSETTER(VideoCaptureFile)(IN_BSTR aFile) if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if(strFile.isEmpty()) - strFile = "VideoCap.webm"; + + if ( Global::IsOnline(mData->mMachineState) + && mHWData->mVideoCaptureEnabled) + return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled")); + + if (!RTPathStartsWithRoot(strFile.c_str())) + return setError(E_INVALIDARG, tr("Video capture file name '%s' is not absolute"), strFile.c_str()); + + if (!strFile.isEmpty()) + { + Utf8Str defaultFile; + getDefaultVideoCaptureFile(defaultFile); + if (!RTPathCompare(strFile.c_str(), defaultFile.c_str())) + strFile.setNull(); + } + + setModified(IsModified_MachineData); + mHWData.backup(); mHWData->mVideoCaptureFile = strFile; + + return S_OK; +} + +STDMETHODIMP Machine::COMGETTER(VideoCaptureWidth)(ULONG *aHorzRes) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + *aHorzRes = mHWData->mVideoCaptureWidth; + return S_OK; +} + +STDMETHODIMP Machine::COMSETTER(VideoCaptureWidth)(ULONG aHorzRes) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if ( Global::IsOnline(mData->mMachineState) + && mHWData->mVideoCaptureEnabled) + return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled")); + + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mVideoCaptureWidth = aHorzRes; + + return S_OK; +} + +STDMETHODIMP Machine::COMGETTER(VideoCaptureHeight)(ULONG *aVertRes) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + *aVertRes = mHWData->mVideoCaptureHeight; return S_OK; } +STDMETHODIMP Machine::COMSETTER(VideoCaptureHeight)(ULONG aVertRes) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if ( Global::IsOnline(mData->mMachineState) + && mHWData->mVideoCaptureEnabled) + return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled")); + + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mVideoCaptureHeight = aVertRes; + + return S_OK; +} -STDMETHODIMP Machine::COMGETTER(VideoCaptureWidth)(ULONG *ulHorzRes) +STDMETHODIMP Machine::COMGETTER(VideoCaptureRate)(ULONG *aRate) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *ulHorzRes = mHWData->mVideoCaptureWidth; + *aRate = mHWData->mVideoCaptureRate; return S_OK; } -STDMETHODIMP Machine::COMSETTER(VideoCaptureWidth)(ULONG ulHorzRes) +STDMETHODIMP Machine::COMSETTER(VideoCaptureRate)(ULONG aRate) { AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) - { - LogFlow(("Autolocked failed\n")); - return autoCaller.rc(); - } + if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - mHWData->mVideoCaptureWidth = ulHorzRes; + + if ( Global::IsOnline(mData->mMachineState) + && mHWData->mVideoCaptureEnabled) + return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled")); + + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mVideoCaptureRate = aRate; + return S_OK; } -STDMETHODIMP Machine::COMGETTER(VideoCaptureHeight)(ULONG *ulVertRes) +STDMETHODIMP Machine::COMGETTER(VideoCaptureFPS)(ULONG *aFPS) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *ulVertRes = mHWData->mVideoCaptureHeight; + *aFPS = mHWData->mVideoCaptureFPS; + return S_OK; +} + +STDMETHODIMP Machine::COMSETTER(VideoCaptureFPS)(ULONG aFPS) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if ( Global::IsOnline(mData->mMachineState) + && mHWData->mVideoCaptureEnabled) + return setError(E_INVALIDARG, tr("Cannot change parameters while capturing is enabled")); + + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mVideoCaptureFPS = aFPS; + return S_OK; } -STDMETHODIMP Machine::COMSETTER(VideoCaptureHeight)(ULONG ulVertRes) +STDMETHODIMP Machine::COMGETTER(GraphicsControllerType)(GraphicsControllerType_T *aGraphicsControllerType) { + CheckComArgOutPointerValid(aGraphicsControllerType); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mHWData->mVideoCaptureHeight = ulVertRes; + + *aGraphicsControllerType = mHWData->mGraphicsControllerType; + + return S_OK; +} + +STDMETHODIMP Machine::COMSETTER(GraphicsControllerType)(GraphicsControllerType_T aGraphicsControllerType) +{ + switch (aGraphicsControllerType) + { + case GraphicsControllerType_Null: + case GraphicsControllerType_VBoxVGA: +#ifdef VBOX_WITH_VMSVGA + case GraphicsControllerType_VMSVGA: +#endif + break; + default: + return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType); + } + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = checkStateDependency(MutableStateDep); + if (FAILED(rc)) return rc; + + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mGraphicsControllerType = aGraphicsControllerType; + return S_OK; } @@ -1838,20 +2045,20 @@ STDMETHODIMP Machine::COMSETTER(MemoryBalloonSize)(ULONG memoryBalloonSize) #endif } -STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *aEnabled) { - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mPageFusionEnabled; + *aEnabled = mHWData->mPageFusionEnabled; return S_OK; } -STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL enabled) +STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL aEnabled) { #ifdef VBOX_WITH_PAGE_SHARING AutoCaller autoCaller(this); @@ -1862,24 +2069,24 @@ STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL enabled) /** @todo must support changes for running vms and keep this in sync with IGuest. */ setModified(IsModified_MachineData); mHWData.backup(); - mHWData->mPageFusionEnabled = enabled; + mHWData->mPageFusionEnabled = aEnabled; return S_OK; #else - NOREF(enabled); + NOREF(aEnabled); return setError(E_NOTIMPL, tr("Page fusion is only supported on 64-bit hosts")); #endif } -STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *aEnabled) { - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mAccelerate3DEnabled; + *aEnabled = mHWData->mAccelerate3DEnabled; return S_OK; } @@ -1904,16 +2111,16 @@ STDMETHODIMP Machine::COMSETTER(Accelerate3DEnabled)(BOOL enable) } -STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *enabled) +STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *aEnabled) { - CheckComArgOutPointerValid(enabled); + CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *enabled = mHWData->mAccelerate2DVideoEnabled; + *aEnabled = mHWData->mAccelerate2DVideoEnabled; return S_OK; } @@ -1996,18 +2203,55 @@ STDMETHODIMP Machine::GetCPUProperty(CPUPropertyType_T property, BOOL *aVal) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - switch(property) + switch (property) { - case CPUPropertyType_PAE: - *aVal = mHWData->mPAEEnabled; - break; + case CPUPropertyType_PAE: + *aVal = mHWData->mPAEEnabled; + break; - case CPUPropertyType_Synthetic: - *aVal = mHWData->mSyntheticCpu; - break; + case CPUPropertyType_Synthetic: + *aVal = mHWData->mSyntheticCpu; + break; - default: - return E_INVALIDARG; + case CPUPropertyType_LongMode: + if (mHWData->mLongMode == settings::Hardware::LongMode_Enabled) + *aVal = TRUE; + else if (mHWData->mLongMode == settings::Hardware::LongMode_Disabled) + *aVal = FALSE; +#if HC_ARCH_BITS == 64 + else + *aVal = TRUE; +#else + else + { + *aVal = FALSE; + + ComPtr ptrGuestOSType; + HRESULT hrc2 = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(), ptrGuestOSType.asOutParam()); + if (SUCCEEDED(hrc2)) + { + BOOL fIs64Bit = FALSE; + hrc2 = ptrGuestOSType->COMGETTER(Is64Bit)(&fIs64Bit); AssertComRC(hrc2); + if (SUCCEEDED(hrc2) && fIs64Bit) + { + ComObjPtr ptrHost = mParent->host(); + alock.release(); + + hrc2 = ptrHost->GetProcessorFeature(ProcessorFeature_LongMode, aVal); AssertComRC(hrc2); + if (FAILED(hrc2)) + *aVal = FALSE; + } + } + } +#endif + break; + + case CPUPropertyType_TripleFaultReset: + *aVal = mHWData->mTripleFaultReset; + break; + + default: + return E_INVALIDARG; } return S_OK; } @@ -2022,22 +2266,34 @@ STDMETHODIMP Machine::SetCPUProperty(CPUPropertyType_T property, BOOL aVal) HRESULT rc = checkStateDependency(MutableStateDep); if (FAILED(rc)) return rc; - switch(property) + switch (property) { - case CPUPropertyType_PAE: - setModified(IsModified_MachineData); - mHWData.backup(); - mHWData->mPAEEnabled = !!aVal; - break; + case CPUPropertyType_PAE: + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mPAEEnabled = !!aVal; + break; - case CPUPropertyType_Synthetic: - setModified(IsModified_MachineData); - mHWData.backup(); - mHWData->mSyntheticCpu = !!aVal; - break; + case CPUPropertyType_Synthetic: + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mSyntheticCpu = !!aVal; + break; - default: - return E_INVALIDARG; + case CPUPropertyType_LongMode: + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mLongMode = !aVal ? settings::Hardware::LongMode_Disabled : settings::Hardware::LongMode_Enabled; + break; + + case CPUPropertyType_TripleFaultReset: + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mTripleFaultReset = !!aVal; + break; + + default: + return E_INVALIDARG; } return S_OK; } @@ -2259,10 +2515,6 @@ STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL *aVal = mHWData->mHWVirtExEnabled; break; - case HWVirtExPropertyType_Exclusive: - *aVal = mHWData->mHWVirtExExclusive; - break; - case HWVirtExPropertyType_VPID: *aVal = mHWData->mHWVirtExVPIDEnabled; break; @@ -2271,6 +2523,10 @@ STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL *aVal = mHWData->mHWVirtExNestedPagingEnabled; break; + case HWVirtExPropertyType_UnrestrictedExecution: + *aVal = mHWData->mHWVirtExUXEnabled; + break; + case HWVirtExPropertyType_LargePages: *aVal = mHWData->mHWVirtExLargePagesEnabled; #if defined(DEBUG_bird) && defined(RT_OS_LINUX) /* This feature is deadly here */ @@ -2306,12 +2562,6 @@ STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL mHWData->mHWVirtExEnabled = !!aVal; break; - case HWVirtExPropertyType_Exclusive: - setModified(IsModified_MachineData); - mHWData.backup(); - mHWData->mHWVirtExExclusive = !!aVal; - break; - case HWVirtExPropertyType_VPID: setModified(IsModified_MachineData); mHWData.backup(); @@ -2324,6 +2574,12 @@ STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL mHWData->mHWVirtExNestedPagingEnabled = !!aVal; break; + case HWVirtExPropertyType_UnrestrictedExecution: + setModified(IsModified_MachineData); + mHWData.backup(); + mHWData->mHWVirtExUXEnabled = !!aVal; + break; + case HWVirtExPropertyType_LargePages: setModified(IsModified_MachineData); mHWData.backup(); @@ -2444,10 +2700,40 @@ STDMETHODIMP Machine::COMGETTER(AudioAdapter)(IAudioAdapter **audioAdapter) return S_OK; } -STDMETHODIMP Machine::COMGETTER(USBController)(IUSBController **aUSBController) +STDMETHODIMP Machine::COMGETTER(USBControllers)(ComSafeArrayOut(IUSBController *, aUSBControllers)) +{ +#ifdef VBOX_WITH_VUSB + CheckComArgOutPointerValid(aUSBControllers); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + clearError(); + MultiResult rc(S_OK); + +# ifdef VBOX_WITH_USB + rc = mParent->host()->checkUSBProxyService(); + if (FAILED(rc)) return rc; +# endif + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + SafeIfaceArray ctrls(*mUSBControllers.data()); + ctrls.detachTo(ComSafeArrayOutArg(aUSBControllers)); + return S_OK; +#else + /* Note: The GUI depends on this method returning E_NOTIMPL with no + * extended error info to indicate that USB is simply not available + * (w/o treating it as a failure), for example, as in OSE */ + NOREF(aUSBControllers); + ReturnComNotImplemented(); +#endif /* VBOX_WITH_VUSB */ +} + +STDMETHODIMP Machine::COMGETTER(USBDeviceFilters)(IUSBDeviceFilters **aUSBDeviceFilters) { #ifdef VBOX_WITH_VUSB - CheckComArgOutPointerValid(aUSBController); + CheckComArgOutPointerValid(aUSBDeviceFilters); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2462,12 +2748,12 @@ STDMETHODIMP Machine::COMGETTER(USBController)(IUSBController **aUSBController) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - return rc = mUSBController.queryInterfaceTo(aUSBController); + return rc = mUSBDeviceFilters.queryInterfaceTo(aUSBDeviceFilters); #else /* Note: The GUI depends on this method returning E_NOTIMPL with no * extended error info to indicate that USB is simply not available * (w/o treating it as a failure), for example, as in OSE */ - NOREF(aUSBController); + NOREF(aUSBDeviceFilters); ReturnComNotImplemented(); #endif /* VBOX_WITH_VUSB */ } @@ -2685,8 +2971,7 @@ STDMETHODIMP Machine::COMGETTER(ClipboardMode)(ClipboardMode_T *aClipboardMode) return S_OK; } -STDMETHODIMP -Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode) +STDMETHODIMP Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode) { HRESULT rc = S_OK; @@ -2704,7 +2989,7 @@ Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode) mHWData.backup(); mHWData->mClipboardMode = aClipboardMode; - /* Save settings if online - todo why is this required?? */ + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ if (Global::IsOnline(mData->mMachineState)) saveSettings(NULL); @@ -2725,8 +3010,7 @@ STDMETHODIMP Machine::COMGETTER(DragAndDropMode)(DragAndDropMode_T *aDragAndDrop return S_OK; } -STDMETHODIMP -Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode) +STDMETHODIMP Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode) { HRESULT rc = S_OK; @@ -2744,15 +3028,14 @@ Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode) mHWData.backup(); mHWData->mDragAndDropMode = aDragAndDropMode; - /* Save settings if online - todo why is this required?? */ + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ if (Global::IsOnline(mData->mMachineState)) saveSettings(NULL); return S_OK; } -STDMETHODIMP -Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns) +STDMETHODIMP Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns) { CheckComArgOutPointerValid(aPatterns); @@ -2773,8 +3056,7 @@ Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns) return S_OK; } -STDMETHODIMP -Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns) +STDMETHODIMP Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2790,8 +3072,7 @@ Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns) return rc; } -STDMETHODIMP -Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aStorageControllers)) +STDMETHODIMP Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aStorageControllers)) { CheckComArgOutSafeArrayPointerValid(aStorageControllers); @@ -2806,8 +3087,7 @@ Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aSt return S_OK; } -STDMETHODIMP -Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled) +STDMETHODIMP Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled) { CheckComArgOutPointerValid(aEnabled); @@ -3301,7 +3581,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, if (FAILED(rc)) // the failure may occur w/o any error info (from RPC), so provide one return setError(VBOX_E_VM_ERROR, - tr("Failed to get a console object from the direct session (%Rrc)"), rc); + tr("Failed to get a console object from the direct session (%Rhrc)"), rc); ComAssertRet(!pConsoleW.isNull(), E_FAIL); @@ -3313,7 +3593,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, if (FAILED(rc)) // the failure may occur w/o any error info (from RPC), so provide one return setError(VBOX_E_VM_ERROR, - tr("Failed to assign the machine to the session (%Rrc)"), rc); + tr("Failed to assign the machine to the session (%Rhrc)"), rc); alock.acquire(); // need to revalidate the state after acquiring the lock again @@ -3354,7 +3634,18 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, if (fLaunchingVMProcess) { - // this machine is awaiting for a spawning session to be opened: + if (mData->mSession.mPID == NIL_RTPROCESS) + { + // two or more clients racing for a lock, the one which set the + // session state to Spawning will win, the others will get an + // error as we can't decide here if waiting a little would help + // (only for shared locks this would avoid an error) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("The machine '%s' already has a lock request pending"), + mUserData->s.strName.c_str()); + } + + // this machine is awaiting for a spawning session to be opened: // then the calling process must be the one that got started by // LaunchVMProcess() @@ -3390,6 +3681,19 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, SessionState_T origState = mData->mSession.mState; mData->mSession.mState = SessionState_Spawning; +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + /* Get the client token ID to be passed to the client process */ + Utf8Str strTokenId; + sessionMachine->getTokenId(strTokenId); + Assert(!strTokenId.isEmpty()); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + /* Get the client token to be passed to the client process */ + ComPtr pToken(sessionMachine->getToken()); + /* The token is now "owned" by pToken, fix refcount */ + if (!pToken.isNull()) + pToken->Release(); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + /* * Release the lock before calling the client process -- it will call * Machine/SessionMachine methods. Releasing the lock here is quite safe @@ -3403,13 +3707,19 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, alock.release(); LogFlowThisFunc(("Calling AssignMachine()...\n")); - rc = pSessionControl->AssignMachine(sessionMachine, lockType); +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + rc = pSessionControl->AssignMachine(sessionMachine, lockType, Bstr(strTokenId).raw()); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + rc = pSessionControl->AssignMachine(sessionMachine, lockType, pToken); + /* Now the token is owned by the client process. */ + pToken.setNull(); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ LogFlowThisFunc(("AssignMachine() returned %08X\n", rc)); /* The failure may occur w/o any error info (from RPC), so provide one */ if (FAILED(rc)) setError(VBOX_E_VM_ERROR, - tr("Failed to assign the machine to the session (%Rrc)"), rc); + tr("Failed to assign the machine to the session (%Rhrc)"), rc); if ( SUCCEEDED(rc) && fLaunchingVMProcess @@ -3442,7 +3752,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, /* The failure may occur w/o any error info (from RPC), so provide one */ if (FAILED(rc)) setError(VBOX_E_VM_ERROR, - tr("Failed to assign the machine to the remote session (%Rrc)"), rc); + tr("Failed to assign the machine to the remote session (%Rhrc)"), rc); } if (FAILED(rc)) @@ -3470,7 +3780,7 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, { /* Close the remote session, remove the remote control from the list * and reset session state to Closed (@note keep the code in sync - * with the relevant part in openSession()). */ + * with the relevant part in checkForSpawnFailure()). */ Assert(mData->mSession.mRemoteControls.size() == 1); if (mData->mSession.mRemoteControls.size() == 1) @@ -3535,28 +3845,52 @@ STDMETHODIMP Machine::LockMachine(ISession *aSession, * @note Locks objects! */ STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession, - IN_BSTR aType, + IN_BSTR aFrontend, IN_BSTR aEnvironment, IProgress **aProgress) { - CheckComArgStrNotEmptyOrNull(aType); - Utf8Str strType(aType); + CheckComArgStr(aFrontend); + Utf8Str strFrontend(aFrontend); Utf8Str strEnvironment(aEnvironment); /* "emergencystop" doesn't need the session, so skip the checks/interface * retrieval. This code doesn't quite fit in here, but introducing a * special API method would be even more effort, and would require explicit * support by every API client. It's better to hide the feature a bit. */ - if (strType != "emergencystop") + if (strFrontend != "emergencystop") CheckComArgNotNull(aSession); CheckComArgOutPointerValid(aProgress); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - ComPtr control; HRESULT rc = S_OK; + if (strFrontend.isEmpty()) + { + Bstr bstrFrontend; + rc = COMGETTER(DefaultFrontend)(bstrFrontend.asOutParam()); + if (FAILED(rc)) + return rc; + strFrontend = bstrFrontend; + if (strFrontend.isEmpty()) + { + ComPtr systemProperties; + rc = mParent->COMGETTER(SystemProperties)(systemProperties.asOutParam()); + if (FAILED(rc)) + return rc; + rc = systemProperties->COMGETTER(DefaultFrontend)(bstrFrontend.asOutParam()); + if (FAILED(rc)) + return rc; + strFrontend = bstrFrontend; + } + /* paranoia - emergencystop is not a valid default */ + if (strFrontend == "emergencystop") + strFrontend = Utf8Str::Empty; + } + /* default frontend: Qt GUI */ + if (strFrontend.isEmpty()) + strFrontend = "GUI/Qt"; - if (strType != "emergencystop") + if (strFrontend != "emergencystop") { /* check the session state */ SessionState_T state; @@ -3569,21 +3903,18 @@ STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession, tr("The given session is busy")); /* get the IInternalSessionControl interface */ - control = aSession; + ComPtr control(aSession); ComAssertMsgRet(!control.isNull(), ("No IInternalSessionControl interface"), E_INVALIDARG); - } - /* get the teleporter enable state for the progress object init. */ - BOOL fTeleporterEnabled; - rc = COMGETTER(TeleporterEnabled)(&fTeleporterEnabled); - if (FAILED(rc)) - return rc; + /* get the teleporter enable state for the progress object init. */ + BOOL fTeleporterEnabled; + rc = COMGETTER(TeleporterEnabled)(&fTeleporterEnabled); + if (FAILED(rc)) + return rc; - /* create a progress object */ - if (strType != "emergencystop") - { + /* create a progress object */ ComObjPtr progress; progress.createObject(); rc = progress->init(mParent, @@ -3591,13 +3922,13 @@ STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession, Bstr(tr("Starting VM")).raw(), TRUE /* aCancelable */, fTeleporterEnabled ? 20 : 10 /* uTotalOperationsWeight */, - BstrFmt(tr("Creating process for virtual machine \"%s\" (%s)"), mUserData->s.strName.c_str(), strType.c_str()).raw(), + BstrFmt(tr("Creating process for virtual machine \"%s\" (%s)"), mUserData->s.strName.c_str(), strFrontend.c_str()).raw(), 2 /* uFirstOperationWeight */, fTeleporterEnabled ? 3 : 1 /* cOtherProgressObjectOperations */); if (SUCCEEDED(rc)) { - rc = launchVMProcess(control, strType, strEnvironment, progress); + rc = launchVMProcess(control, strFrontend, strEnvironment, progress); if (SUCCEEDED(rc)) { progress.queryInterfaceTo(aProgress); @@ -3725,9 +4056,18 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName, tr("Could not get type of controller '%ls'"), aControllerName); + bool fSilent = false; + Utf8Str strReconfig; + + /* Check whether the flag to allow silent storage attachment reconfiguration is set. */ + strReconfig = getExtraData(Utf8Str("VBoxInternal2/SilentReconfigureWhilePaused")); + if ( mData->mMachineState == MachineState_Paused + && strReconfig == "1") + fSilent = true; + /* Check that the controller can do hotplugging if we detach the device while the VM is running. */ bool fHotplug = false; - if (Global::IsOnlineOrTransient(mData->mMachineState)) + if (!fSilent && Global::IsOnlineOrTransient(mData->mMachineState)) fHotplug = true; if (fHotplug && !isControllerHotplugCapable(ctrlType)) @@ -3834,6 +4174,46 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName, /* the simplest case: restore the whole attachment * and return, nothing else to do */ mMediaData->mAttachments.push_back(pAttachTemp); + + /* Reattach the medium to the VM. */ + if (fHotplug || fSilent) + { + mediumLock.release(); + treeLock.release(); + alock.release(); + + MediumLockList *pMediumLockList(new MediumLockList()); + + rc = medium->createMediumLockList(true /* fFailIfInaccessible */, + true /* fMediumLockWrite */, + NULL, + *pMediumLockList); + alock.acquire(); + if (FAILED(rc)) + delete pMediumLockList; + else + { + mData->mSession.mLockedMedia.Unlock(); + alock.release(); + rc = mData->mSession.mLockedMedia.Insert(pAttachTemp, pMediumLockList); + mData->mSession.mLockedMedia.Lock(); + alock.acquire(); + } + alock.release(); + + if (SUCCEEDED(rc)) + { + rc = onStorageDeviceChange(pAttachTemp, FALSE /* aRemove */, fSilent); + /* Remove lock list in case of error. */ + if (FAILED(rc)) + { + mData->mSession.mLockedMedia.Unlock(); + mData->mSession.mLockedMedia.Remove(pAttachTemp); + mData->mSession.mLockedMedia.Lock(); + } + } + } + return S_OK; } @@ -3893,6 +4273,46 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName, /* the simplest case: restore the whole attachment * and return, nothing else to do */ mMediaData->mAttachments.push_back(*it); + + /* Reattach the medium to the VM. */ + if (fHotplug || fSilent) + { + mediumLock.release(); + treeLock.release(); + alock.release(); + + MediumLockList *pMediumLockList(new MediumLockList()); + + rc = medium->createMediumLockList(true /* fFailIfInaccessible */, + true /* fMediumLockWrite */, + NULL, + *pMediumLockList); + alock.acquire(); + if (FAILED(rc)) + delete pMediumLockList; + else + { + mData->mSession.mLockedMedia.Unlock(); + alock.release(); + rc = mData->mSession.mLockedMedia.Insert(pAttachTemp, pMediumLockList); + mData->mSession.mLockedMedia.Lock(); + alock.acquire(); + } + alock.release(); + + if (SUCCEEDED(rc)) + { + rc = onStorageDeviceChange(pAttachTemp, FALSE /* aRemove */, fSilent); + /* Remove lock list in case of error. */ + if (FAILED(rc)) + { + mData->mSession.mLockedMedia.Unlock(); + mData->mSession.mLockedMedia.Remove(pAttachTemp); + mData->mSession.mLockedMedia.Lock(); + } + } + } + return S_OK; } else if ( foundIt == oldAtts.end() @@ -4098,6 +4518,7 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName, false /* fTempEject */, false /* fNonRotational */, false /* fDiscard */, + false /* fHotPluggable */, Utf8Str::Empty); if (FAILED(rc)) return rc; @@ -4126,8 +4547,42 @@ STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName, treeLock.release(); alock.release(); - if (fHotplug) - rc = onStorageDeviceChange(attachment, FALSE /* aRemove */); + if (fHotplug || fSilent) + { + if (!medium.isNull()) + { + MediumLockList *pMediumLockList(new MediumLockList()); + + rc = medium->createMediumLockList(true /* fFailIfInaccessible */, + true /* fMediumLockWrite */, + NULL, + *pMediumLockList); + alock.acquire(); + if (FAILED(rc)) + delete pMediumLockList; + else + { + mData->mSession.mLockedMedia.Unlock(); + alock.release(); + rc = mData->mSession.mLockedMedia.Insert(attachment, pMediumLockList); + mData->mSession.mLockedMedia.Lock(); + alock.acquire(); + } + alock.release(); + } + + if (SUCCEEDED(rc)) + { + rc = onStorageDeviceChange(attachment, FALSE /* aRemove */, fSilent); + /* Remove lock list in case of error. */ + if (FAILED(rc)) + { + mData->mSession.mLockedMedia.Unlock(); + mData->mSession.mLockedMedia.Remove(attachment); + mData->mSession.mLockedMedia.Lock(); + } + } + } mParent->saveModifiedRegistries(); @@ -4164,9 +4619,18 @@ STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort tr("Could not get type of controller '%ls'"), aControllerName); + bool fSilent = false; + Utf8Str strReconfig; + + /* Check whether the flag to allow silent storage attachment reconfiguration is set. */ + strReconfig = getExtraData(Utf8Str("VBoxInternal2/SilentReconfigureWhilePaused")); + if ( mData->mMachineState == MachineState_Paused + && strReconfig == "1") + fSilent = true; + /* Check that the controller can do hotplugging if we detach the device while the VM is running. */ bool fHotplug = false; - if (Global::IsOnlineOrTransient(mData->mMachineState)) + if (!fSilent && Global::IsOnlineOrTransient(mData->mMachineState)) fHotplug = true; if (fHotplug && !isControllerHotplugCapable(ctrlType)) @@ -4187,10 +4651,10 @@ STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort * The VM has to detach the device before we delete any implicit diffs. * If this fails we can roll back without loosing data. */ - if (fHotplug) + if (fHotplug || fSilent) { alock.release(); - rc = onStorageDeviceChange(pAttach, TRUE /* aRemove */); + rc = onStorageDeviceChange(pAttach, TRUE /* aRemove */, fSilent); alock.acquire(); } if (FAILED(rc)) return rc; @@ -4386,6 +4850,58 @@ STDMETHODIMP Machine::SetAutoDiscardForDevice(IN_BSTR aControllerName, LONG aCon return S_OK; } +STDMETHODIMP Machine::SetHotPluggableForDevice(IN_BSTR aControllerName, LONG aControllerPort, + LONG aDevice, BOOL aHotPluggable) +{ + CheckComArgStrNotEmptyOrNull(aControllerName); + + LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aHotPluggable=%d\n", + aControllerName, aControllerPort, aDevice, aHotPluggable)); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = checkStateDependency(MutableStateDep); + if (FAILED(rc)) return rc; + + AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL); + + if (Global::IsOnlineOrTransient(mData->mMachineState)) + return setError(VBOX_E_INVALID_VM_STATE, + tr("Invalid machine state: %s"), + Global::stringifyMachineState(mData->mMachineState)); + + MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments, + aControllerName, + aControllerPort, + aDevice); + if (!pAttach) + return setError(VBOX_E_OBJECT_NOT_FOUND, + tr("No storage device attached to device slot %d on port %d of controller '%ls'"), + aDevice, aControllerPort, aControllerName); + + /** @todo remove this blocker and add the missing code to support this + * flag properly in all code areas, with proper support checks below. */ + return setError(VBOX_E_NOT_SUPPORTED, + tr("Controller '%ls' does not support changing the hot-pluggable device flag"), + aControllerName); + + setModified(IsModified_Storage); + mMediaData.backup(); + + AutoWriteLock attLock(pAttach COMMA_LOCKVAL_SRC_POS); + + if (pAttach->getType() == DeviceType_Floppy) + return setError(E_INVALIDARG, + tr("Setting the hot-pluggable device flag rejected as the device attached to device slot %d on port %d of controller '%ls' is a floppy drive"), + aDevice, aControllerPort, aControllerName); + pAttach->updateHotPluggable(!!aHotPluggable); + + return S_OK; +} + STDMETHODIMP Machine::SetNoBandwidthGroupForDevice(IN_BSTR aControllerName, LONG aControllerPort, LONG aDevice) { @@ -4833,6 +5349,18 @@ STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue) return S_OK; } +STDMETHODIMP Machine::SetSettingsFilePath(IN_BSTR aFilePath, IProgress **aProgress) +{ + CheckComArgStrNotEmptyOrNull(aFilePath); + CheckComArgOutPointerValid(aProgress); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *aProgress = NULL; + ReturnComNotImplemented(); +} + STDMETHODIMP Machine::SaveSettings() { AutoCaller autoCaller(this); @@ -5024,7 +5552,7 @@ struct Machine::DeleteTask ComObjPtr pProgress; }; -STDMETHODIMP Machine::Delete(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress) +STDMETHODIMP Machine::DeleteConfig(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress) { LogFlowFuncEnter(); @@ -5169,7 +5697,7 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task) if (FAILED(rc)) throw rc; rc = task.pProgress->WaitForAsyncProgressCompletion(pProgress2); if (FAILED(rc)) throw rc; - /* Check the result of the asynchrony process. */ + /* Check the result of the asynchronous process. */ LONG iRc; rc = pProgress2->COMGETTER(ResultCode)(&iRc); if (FAILED(rc)) throw rc; @@ -5177,6 +5705,15 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task) * retrieve the error info from there, or it'll be lost. */ if (FAILED(iRc)) throw setError(ProgressErrorInfo(pProgress2)); + + /* Close the medium, deliberately without checking the return + * code, and without leaving any trace in the error info, as + * a failure here is a very minor issue, which shouldn't happen + * as above we even managed to delete the medium. */ + { + ErrorInfoKeeper eik; + pMedium->Close(); + } } setMachineState(oldState); alock.acquire(); @@ -5292,7 +5829,7 @@ STDMETHODIMP Machine::FindSnapshot(IN_BSTR aNameOrId, ISnapshot **aSnapshot) else { Guid uuid(aNameOrId); - if (!uuid.isEmpty()) + if (uuid.isValid()) rc = findSnapshotById(uuid, pSnapshot, true /* aSetError */); else rc = findSnapshotByName(Utf8Str(aNameOrId), pSnapshot, true /* aSetError */); @@ -5441,21 +5978,17 @@ HRESULT Machine::getGuestPropertyFromService(IN_BSTR aName, AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); Utf8Str strName(aName); - HWData::GuestPropertyList::const_iterator it; + HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.find(strName); - for (it = mHWData->mGuestProperties.begin(); - it != mHWData->mGuestProperties.end(); ++it) + if (it != mHWData->mGuestProperties.end()) { - if (it->strName == strName) - { - char szFlags[MAX_FLAGS_LEN + 1]; - it->strValue.cloneTo(aValue); - *aTimestamp = it->mTimestamp; - writeFlags(it->mFlags, szFlags); - Bstr(szFlags).cloneTo(aFlags); - break; - } + char szFlags[MAX_FLAGS_LEN + 1]; + it->second.strValue.cloneTo(aValue); + *aTimestamp = it->second.mTimestamp; + writeFlags(it->second.mFlags, szFlags); + Bstr(szFlags).cloneTo(aFlags); } + return S_OK; } @@ -5477,6 +6010,9 @@ HRESULT Machine::getGuestPropertyFromVM(IN_BSTR aName, /* fail if we were called after #OnSessionEnd() is called. This is a * silly race condition. */ + /** @todo This code is bothering API clients (like python script clients) with + * the AccessGuestProperty call, creating unncessary IPC. Need to + * have a way of figuring out which kind of direct session it is... */ if (!directControl) rc = E_ACCESSDENIED; else @@ -5536,9 +6072,6 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue, AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); HRESULT rc = S_OK; - HWData::GuestProperty property; - property.mFlags = NILFLAG; - bool found = false; rc = checkStateDependency(MutableStateDep); if (FAILED(rc)) return rc; @@ -5548,64 +6081,59 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue, Utf8Str utf8Name(aName); Utf8Str utf8Flags(aFlags); uint32_t fFlags = NILFLAG; - if ( (aFlags != NULL) - && RT_FAILURE(validateFlags(utf8Flags.c_str(), &fFlags)) - ) + if ( aFlags != NULL + && RT_FAILURE(validateFlags(utf8Flags.c_str(), &fFlags))) return setError(E_INVALIDARG, - tr("Invalid flag values: '%ls'"), + tr("Invalid guest property flag values: '%ls'"), aFlags); - /** @todo r=bird: see efficiency rant in PushGuestProperty. (Yeah, I - * know, this is simple and do an OK job atm.) */ - HWData::GuestPropertyList::iterator it; - for (it = mHWData->mGuestProperties.begin(); - it != mHWData->mGuestProperties.end(); ++it) - if (it->strName == utf8Name) - { - property = *it; - if (it->mFlags & (RDONLYHOST)) - rc = setError(E_ACCESSDENIED, - tr("The property '%ls' cannot be changed by the host"), - aName); - else - { - setModified(IsModified_MachineData); - mHWData.backup(); // @todo r=dj backup in a loop?!? - - /* The backup() operation invalidates our iterator, so - * get a new one. */ - for (it = mHWData->mGuestProperties.begin(); - it->strName != utf8Name; - ++it) - ; - mHWData->mGuestProperties.erase(it); - } - found = true; - break; - } - if (found && SUCCEEDED(rc)) + bool fDelete = !RT_VALID_PTR(aValue) || *(aValue) == '\0'; + HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.find(utf8Name); + if (it == mHWData->mGuestProperties.end()) { - if (aValue) + if (!fDelete) { + setModified(IsModified_MachineData); + mHWData.backupEx(); + RTTIMESPEC time; - property.strValue = aValue; - property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time)); - if (aFlags != NULL) - property.mFlags = fFlags; - mHWData->mGuestProperties.push_back(property); + HWData::GuestProperty prop; + prop.strValue = aValue; + prop.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time)); + prop.mFlags = fFlags; + mHWData->mGuestProperties[Utf8Str(aName)] = prop; } } - else if (SUCCEEDED(rc) && aValue) + else { - RTTIMESPEC time; - setModified(IsModified_MachineData); - mHWData.backup(); - property.strName = aName; - property.strValue = aValue; - property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time)); - property.mFlags = fFlags; - mHWData->mGuestProperties.push_back(property); + if (it->second.mFlags & (RDONLYHOST)) + { + rc = setError(E_ACCESSDENIED, + tr("The property '%ls' cannot be changed by the host"), + aName); + } + else + { + setModified(IsModified_MachineData); + mHWData.backupEx(); + + /* The backupEx() operation invalidates our iterator, + * so get a new one. */ + it = mHWData->mGuestProperties.find(utf8Name); + Assert(it != mHWData->mGuestProperties.end()); + + if (!fDelete) + { + RTTIMESPEC time; + it->second.strValue = aValue; + it->second.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time)); + it->second.mFlags = fFlags; + } + else + mHWData->mGuestProperties.erase(it); + } } + if ( SUCCEEDED(rc) && ( mHWData->mGuestPropertyNotificationPatterns.isEmpty() || RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.c_str(), @@ -5616,8 +6144,8 @@ HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue, ) ) { - /** @todo r=bird: Why aren't we leaving the lock here? The - * same code in PushGuestProperty does... */ + alock.release(); + mParent->onGuestPropertyChange(mData->mUuid, aName, aValue ? aValue : Bstr("").raw(), aFlags ? aFlags : Bstr("").raw()); @@ -5651,8 +6179,7 @@ HRESULT Machine::setGuestPropertyToVM(IN_BSTR aName, IN_BSTR aValue, if (!directControl) rc = E_ACCESSDENIED; else - /** @todo Fix when adding DeleteGuestProperty(), - see defect. */ + /** @todo Fix when adding DeleteGuestProperty(), see defect. */ rc = directControl->AccessGuestProperty(aName, aValue, aFlags, true /* isSetter */, &dummy, &dummy64, &dummy); @@ -5713,42 +6240,50 @@ HRESULT Machine::enumerateGuestPropertiesInService AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); Utf8Str strPatterns(aPatterns); + HWData::GuestPropertyMap propMap; + /* * Look for matching patterns and build up a list. */ - HWData::GuestPropertyList propList; - for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin(); - it != mHWData->mGuestProperties.end(); - ++it) + HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.begin(); + while (it != mHWData->mGuestProperties.end()) + { if ( strPatterns.isEmpty() || RTStrSimplePatternMultiMatch(strPatterns.c_str(), RTSTR_MAX, - it->strName.c_str(), + it->first.c_str(), RTSTR_MAX, NULL) ) - propList.push_back(*it); + { + propMap.insert(*it); + } + + it++; + } + + alock.release(); /* * And build up the arrays for returning the property information. */ - size_t cEntries = propList.size(); + size_t cEntries = propMap.size(); SafeArray names(cEntries); SafeArray values(cEntries); SafeArray timestamps(cEntries); SafeArray flags(cEntries); size_t iProp = 0; - for (HWData::GuestPropertyList::iterator it = propList.begin(); - it != propList.end(); - ++it) + + it = propMap.begin(); + while (it != propMap.end()) { char szFlags[MAX_FLAGS_LEN + 1]; - it->strName.cloneTo(&names[iProp]); - it->strValue.cloneTo(&values[iProp]); - timestamps[iProp] = it->mTimestamp; - writeFlags(it->mFlags, szFlags); - Bstr(szFlags).cloneTo(&flags[iProp]); - ++iProp; + it->first.cloneTo(&names[iProp]); + it->second.strValue.cloneTo(&values[iProp]); + timestamps[iProp] = it->second.mTimestamp; + writeFlags(it->second.mFlags, szFlags); + Bstr(szFlags).cloneTo(&flags[iProp++]); + it++; } names.detachTo(ComSafeArrayOutArg(aNames)); values.detachTo(ComSafeArrayOutArg(aValues)); @@ -6083,6 +6618,132 @@ STDMETHODIMP Machine::RemoveStorageController(IN_BSTR aName) return S_OK; } +STDMETHODIMP Machine::AddUSBController(IN_BSTR aName, USBControllerType_T aType, + IUSBController **controller) +{ + if ( (aType <= USBControllerType_Null) + || (aType >= USBControllerType_Last)) + return setError(E_INVALIDARG, + tr("Invalid USB controller type: %d"), + aType); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = checkStateDependency(MutableStateDep); + if (FAILED(rc)) return rc; + + /* try to find one with the same type first. */ + ComObjPtr ctrl; + + rc = getUSBControllerByName(aName, ctrl, false /* aSetError */); + if (SUCCEEDED(rc)) + return setError(VBOX_E_OBJECT_IN_USE, + tr("USB controller named '%ls' already exists"), + aName); + + /* Check that we don't exceed the maximum number of USB controllers for the given type. */ + ULONG maxInstances; + rc = mParent->getSystemProperties()->GetMaxInstancesOfUSBControllerType(mHWData->mChipsetType, aType, &maxInstances); + if (FAILED(rc)) + return rc; + + ULONG cInstances = getUSBControllerCountByType(aType); + if (cInstances >= maxInstances) + return setError(E_INVALIDARG, + tr("Too many USB controllers of this type")); + + ctrl.createObject(); + + rc = ctrl->init(this, aName, aType); + if (FAILED(rc)) return rc; + + setModified(IsModified_USB); + mUSBControllers.backup(); + mUSBControllers->push_back(ctrl); + + ctrl.queryInterfaceTo(controller); + + /* inform the direct session if any */ + alock.release(); + onUSBControllerChange(); + + return S_OK; +} + +STDMETHODIMP Machine::GetUSBControllerByName(IN_BSTR aName, IUSBController **aUSBController) +{ + CheckComArgStrNotEmptyOrNull(aName); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + ComObjPtr ctrl; + + HRESULT rc = getUSBControllerByName(aName, ctrl, true /* aSetError */); + if (SUCCEEDED(rc)) + ctrl.queryInterfaceTo(aUSBController); + + return rc; +} + +STDMETHODIMP Machine::GetUSBControllerCountByType(USBControllerType_T aType, + ULONG *aControllers) +{ + CheckComArgOutPointerValid(aControllers); + + if ( (aType <= USBControllerType_Null) + || (aType >= USBControllerType_Last)) + return setError(E_INVALIDARG, + tr("Invalid USB controller type: %d"), + aType); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + ComObjPtr ctrl; + + *aControllers = getUSBControllerCountByType(aType); + + return S_OK; +} + +STDMETHODIMP Machine::RemoveUSBController(IN_BSTR aName) +{ + CheckComArgStrNotEmptyOrNull(aName); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = checkStateDependency(MutableStateDep); + if (FAILED(rc)) return rc; + + ComObjPtr ctrl; + rc = getUSBControllerByName(aName, ctrl, true /* aSetError */); + if (FAILED(rc)) return rc; + + setModified(IsModified_USB); + mUSBControllers.backup(); + + ctrl->unshare(); + + mUSBControllers->remove(ctrl); + + /* inform the direct session if any */ + alock.release(); + onUSBControllerChange(); + + return S_OK; +} + STDMETHODIMP Machine::QuerySavedGuestScreenInfo(ULONG uScreenId, ULONG *puOriginX, ULONG *puOriginY, @@ -6397,7 +7058,7 @@ STDMETHODIMP Machine::HotPlugCPU(ULONG aCpu) mHWData.backup(); mHWData->mCPUAttached[aCpu] = true; - /* Save settings if online */ + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ if (Global::IsOnline(mData->mMachineState)) saveSettings(NULL); @@ -6438,7 +7099,7 @@ STDMETHODIMP Machine::HotUnplugCPU(ULONG aCpu) mHWData.backup(); mHWData->mCPUAttached[aCpu] = false; - /* Save settings if online */ + /** Save settings if online - @todo why is this required? -- @bugref{6818} */ if (Global::IsOnline(mData->mMachineState)) saveSettings(NULL); @@ -6934,8 +7595,94 @@ STDMETHODIMP Machine::COMSETTER(AutostopType)(AutostopType_T enmAutostopType) return hrc; } +STDMETHODIMP Machine::COMGETTER(DefaultFrontend)(BSTR *aDefaultFrontend) +{ + CheckComArgOutPointerValid(aDefaultFrontend); + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + mHWData->mDefaultFrontend.cloneTo(aDefaultFrontend); + } + return hrc; +} -STDMETHODIMP Machine::CloneTo(IMachine *pTarget, CloneMode_T mode, ComSafeArrayIn(CloneOptions_T, options), IProgress **pProgress) +STDMETHODIMP Machine::COMSETTER(DefaultFrontend)(IN_BSTR aDefaultFrontend) +{ + CheckComArgStr(aDefaultFrontend); + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + hrc = checkStateDependency(MutableOrSavedStateDep); + if (SUCCEEDED(hrc)) + { + hrc = mHWData.backupEx(); + if (SUCCEEDED(hrc)) + { + setModified(IsModified_MachineData); + mHWData->mDefaultFrontend = aDefaultFrontend; + } + } + } + return hrc; +} + +STDMETHODIMP Machine::COMGETTER(Icon)(ComSafeArrayOut(BYTE, aIcon)) +{ + CheckComArgSafeArrayNotNull(aIcon); + CheckComArgOutSafeArrayPointerValid(aIcon); + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + com::SafeArray icon(mUserData->mIcon.size()); + memcpy(icon.raw(), &mUserData->mIcon[0], mUserData->mIcon.size()); + icon.detachTo(ComSafeArrayOutArg(aIcon)); + } + return hrc; +} + +STDMETHODIMP Machine::COMSETTER(Icon)(ComSafeArrayIn(BYTE, aIcon)) +{ + CheckComArgSafeArrayNotNull(aIcon); + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + hrc = checkStateDependency(MutableOrSavedStateDep); + if (SUCCEEDED(hrc)) + { + setModified(IsModified_MachineData); + mUserData.backup(); + com::SafeArray icon(ComSafeArrayInArg(aIcon)); + mUserData->mIcon.resize(icon.size()); + memcpy(&mUserData->mIcon[0], icon.raw(), mUserData->mIcon.size()); + } + } + return hrc; +} + +STDMETHODIMP Machine::COMGETTER(USBProxyAvailable)(BOOL *aAvailable) +{ + CheckComArgOutPointerValid(aAvailable); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + +#ifdef VBOX_WITH_USB + *aAvailable = true; +#else + *aAvailable = false; +#endif + return S_OK; +} + +STDMETHODIMP Machine::CloneTo(IMachine *pTarget, CloneMode_T mode, ComSafeArrayIn(CloneOptions_T, options), IProgress **pProgress) { LogFlowFuncEnter(); @@ -7179,12 +7926,40 @@ void Machine::composeSavedStateFilename(Utf8Str &strStateFilePath) time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond); } +/** + * Returns the full path to the default video capture file. + */ +void Machine::getDefaultVideoCaptureFile(Utf8Str &strFile) +{ + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + strFile = mData->m_strConfigFileFull; // path/to/machinesfolder/vmname/vmname.vbox + strFile.stripExt(); // path/to/machinesfolder/vmname/vmname + strFile.append(".webm"); // path/to/machinesfolder/vmname/vmname.webm +} + +/** + * Returns whether at least one USB controller is present for the VM. + */ +bool Machine::isUSBControllerPresent() +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), false); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + return (mUSBControllers->size() > 0); +} + /** * @note Locks this object for writing, calls the client process * (inside the lock). */ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, - const Utf8Str &strType, + const Utf8Str &strFrontend, const Utf8Str &strEnvironment, ProgressProxy *aProgress) { @@ -7192,6 +7967,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, AssertReturn(aControl, E_FAIL); AssertReturn(aProgress, E_FAIL); + AssertReturn(!strFrontend.isEmpty(), E_FAIL); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -7222,7 +7998,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, szPath[sz++] = RTPATH_DELIMITER; szPath[sz] = 0; char *cmd = szPath + sz; - sz = RTPATH_MAX - sz; + sz = sizeof(szPath) - sz; int vrc = VINF_SUCCESS; RTPROCESS pid = NIL_RTPROCESS; @@ -7278,16 +8054,44 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, RTStrFree(newEnvStr); } - /* Qt is default */ #ifdef VBOX_WITH_QTGUI - if (strType == "gui" || strType == "GUI/Qt") + if (strFrontend == "gui" || strFrontend == "GUI/Qt") { # ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */ - const char VirtualBox_exe[] = "../Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM"; + /* Modify the base path so that we don't need to use ".." below. */ + RTPathStripTrailingSlash(szPath); + RTPathStripFilename(szPath); + sz = strlen(szPath); + cmd = szPath + sz; + sz = sizeof(szPath) - sz; + +#define OSX_APP_NAME "VirtualBoxVM" +#define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM" + + Utf8Str strAppOverride = getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride")); + if ( strAppOverride.contains(".") + || strAppOverride.contains("/") + || strAppOverride.contains("\\") + || strAppOverride.contains(":")) + strAppOverride.setNull(); + Utf8Str strAppPath; + if (!strAppOverride.isEmpty()) + { + strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, strAppOverride.c_str()); + Utf8Str strFullPath(szPath); + strFullPath.append(strAppPath); + /* there is a race, but people using this deserve the failure */ + if (!RTFileExists(strFullPath.c_str())) + strAppOverride.setNull(); + } + if (strAppOverride.isEmpty()) + strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, OSX_APP_NAME); + const char *VirtualBox_exe = strAppPath.c_str(); + AssertReturn(sz >= strlen(VirtualBox_exe), E_UNEXPECTED); # else const char VirtualBox_exe[] = "VirtualBox" HOSTSUFF_EXE; -# endif Assert(sz >= sizeof(VirtualBox_exe)); +# endif strcpy(cmd, VirtualBox_exe); Utf8Str idStr = mData->mUuid.toString(); @@ -7302,7 +8106,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, else #ifdef VBOX_WITH_VBOXSDL - if (strType == "sdl" || strType == "GUI/SDL") + if (strFrontend == "sdl" || strFrontend == "GUI/SDL") { const char VBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE; Assert(sz >= sizeof(VBoxSDL_exe)); @@ -7320,9 +8124,9 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, else #ifdef VBOX_WITH_HEADLESS - if ( strType == "headless" - || strType == "capture" - || strType == "vrdp" /* Deprecated. Same as headless. */ + if ( strFrontend == "headless" + || strFrontend == "capture" + || strFrontend == "vrdp" /* Deprecated. Same as headless. */ ) { /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE, @@ -7343,7 +8147,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, "--vrde", "config", 0, /* For "--capture". */ 0 }; - if (strType == "capture") + if (strFrontend == "capture") { unsigned pos = RT_ELEMENTS(args) - 2; args[pos] = "--capture"; @@ -7364,8 +8168,8 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, { RTEnvDestroy(env); return setError(E_INVALIDARG, - tr("Invalid session type: '%s'"), - strType.c_str()); + tr("Invalid frontend name: '%s'"), + strFrontend.c_str()); } RTEnvDestroy(env); @@ -7382,22 +8186,28 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, * because it doesn't need to call us back if called with a NULL argument. * Releasing the lock here is dangerous because we didn't prepare the * launch data yet, but the client we've just started may happen to be - * too fast and call openSession() that will fail (because of PID, etc.), + * too fast and call LockMachine() that will fail (because of PID, etc.), * so that the Machine will never get out of the Spawning session state. */ /* inform the session that it will be a remote one */ LogFlowThisFunc(("Calling AssignMachine (NULL)...\n")); - HRESULT rc = aControl->AssignMachine(NULL, LockType_Write); +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER + HRESULT rc = aControl->AssignMachine(NULL, LockType_Write, Bstr::Empty.raw()); +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ + HRESULT rc = aControl->AssignMachine(NULL, LockType_Write, NULL); +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ LogFlowThisFunc(("AssignMachine (NULL) returned %08X\n", rc)); if (FAILED(rc)) { /* restore the session state */ mData->mSession.mState = SessionState_Unlocked; + alock.release(); + mParent->addProcessToReap(pid); /* The failure may occur w/o any error info (from RPC), so provide one */ return setError(VBOX_E_VM_ERROR, - tr("Failed to assign the machine to the session (%Rrc)"), rc); + tr("Failed to assign the machine to the session (%Rhrc)"), rc); } /* attach launch data to the machine */ @@ -7406,40 +8216,32 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl, mData->mSession.mProgress = aProgress; mData->mSession.mPID = pid; mData->mSession.mState = SessionState_Spawning; - mData->mSession.mType = strType; + mData->mSession.mType = strFrontend; + + alock.release(); + mParent->addProcessToReap(pid); LogFlowThisFuncLeave(); return S_OK; } /** - * Returns @c true if the given machine has an open direct session and returns - * the session machine instance and additional session data (on some platforms) - * if so. + * Returns @c true if the given session machine instance has an open direct + * session (and optionally also for direct sessions which are closing) and + * returns the session control machine instance if so. * * Note that when the method returns @c false, the arguments remain unchanged. * - * @param aMachine Session machine object. - * @param aControl Direct session control object (optional). - * @param aIPCSem Mutex IPC semaphore handle for this machine (optional). + * @param aMachine Session machine object. + * @param aControl Direct session control object (optional). + * @param aAllowClosing If true then additionally a session which is currently + * being closed will also be allowed. * * @note locks this object for reading. */ -#if defined(RT_OS_WINDOWS) -bool Machine::isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl /*= NULL*/, - HANDLE *aIPCSem /*= NULL*/, - bool aAllowClosing /*= false*/) -#elif defined(RT_OS_OS2) -bool Machine::isSessionOpen(ComObjPtr &aMachine, - ComPtr *aControl /*= NULL*/, - HMTX *aIPCSem /*= NULL*/, - bool aAllowClosing /*= false*/) -#else bool Machine::isSessionOpen(ComObjPtr &aMachine, ComPtr *aControl /*= NULL*/, bool aAllowClosing /*= false*/) -#endif { AutoLimitedCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), false); @@ -7461,11 +8263,6 @@ bool Machine::isSessionOpen(ComObjPtr &aMachine, if (aControl != NULL) *aControl = mData->mSession.mDirectControl; -#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) - /* Additional session data */ - if (aIPCSem != NULL) - *aIPCSem = aMachine->mIPCSem; -#endif return true; } @@ -7473,20 +8270,11 @@ bool Machine::isSessionOpen(ComObjPtr &aMachine, } /** - * Returns @c true if the given machine has an spawning direct session and - * returns and additional session data (on some platforms) if so. - * - * Note that when the method returns @c false, the arguments remain unchanged. - * - * @param aPID PID of the spawned direct session process. + * Returns @c true if the given machine has an spawning direct session. * * @note locks this object for reading. */ -#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) -bool Machine::isSessionSpawning(RTPROCESS *aPID /*= NULL*/) -#else bool Machine::isSessionSpawning() -#endif { AutoLimitedCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), false); @@ -7498,17 +8286,7 @@ bool Machine::isSessionSpawning() AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); if (mData->mSession.mState == SessionState_Spawning) - { -#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) - /* Additional session data */ - if (aPID != NULL) - { - AssertReturn(mData->mSession.mPID != NIL_RTPROCESS, false); - *aPID = mData->mSession.mPID; - } -#endif return true; - } return false; } @@ -7537,8 +8315,7 @@ bool Machine::checkForSpawnFailure() return true; } - /* VirtualBox::addProcessToReap() needs a write lock */ - AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS); + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (mData->mSession.mState != SessionState_Spawning) { @@ -7549,22 +8326,12 @@ bool Machine::checkForSpawnFailure() HRESULT rc = S_OK; -#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) - - /* the process was already unexpectedly terminated, we just need to set an - * error and finalize session spawning */ - rc = setError(E_FAIL, - tr("The virtual machine '%s' has terminated unexpectedly during startup"), - getName().c_str()); -#else - /* PID not yet initialized, skip check. */ if (mData->mSession.mPID == NIL_RTPROCESS) return false; RTPROCSTATUS status; - int vrc = ::RTProcWait(mData->mSession.mPID, RTPROCWAIT_FLAGS_NOBLOCK, - &status); + int vrc = RTProcWait(mData->mSession.mPID, RTPROCWAIT_FLAGS_NOBLOCK, &status); if (vrc != VERR_PROCESS_RUNNING) { @@ -7583,16 +8350,14 @@ bool Machine::checkForSpawnFailure() else rc = setError(E_FAIL, tr("The virtual machine '%s' has terminated unexpectedly during startup (%Rrc)"), - getName().c_str(), rc); + getName().c_str(), vrc); } -#endif - if (FAILED(rc)) { /* Close the remote session, remove the remote control from the list * and reset session state to Closed (@note keep the code in sync with - * the relevant part in checkForSpawnFailure()). */ + * the relevant part in LockMachine()). */ Assert(mData->mSession.mRemoteControls.size() == 1); if (mData->mSession.mRemoteControls.size() == 1) @@ -7611,7 +8376,6 @@ bool Machine::checkForSpawnFailure() mData->mSession.mProgress.setNull(); } - mParent->addProcessToReap(mData->mSession.mPID); mData->mSession.mPID = NIL_RTPROCESS; mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked); @@ -7771,6 +8535,21 @@ void Machine::releaseStateDependency() } } +Utf8Str Machine::getExtraData(const Utf8Str &strKey) +{ + /* start with nothing found */ + Utf8Str strResult(""); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + settings::StringsMap::const_iterator it = mData->pMachineConfigFile->mapExtraDataItems.find(strKey); + if (it != mData->pMachineConfigFile->mapExtraDataItems.end()) + // found: + strResult = it->second; // source is a Utf8Str + + return strResult; +} + // protected methods ///////////////////////////////////////////////////////////////////////////// @@ -7894,6 +8673,7 @@ HRESULT Machine::initDataAndChildObjects() mHWData.allocate(); mMediaData.allocate(); mStorageControllers.allocate(); + mUSBControllers.allocate(); /* initialize mOSTypeId */ mUserData->s.strOsType = mParent->getUnknownOSType()->id(); @@ -7924,9 +8704,9 @@ HRESULT Machine::initDataAndChildObjects() unconst(mAudioAdapter).createObject(); mAudioAdapter->init(this); - /* create the USB controller object (always present, default is disabled) */ - unconst(mUSBController).createObject(); - mUSBController->init(this); + /* create the USB device filters object (always present) */ + unconst(mUSBDeviceFilters).createObject(); + mUSBDeviceFilters->init(this); /* create associated network adapter objects */ mNetworkAdapters.resize(Global::getMaxNetworkAdapters(mHWData->mChipsetType)); @@ -7975,10 +8755,10 @@ void Machine::uninitDataAndChildObjects() } } - if (mUSBController) + if (mUSBDeviceFilters) { - mUSBController->uninit(); - unconst(mUSBController).setNull(); + mUSBDeviceFilters->uninit(); + unconst(mUSBDeviceFilters).setNull(); } if (mAudioAdapter) @@ -8017,13 +8797,13 @@ void Machine::uninitDataAndChildObjects() unconst(mBIOSSettings).setNull(); } - /* Deassociate hard disks (only when a real Machine or a SnapshotMachine + /* Deassociate media (only when a real Machine or a SnapshotMachine * instance is uninitialized; SessionMachine instances refer to real - * Machine hard disks). This is necessary for a clean re-initialization of + * Machine media). This is necessary for a clean re-initialization of * the VM after successfully re-checking the accessibility state. Note * that in case of normal Machine or SnapshotMachine uninitialization (as - * a result of unregistering or deleting the snapshot), outdated hard - * disk attachments will already be uninitialized and deleted, so this + * a result of unregistering or deleting the snapshot), outdated media + * attachments will already be uninitialized and deleted, so this * code will not affect them. */ if ( !!mMediaData && (!isSessionMachine()) @@ -8033,10 +8813,10 @@ void Machine::uninitDataAndChildObjects() it != mMediaData->mAttachments.end(); ++it) { - ComObjPtr hd = (*it)->getMedium(); - if (hd.isNull()) + ComObjPtr pMedium = (*it)->getMedium(); + if (pMedium.isNull()) continue; - HRESULT rc = hd->removeBackReference(mData->mUuid, getSnapshotId()); + HRESULT rc = pMedium->removeBackReference(mData->mUuid, getSnapshotId()); AssertComRC(rc); } } @@ -8061,6 +8841,7 @@ void Machine::uninitDataAndChildObjects() * since it may be still in use) */ mMediaData.free(); mStorageControllers.free(); + mUSBControllers.free(); mHWData.free(); mUserData.free(); mSSData.free(); @@ -8228,9 +9009,28 @@ HRESULT Machine::loadMachineDataFromSettings(const settings::MachineConfigFile & // copy name, description, OS type, teleporter, UTC etc. mUserData->s = config.machineUserData; + // Decode the Icon overide data from config userdata and set onto Machine. + #define DECODE_STR_MAX _1M + const char* pszStr = config.machineUserData.ovIcon.c_str(); + ssize_t cbOut = RTBase64DecodedSize(pszStr, NULL); + if (cbOut > DECODE_STR_MAX) + return setError(E_FAIL, + tr("Icon Data too long.'%d' > '%d'"), + cbOut, + DECODE_STR_MAX); + com::SafeArray iconByte(cbOut); + HRESULT rc = RTBase64Decode(pszStr, iconByte.raw(), cbOut, NULL, NULL); + if (FAILED(rc)) + return setError(E_FAIL, + tr("Failure to Decode Icon Data. '%s' (%d)"), + pszStr, + rc); + mUserData->mIcon.resize(iconByte.size()); + memcpy(&mUserData->mIcon[0], iconByte.raw(), mUserData->mIcon.size()); + // look up the object by Id to check it is valid ComPtr guestOSType; - HRESULT rc = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(), + rc = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType).raw(), guestOSType.asOutParam()); if (FAILED(rc)) return rc; @@ -8435,14 +9235,15 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De mHWData->mHardwareUUID = data.uuid; mHWData->mHWVirtExEnabled = data.fHardwareVirt; - mHWData->mHWVirtExExclusive = data.fHardwareVirtExclusive; mHWData->mHWVirtExNestedPagingEnabled = data.fNestedPaging; mHWData->mHWVirtExLargePagesEnabled = data.fLargePages; mHWData->mHWVirtExVPIDEnabled = data.fVPID; + mHWData->mHWVirtExUXEnabled = data.fUnrestrictedExecution; mHWData->mHWVirtExForceEnabled = data.fHardwareVirtForce; mHWData->mPAEEnabled = data.fPAE; mHWData->mSyntheticCpu = data.fSyntheticCpu; - + mHWData->mLongMode = data.enmLongMode; + mHWData->mTripleFaultReset = data.fTripleFaultReset; mHWData->mCPUCount = data.cCPUs; mHWData->mCPUHotPlugEnabled = data.fCpuHotPlug; mHWData->mCpuExecutionCap = data.ulCpuExecutionCap; @@ -8518,6 +9319,7 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De mHWData->mBootOrder[i] = it->second; } + mHWData->mGraphicsControllerType = data.graphicsControllerType; mHWData->mVRAMSize = data.ulVRAMSizeMB; mHWData->mMonitorCount = data.cMonitors; mHWData->mAccelerate3DEnabled = data.fAccelerate3D; @@ -8525,7 +9327,15 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De mHWData->mVideoCaptureWidth = data.ulVideoCaptureHorzRes; mHWData->mVideoCaptureHeight = data.ulVideoCaptureVertRes; mHWData->mVideoCaptureEnabled = data.fVideoCaptureEnabled; - mHWData->mVideoCaptureFile = data.strVideoCaptureFile; + for (unsigned i = 0; i < RT_ELEMENTS(mHWData->maVideoCaptureScreens); i++) + mHWData->maVideoCaptureScreens[i] = ASMBitTest(&data.u64VideoCaptureScreens, i); + AssertCompile(RT_ELEMENTS(mHWData->maVideoCaptureScreens) == sizeof(data.u64VideoCaptureScreens) * 8); + mHWData->mVideoCaptureRate = data.ulVideoCaptureRate; + mHWData->mVideoCaptureFPS = data.ulVideoCaptureFPS; + if (!data.strVideoCaptureFile.isEmpty()) + calculateFullPath(data.strVideoCaptureFile, mHWData->mVideoCaptureFile); + else + mHWData->mVideoCaptureFile.setNull(); mHWData->mFirmwareType = data.firmwareType; mHWData->mPointingHIDType = data.pointingHIDType; mHWData->mKeyboardHIDType = data.keyboardHIDType; @@ -8545,8 +9355,21 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De rc = mBandwidthControl->loadSettings(data.ioSettings); if (FAILED(rc)) return rc; - /* USB Controller */ - rc = mUSBController->loadSettings(data.usbController); + /* Shared folders */ + for (settings::USBControllerList::const_iterator it = data.usbSettings.llUSBControllers.begin(); + it != data.usbSettings.llUSBControllers.end(); + ++it) + { + const settings::USBController &settingsCtrl = *it; + ComObjPtr newCtrl; + + newCtrl.createObject(); + newCtrl->init(this, settingsCtrl.strName, settingsCtrl.enmType); + mUSBControllers->push_back(newCtrl); + } + + /* USB device filters */ + rc = mUSBDeviceFilters->loadSettings(data.usbSettings); if (FAILED(rc)) return rc; // network adapters @@ -8671,8 +9494,8 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De const settings::GuestProperty &prop = *it; uint32_t fFlags = guestProp::NILFLAG; guestProp::validateFlags(prop.strFlags.c_str(), &fFlags); - HWData::GuestProperty property = { prop.strName, prop.strValue, (LONG64) prop.timestamp, fFlags }; - mHWData->mGuestProperties.push_back(property); + HWData::GuestProperty property = { prop.strValue, (LONG64) prop.timestamp, fFlags }; + mHWData->mGuestProperties[prop.strName] = property; } mHWData->mGuestPropertyNotificationPatterns = data.strNotificationPatterns; @@ -8683,6 +9506,9 @@ HRESULT Machine::loadHardware(const settings::Hardware &data, const settings::De return rc; mHWData->mAutostart = *pAutostart; + + /* default frontend */ + mHWData->mDefaultFrontend = data.strDefaultFrontend; } catch(std::bad_alloc &) { @@ -8973,6 +9799,8 @@ HRESULT Machine::loadStorageDevices(StorageController *aStorageController, dev.fTempEject, dev.fNonRotational, dev.fDiscard, + /// @todo load setting once the hot-pluggable flag works + false /*dev.fHotPluggable*/, pBwGroup.isNull() ? Utf8Str::Empty : pBwGroup->getName()); if (FAILED(rc)) break; @@ -9028,7 +9856,7 @@ HRESULT Machine::findSnapshotById(const Guid &aId, return E_FAIL; } - if (aId.isEmpty()) + if (aId.isZero()) aSnapshot = mData->mFirstSnapshot; else aSnapshot = mData->mFirstSnapshot->findChildOrSelf(aId.ref()); @@ -9112,6 +9940,57 @@ HRESULT Machine::getStorageControllerByName(const Utf8Str &aName, return VBOX_E_OBJECT_NOT_FOUND; } +/** + * Returns a USB controller object with the given name. + * + * @param aName USB controller name to find + * @param aUSBController where to return the found USB controller + * @param aSetError true to set extended error info on failure + */ +HRESULT Machine::getUSBControllerByName(const Utf8Str &aName, + ComObjPtr &aUSBController, + bool aSetError /* = false */) +{ + AssertReturn(!aName.isEmpty(), E_INVALIDARG); + + for (USBControllerList::const_iterator it = mUSBControllers->begin(); + it != mUSBControllers->end(); + ++it) + { + if ((*it)->getName() == aName) + { + aUSBController = (*it); + return S_OK; + } + } + + if (aSetError) + return setError(VBOX_E_OBJECT_NOT_FOUND, + tr("Could not find a storage controller named '%s'"), + aName.c_str()); + return VBOX_E_OBJECT_NOT_FOUND; +} + +/** + * Returns the number of USB controller instance of the given type. + * + * @param enmType USB controller type. + */ +ULONG Machine::getUSBControllerCountByType(USBControllerType_T enmType) +{ + ULONG cCtrls = 0; + + for (USBControllerList::const_iterator it = mUSBControllers->begin(); + it != mUSBControllers->end(); + ++it) + { + if ((*it)->getControllerType() == enmType) + cCtrls++; + } + + return cCtrls; +} + HRESULT Machine::getMediumAttachmentsOfController(CBSTR aName, MediaData::AttachmentList &atts) { @@ -9534,6 +10413,26 @@ void Machine::copyMachineDataToSettings(settings::MachineConfigFile &config) // copy name, description, OS type, teleport, UTC etc. config.machineUserData = mUserData->s; + // Encode the Icon Override data from Machine and store on config userdata. + com::SafeArray iconByte; + COMGETTER(Icon)(ComSafeArrayAsOutParam(iconByte)); + ssize_t cbData = iconByte.size(); + if (cbData > 0) + { + ssize_t cchOut = RTBase64EncodedLength(cbData); + Utf8Str strIconData; + strIconData.reserve(cchOut+1); + int vrc = RTBase64Encode(iconByte.raw(), cbData, + strIconData.mutableRaw(), strIconData.capacity(), + NULL); + if (RT_FAILURE(vrc)) + throw setError(E_FAIL, tr("Failure to Encode Icon Data. '%s' (%Rrc)"), strIconData.mutableRaw(), vrc); + strIconData.jolt(); + config.machineUserData.ovIcon = strIconData; + } + else + config.machineUserData.ovIcon.setNull(); + if ( mData->mMachineState == MachineState_Saved || mData->mMachineState == MachineState_Restoring // when deleting a snapshot we may or may not have a saved state in the current state, @@ -9662,13 +10561,15 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb // CPU data.fHardwareVirt = !!mHWData->mHWVirtExEnabled; - data.fHardwareVirtExclusive = !!mHWData->mHWVirtExExclusive; data.fNestedPaging = !!mHWData->mHWVirtExNestedPagingEnabled; data.fLargePages = !!mHWData->mHWVirtExLargePagesEnabled; data.fVPID = !!mHWData->mHWVirtExVPIDEnabled; + data.fUnrestrictedExecution = !!mHWData->mHWVirtExUXEnabled; data.fHardwareVirtForce = !!mHWData->mHWVirtExForceEnabled; data.fPAE = !!mHWData->mPAEEnabled; + data.enmLongMode = mHWData->mLongMode; data.fSyntheticCpu = !!mHWData->mSyntheticCpu; + data.fTripleFaultReset = !!mHWData->mTripleFaultReset; /* Standard and Extended CPUID leafs. */ data.llCpuIdLeafs.clear(); @@ -9728,14 +10629,25 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb data.mapBootOrder[i] = mHWData->mBootOrder[i]; // display + data.graphicsControllerType = mHWData->mGraphicsControllerType; data.ulVRAMSizeMB = mHWData->mVRAMSize; data.cMonitors = mHWData->mMonitorCount; data.fAccelerate3D = !!mHWData->mAccelerate3DEnabled; data.fAccelerate2DVideo = !!mHWData->mAccelerate2DVideoEnabled; data.ulVideoCaptureHorzRes = mHWData->mVideoCaptureWidth; data.ulVideoCaptureVertRes = mHWData->mVideoCaptureHeight; - data.fVideoCaptureEnabled = !! mHWData->mVideoCaptureEnabled; - data.strVideoCaptureFile = mHWData->mVideoCaptureFile; + data.ulVideoCaptureRate = mHWData->mVideoCaptureRate; + data.ulVideoCaptureFPS = mHWData->mVideoCaptureFPS; + data.fVideoCaptureEnabled = !!mHWData->mVideoCaptureEnabled; + for (unsigned i = 0; i < sizeof(data.u64VideoCaptureScreens) * 8; i++) + { + if (mHWData->maVideoCaptureScreens[i]) + ASMBitSet(&data.u64VideoCaptureScreens, i); + else + ASMBitClear(&data.u64VideoCaptureScreens, i); + } + /* store relative video capture file if possible */ + copyPathRelativeToMachine(mHWData->mVideoCaptureFile, data.strVideoCaptureFile); /* VRDEServer settings (optional) */ rc = mVRDEServer->saveSettings(data.vrdeSettings); @@ -9746,7 +10658,21 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb if (FAILED(rc)) throw rc; /* USB Controller (required) */ - rc = mUSBController->saveSettings(data.usbController); + for (USBControllerList::const_iterator it = mUSBControllers->begin(); + it != mUSBControllers->end(); + ++it) + { + ComObjPtr ctrl = *it; + settings::USBController settingsCtrl; + + settingsCtrl.strName = ctrl->getName(); + settingsCtrl.enmType = ctrl->getControllerType(); + + data.usbSettings.llUSBControllers.push_back(settingsCtrl); + } + + /* USB device filters (required) */ + rc = mUSBDeviceFilters->saveSettings(data.usbSettings); if (FAILED(rc)) throw rc; /* Network adapters (required) */ @@ -9854,11 +10780,11 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb // guest properties data.llGuestProperties.clear(); #ifdef VBOX_WITH_GUEST_PROPS - for (HWData::GuestPropertyList::const_iterator it = mHWData->mGuestProperties.begin(); + for (HWData::GuestPropertyMap::const_iterator it = mHWData->mGuestProperties.begin(); it != mHWData->mGuestProperties.end(); ++it) { - HWData::GuestProperty property = *it; + HWData::GuestProperty property = it->second; /* Remove transient guest properties at shutdown unless we * are saving state */ @@ -9869,7 +10795,7 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb || property.mFlags & guestProp::TRANSRESET)) continue; settings::GuestProperty prop; - prop.strName = property.strName; + prop.strName = it->first; prop.strValue = property.strValue; prop.timestamp = property.mTimestamp; char szFlags[guestProp::MAX_FLAGS_LEN + 1]; @@ -9886,6 +10812,8 @@ HRESULT Machine::saveHardware(settings::Hardware &data, settings::Debugging *pDb *pDbg = mHWData->mDebugging; *pAutostart = mHWData->mAutostart; + + data.strDefaultFrontend = mHWData->mDefaultFrontend; } catch(std::bad_alloc &) { @@ -9976,14 +10904,17 @@ HRESULT Machine::saveStorageDevices(ComObjPtr aStorageControl dev.deviceType = pAttach->getType(); dev.lPort = pAttach->getPort(); dev.lDevice = pAttach->getDevice(); + dev.fPassThrough = pAttach->getPassthrough(); + /// @todo save setting once the hot-pluggable flag works + dev.fHotPluggable = false /* pAttach->getHotPluggable()*/; if (pMedium) { if (pMedium->isHostDrive()) dev.strHostDriveSrc = pMedium->getLocationFull(); else dev.uuid = pMedium->getId(); - dev.fPassThrough = pAttach->getPassthrough(); dev.fTempEject = pAttach->getTempEject(); + dev.fNonRotational = pAttach->getNonRotational(); dev.fDiscard = pAttach->getDiscard(); } @@ -10128,7 +11059,7 @@ void Machine::addMediumToRegistry(ComObjPtr &pMedium) * @note The progress object is not marked as completed, neither on success nor * on failure. This is a responsibility of the caller. * - * @note Locks this object for writing. + * @note Locks this object and the media tree for writing. */ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, ULONG aWeight, @@ -10151,6 +11082,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, HRESULT rc = S_OK; + // use appropriate locked media map (online or offline) MediumLockListMap lockedMediaOffline; MediumLockListMap *lockedMediaMap; if (aOnline) @@ -10282,6 +11214,8 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, if (aOnline) { alock.release(); + /* The currently attached medium will be read-only, change + * the lock type to read. */ rc = pMediumLockList->Update(pMedium, false); alock.acquire(); AssertComRCThrowRC(rc); @@ -10296,16 +11230,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, alock.acquire(); if (FAILED(rc)) throw rc; - rc = lockedMediaMap->Unlock(); - AssertComRCThrowRC(rc); - alock.release(); - rc = pMediumLockList->Append(diff, true); - alock.acquire(); - AssertComRCThrowRC(rc); - alock.release(); - rc = lockedMediaMap->Lock(); - alock.acquire(); - AssertComRCThrowRC(rc); + /* actual lock list update is done in Medium::commitMedia */ rc = diff->addBackReference(mData->mUuid); AssertComRCThrowRC(rc); @@ -10324,6 +11249,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, false /* aTempEject */, pAtt->getNonRotational(), pAtt->getDiscard(), + pAtt->getHotPluggable(), pAtt->getBandwidthGroup()); if (FAILED(rc)) throw rc; @@ -10334,7 +11260,7 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, } catch (HRESULT aRC) { rc = aRC; } - /* unlock all hard disks we locked */ + /* unlock all hard disks we locked when there is no VM */ if (!aOnline) { ErrorInfoKeeper eik; @@ -10343,14 +11269,6 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, AssertComRC(rc1); } - if (FAILED(rc)) - { - MultiResult mrc = rc; - - alock.release(); - mrc = deleteImplicitDiffs(); - } - return rc; } @@ -10361,99 +11279,225 @@ HRESULT Machine::createImplicitDiffs(IProgress *aProgress, * Note that to delete hard disks created by #AttachDevice() this method is * called from #fixupMedia() when the changes are rolled back. * - * @note Locks this object for writing. + * @note Locks this object and the media tree for writing. */ -HRESULT Machine::deleteImplicitDiffs() +HRESULT Machine::deleteImplicitDiffs(bool aOnline) { + LogFlowThisFunc(("aOnline=%d\n", aOnline)); + AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - LogFlowThisFuncEnter(); + AutoMultiWriteLock2 alock(this->lockHandle(), + &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); + /* We absolutely must have backed up state. */ AssertReturn(mMediaData.isBackedUp(), E_FAIL); - HRESULT rc = S_OK; - - MediaData::AttachmentList implicitAtts; - - const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments; - - /* enumerate new attachments */ + /* Check if there are any implicitly created diff images. */ + bool fImplicitDiffs = false; for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin(); it != mMediaData->mAttachments.end(); ++it) { - ComObjPtr hd = (*it)->getMedium(); - if (hd.isNull()) - continue; - - if ((*it)->isImplicit()) - { - /* deassociate and mark for deletion */ - LogFlowThisFunc(("Detaching '%s', pending deletion\n", (*it)->getLogName())); - rc = hd->removeBackReference(mData->mUuid); - AssertComRC(rc); - implicitAtts.push_back(*it); - continue; - } - - /* was this hard disk attached before? */ - if (!findAttachment(oldAtts, hd)) + const ComObjPtr &pAtt = *it; + if (pAtt->isImplicit()) { - /* no: de-associate */ - LogFlowThisFunc(("Detaching '%s', no deletion\n", (*it)->getLogName())); - rc = hd->removeBackReference(mData->mUuid); - AssertComRC(rc); - continue; + fImplicitDiffs = true; + break; } - LogFlowThisFunc(("Not detaching '%s'\n", (*it)->getLogName())); } + /* If there is nothing to do, leave early. This saves lots of image locking + * effort. It also avoids a MachineStateChanged event without real reason. + * This is important e.g. when loading a VM config, because there should be + * no events. Otherwise API clients can become thoroughly confused for + * inaccessible VMs (the code for loading VM configs uses this method for + * cleanup if the config makes no sense), as they take such events as an + * indication that the VM is alive, and they would force the VM config to + * be reread, leading to an endless loop. */ + if (!fImplicitDiffs) + return S_OK; - /* rollback hard disk changes */ - mMediaData.rollback(); + HRESULT rc = S_OK; + MachineState_T oldState = mData->mMachineState; + + /* will release the lock before the potentially lengthy operation, + * so protect with the special state (unless already protected) */ + if ( oldState != MachineState_Saving + && oldState != MachineState_LiveSnapshotting + && oldState != MachineState_RestoringSnapshot + && oldState != MachineState_DeletingSnapshot + && oldState != MachineState_DeletingSnapshotOnline + && oldState != MachineState_DeletingSnapshotPaused + ) + setMachineState(MachineState_SettingUp); - MultiResult mrc(S_OK); + // use appropriate locked media map (online or offline) + MediumLockListMap lockedMediaOffline; + MediumLockListMap *lockedMediaMap; + if (aOnline) + lockedMediaMap = &mData->mSession.mLockedMedia; + else + lockedMediaMap = &lockedMediaOffline; - /* delete unused implicit diffs */ - if (implicitAtts.size() != 0) + try { - /* will release the lock before the potentially lengthy - * operation, so protect with the special state (unless already - * protected) */ - MachineState_T oldState = mData->mMachineState; - if ( oldState != MachineState_Saving - && oldState != MachineState_LiveSnapshotting - && oldState != MachineState_RestoringSnapshot - && oldState != MachineState_DeletingSnapshot - && oldState != MachineState_DeletingSnapshotOnline - && oldState != MachineState_DeletingSnapshotPaused - ) - setMachineState(MachineState_SettingUp); - - alock.release(); - - for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin(); - it != implicitAtts.end(); - ++it) + if (!aOnline) { - LogFlowThisFunc(("Deleting '%s'\n", (*it)->getLogName())); - ComObjPtr hd = (*it)->getMedium(); - - rc = hd->deleteStorage(NULL /*aProgress*/, true /*aWait*/); - AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, (*it)->getLogName(), hd->getLocationFull().c_str() )); - mrc = rc; - } - - alock.acquire(); + /* lock all attached hard disks early to detect "in use" + * situations before deleting actual diffs */ + for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin(); + it != mMediaData->mAttachments.end(); + ++it) + { + MediumAttachment* pAtt = *it; + if (pAtt->getType() == DeviceType_HardDisk) + { + Medium* pMedium = pAtt->getMedium(); + Assert(pMedium); - if (mData->mMachineState == MachineState_SettingUp) - setMachineState(oldState); - } + MediumLockList *pMediumLockList(new MediumLockList()); + alock.release(); + rc = pMedium->createMediumLockList(true /* fFailIfInaccessible */, + false /* fMediumLockWrite */, + NULL, + *pMediumLockList); + alock.acquire(); - return mrc; + if (FAILED(rc)) + { + delete pMediumLockList; + throw rc; + } + + rc = lockedMediaMap->Insert(pAtt, pMediumLockList); + if (FAILED(rc)) + throw rc; + } + } + + if (FAILED(rc)) + throw rc; + } // end of offline + + /* Lock lists are now up to date and include implicitly created media */ + + /* Go through remembered attachments and delete all implicitly created + * diffs and fix up the attachment information */ + const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments; + MediaData::AttachmentList implicitAtts; + for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin(); + it != mMediaData->mAttachments.end(); + ++it) + { + ComObjPtr pAtt = *it; + ComObjPtr pMedium = pAtt->getMedium(); + if (pMedium.isNull()) + continue; + + // Implicit attachments go on the list for deletion and back references are removed. + if (pAtt->isImplicit()) + { + /* Deassociate and mark for deletion */ + LogFlowThisFunc(("Detaching '%s', pending deletion\n", pAtt->getLogName())); + rc = pMedium->removeBackReference(mData->mUuid); + if (FAILED(rc)) + throw rc; + implicitAtts.push_back(pAtt); + continue; + } + + /* Was this medium attached before? */ + if (!findAttachment(oldAtts, pMedium)) + { + /* no: de-associate */ + LogFlowThisFunc(("Detaching '%s', no deletion\n", pAtt->getLogName())); + rc = pMedium->removeBackReference(mData->mUuid); + if (FAILED(rc)) + throw rc; + continue; + } + LogFlowThisFunc(("Not detaching '%s'\n", pAtt->getLogName())); + } + + /* If there are implicit attachments to delete, throw away the lock + * map contents (which will unlock all media) since the medium + * attachments will be rolled back. Below we need to completely + * recreate the lock map anyway since it is infinitely complex to + * do this incrementally (would need reconstructing each attachment + * change, which would be extremely hairy). */ + if (implicitAtts.size() != 0) + { + ErrorInfoKeeper eik; + + HRESULT rc1 = lockedMediaMap->Clear(); + AssertComRC(rc1); + } + + /* rollback hard disk changes */ + mMediaData.rollback(); + + MultiResult mrc(S_OK); + + // Delete unused implicit diffs. + if (implicitAtts.size() != 0) + { + alock.release(); + + for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin(); + it != implicitAtts.end(); + ++it) + { + // Remove medium associated with this attachment. + ComObjPtr pAtt = *it; + Assert(pAtt); + LogFlowThisFunc(("Deleting '%s'\n", pAtt->getLogName())); + ComObjPtr pMedium = pAtt->getMedium(); + Assert(pMedium); + + rc = pMedium->deleteStorage(NULL /*aProgress*/, true /*aWait*/); + // continue on delete failure, just collect error messages + AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, pAtt->getLogName(), pMedium->getLocationFull().c_str() )); + mrc = rc; + } + + alock.acquire(); + + /* if there is a VM recreate media lock map as mentioned above, + * otherwise it is a waste of time and we leave things unlocked */ + if (aOnline) + { + const ComObjPtr pMachine = mData->mSession.mMachine; + /* must never be NULL, but better safe than sorry */ + if (!pMachine.isNull()) + { + alock.release(); + rc = mData->mSession.mMachine->lockMedia(); + alock.acquire(); + if (FAILED(rc)) + throw rc; + } + } + } + } + catch (HRESULT aRC) {rc = aRC;} + + if (mData->mMachineState == MachineState_SettingUp) + setMachineState(oldState); + + /* unlock all hard disks we locked when there is no VM */ + if (!aOnline) + { + ErrorInfoKeeper eik; + + HRESULT rc1 = lockedMediaMap->Clear(); + AssertComRC(rc1); + } + + return rc; } + /** * Looks through the given list of media attachments for one with the given parameters * and returns it, or NULL if not found. The list is a parameter so that backup lists @@ -10822,11 +11866,21 @@ void Machine::commitMedia(bool aOnline /*= false*/) /* unlock since medium is not used anymore */ MediumLockList *pMediumLockList; rc = mData->mSession.mLockedMedia.Get(pAttach, pMediumLockList); - AssertComRC(rc); - if (pMediumLockList) + if (RT_UNLIKELY(rc == VBOX_E_INVALID_OBJECT_STATE)) + { + /* this happens for online snapshots, there the attachment + * is changing, but only to a diff image created under + * the old one, so there is no separate lock list */ + Assert(!pMediumLockList); + } + else { - rc = mData->mSession.mLockedMedia.Remove(pAttach); AssertComRC(rc); + if (pMediumLockList) + { + rc = mData->mSession.mLockedMedia.Remove(pAttach); + AssertComRC(rc); + } } } } @@ -10881,11 +11935,10 @@ void Machine::commitMedia(bool aOnline /*= false*/) void Machine::rollbackMedia() { AutoCaller autoCaller(this); - AssertComRCReturnVoid (autoCaller.rc()); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + AssertComRCReturnVoid(autoCaller.rc()); - LogFlowThisFunc(("Entering\n")); + // AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + LogFlowThisFunc(("Entering rollbackMedia\n")); HRESULT rc = S_OK; @@ -10927,7 +11980,7 @@ void Machine::rollbackMedia() /** @todo convert all this Machine-based voodoo to MediumAttachment * based rollback logic. */ - deleteImplicitDiffs(); + deleteImplicitDiffs(Global::IsOnline(mData->mMachineState)); return; } @@ -11011,6 +12064,40 @@ void Machine::rollback(bool aNotify) } } + if (!mUSBControllers.isNull()) + { + if (mUSBControllers.isBackedUp()) + { + /* unitialize all new devices (absent in the backed up list). */ + USBControllerList::const_iterator it = mUSBControllers->begin(); + USBControllerList *backedList = mUSBControllers.backedUpData(); + while (it != mUSBControllers->end()) + { + if ( std::find(backedList->begin(), backedList->end(), *it) + == backedList->end() + ) + { + (*it)->uninit(); + } + ++it; + } + + /* restore the list */ + mUSBControllers.rollback(); + } + + /* rollback any changes to devices after restoring the list */ + if (mData->flModifications & IsModified_USB) + { + USBControllerList::const_iterator it = mUSBControllers->begin(); + while (it != mUSBControllers->end()) + { + (*it)->rollback(); + ++it; + } + } + } + mUserData.rollback(); mHWData.rollback(); @@ -11027,8 +12114,8 @@ void Machine::rollback(bool aNotify) if (mAudioAdapter) mAudioAdapter->rollback(); - if (mUSBController && (mData->flModifications & IsModified_USB)) - mUSBController->rollback(); + if (mUSBDeviceFilters && (mData->flModifications & IsModified_USB)) + mUSBDeviceFilters->rollback(); if (mBandwidthControl && (mData->flModifications & IsModified_BandwidthControl)) mBandwidthControl->rollback(); @@ -11128,12 +12215,12 @@ void Machine::commit() mHWData.commit(); if (mMediaData.isBackedUp()) - commitMedia(); + commitMedia(Global::IsOnline(mData->mMachineState)); mBIOSSettings->commit(); mVRDEServer->commit(); mAudioAdapter->commit(); - mUSBController->commit(); + mUSBDeviceFilters->commit(); mBandwidthControl->commit(); /* Since mNetworkAdapters is a list which might have been changed (resized) @@ -11263,6 +12350,77 @@ void Machine::commit() } } + bool commitUSBControllers = false; + + if (mUSBControllers.isBackedUp()) + { + mUSBControllers.commit(); + + if (mPeer) + { + /* Commit all changes to new controllers (this will reshare data with + * peers for those who have peers) */ + USBControllerList *newList = new USBControllerList(); + USBControllerList::const_iterator it = mUSBControllers->begin(); + while (it != mUSBControllers->end()) + { + (*it)->commit(); + + /* look if this controller has a peer device */ + ComObjPtr peer = (*it)->getPeer(); + if (!peer) + { + /* no peer means the device is a newly created one; + * create a peer owning data this device share it with */ + peer.createObject(); + peer->init(mPeer, *it, true /* aReshare */); + } + else + { + /* remove peer from the old list */ + mPeer->mUSBControllers->remove(peer); + } + /* and add it to the new list */ + newList->push_back(peer); + + ++it; + } + + /* uninit old peer's controllers that are left */ + it = mPeer->mUSBControllers->begin(); + while (it != mPeer->mUSBControllers->end()) + { + (*it)->uninit(); + ++it; + } + + /* attach new list of controllers to our peer */ + mPeer->mUSBControllers.attach(newList); + } + else + { + /* we have no peer (our parent is the newly created machine); + * just commit changes to devices */ + commitUSBControllers = true; + } + } + else + { + /* the list of controllers itself is not changed, + * just commit changes to controllers themselves */ + commitUSBControllers = true; + } + + if (commitUSBControllers) + { + USBControllerList::const_iterator it = mUSBControllers->begin(); + while (it != mUSBControllers->end()) + { + (*it)->commit(); + ++it; + } + } + if (isSessionMachine()) { /* attach new data to the primary machine and reshare it */ @@ -11311,7 +12469,7 @@ void Machine::copyFrom(Machine *aThat) mBIOSSettings->copyFrom(aThat->mBIOSSettings); mVRDEServer->copyFrom(aThat->mVRDEServer); mAudioAdapter->copyFrom(aThat->mAudioAdapter); - mUSBController->copyFrom(aThat->mUSBController); + mUSBDeviceFilters->copyFrom(aThat->mUSBDeviceFilters); mBandwidthControl->copyFrom(aThat->mBandwidthControl); /* create private copies of all controllers */ @@ -11327,6 +12485,19 @@ void Machine::copyFrom(Machine *aThat) mStorageControllers->push_back(ctrl); } + /* create private copies of all USB controllers */ + mUSBControllers.backup(); + mUSBControllers->clear(); + for (USBControllerList::iterator it = aThat->mUSBControllers->begin(); + it != aThat->mUSBControllers->end(); + ++it) + { + ComObjPtr ctrl; + ctrl.createObject(); + ctrl->initCopy(this, *it); + mUSBControllers->push_back(ctrl); + } + mNetworkAdapters.resize(aThat->mNetworkAdapters.size()); for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) mNetworkAdapters[slot]->copyFrom(aThat->mNetworkAdapters[slot]); @@ -11363,6 +12534,26 @@ bool Machine::isControllerHotplugCapable(StorageControllerType_T enmCtrlType) #ifdef VBOX_WITH_RESOURCE_USAGE_API +void Machine::getDiskList(MediaList &list) +{ + for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin(); + it != mMediaData->mAttachments.end(); + ++it) + { + MediumAttachment* pAttach = *it; + /* just in case */ + AssertStmt(pAttach, continue); + + AutoCaller localAutoCallerA(pAttach); + if (FAILED(localAutoCallerA.rc())) continue; + + AutoReadLock local_alockA(pAttach COMMA_LOCKVAL_SRC_POS); + + if (pAttach->getType() == DeviceType_HardDisk) + list.push_back(pAttach->getMedium()); + } +} + void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachine, RTPROCESS pid) { AssertReturnVoid(isWriteLockOnCurrentThread()); @@ -11376,6 +12567,12 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin "Percentage of processor time spent in kernel mode by the VM process."); pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used", "Size of resident portion of VM process in memory."); + pm::SubMetric *diskUsageUsed = new pm::SubMetric("Disk/Usage/Used", + "Actual size of all VM disks combined."); + pm::SubMetric *machineNetRx = new pm::SubMetric("Net/Rate/Rx", + "Network receive rate."); + pm::SubMetric *machineNetTx = new pm::SubMetric("Net/Rate/Tx", + "Network transmit rate."); /* Create and register base metrics */ pm::BaseMetric *cpuLoad = new pm::MachineCpuLoadRaw(hal, aMachine, pid, cpuLoadUser, cpuLoadKernel); @@ -11383,6 +12580,11 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin pm::BaseMetric *ramUsage = new pm::MachineRamUsage(hal, aMachine, pid, ramUsageUsed); aCollector->registerBaseMetric(ramUsage); + MediaList disks; + getDiskList(disks); + pm::BaseMetric *diskUsage = new pm::MachineDiskUsage(hal, aMachine, disks, + diskUsageUsed); + aCollector->registerBaseMetric(diskUsage); aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0)); aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, @@ -11407,6 +12609,14 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, new pm::AggregateMax())); + aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed, 0)); + aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed, + new pm::AggregateAvg())); + aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed, + new pm::AggregateMin())); + aCollector->registerMetric(new pm::Metric(diskUsage, diskUsageUsed, + new pm::AggregateMax())); + /* Guest metrics collector */ mCollectorGuest = new pm::CollectorGuest(aMachine, pid); @@ -11432,6 +12642,10 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin pm::SubMetric *guestPagedTotal = new pm::SubMetric("Guest/Pagefile/Usage/Total", "Total amount of space in the page file."); /* Create and register base metrics */ + pm::BaseMetric *machineNetRate = new pm::MachineNetRate(mCollectorGuest, aMachine, + machineNetRx, machineNetTx); + aCollector->registerBaseMetric(machineNetRate); + pm::BaseMetric *guestCpuLoad = new pm::GuestCpuLoad(mCollectorGuest, aMachine, guestLoadUser, guestLoadKernel, guestLoadIdle); aCollector->registerBaseMetric(guestCpuLoad); @@ -11442,6 +12656,16 @@ void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachin guestMemCache, guestPagedTotal); aCollector->registerBaseMetric(guestCpuMem); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, 0)); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateAvg())); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateMin())); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetRx, new pm::AggregateMax())); + + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, 0)); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateAvg())); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateMin())); + aCollector->registerMetric(new pm::Metric(machineNetRate, machineNetTx, new pm::AggregateMax())); + aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, 0)); aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateAvg())); aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateMin())); @@ -11510,15 +12734,7 @@ HRESULT SessionMachine::FinalConstruct() { LogFlowThisFunc(("\n")); -#if defined(RT_OS_WINDOWS) - mIPCSem = NULL; -#elif defined(RT_OS_OS2) - mIPCSem = NULLHANDLE; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - mIPCSem = -1; -#else -# error "Port me!" -#endif + mClientToken = NULL; return BaseFinalConstruct(); } @@ -11527,13 +12743,21 @@ void SessionMachine::FinalRelease() { LogFlowThisFunc(("\n")); + Assert(!mClientToken); + /* paranoia, should not hang around any more */ + if (mClientToken) + { + delete mClientToken; + mClientToken = NULL; + } + uninit(Uninit::Unexpected); BaseFinalRelease(); } /** - * @note Must be called only by Machine::openSession() from its own write lock. + * @note Must be called only by Machine::LockMachine() from its own write lock. */ HRESULT SessionMachine::init(Machine *aMachine) { @@ -11548,96 +12772,25 @@ HRESULT SessionMachine::init(Machine *aMachine) AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); - /* create the interprocess semaphore */ -#if defined(RT_OS_WINDOWS) - mIPCSemName = aMachine->mData->m_strConfigFileFull; - for (size_t i = 0; i < mIPCSemName.length(); i++) - if (mIPCSemName.raw()[i] == '\\') - mIPCSemName.raw()[i] = '/'; - mIPCSem = ::CreateMutex(NULL, FALSE, mIPCSemName.raw()); - ComAssertMsgRet(mIPCSem, - ("Cannot create IPC mutex '%ls', err=%d", - mIPCSemName.raw(), ::GetLastError()), - E_FAIL); -#elif defined(RT_OS_OS2) - Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}", - aMachine->mData->mUuid.raw()); - mIPCSemName = ipcSem; - APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mIPCSem, 0, FALSE); - ComAssertMsgRet(arc == NO_ERROR, - ("Cannot create IPC mutex '%s', arc=%ld", - ipcSem.c_str(), arc), - E_FAIL); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN -# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64) - /** @todo Check that this still works correctly. */ - AssertCompileSize(key_t, 8); -# else - AssertCompileSize(key_t, 4); -# endif - key_t key; - mIPCSem = -1; - mIPCKey = "0"; - for (uint32_t i = 0; i < 1 << 24; i++) - { - key = ((uint32_t)'V' << 24) | i; - int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL); - if (sem >= 0 || (errno != EEXIST && errno != EACCES)) - { - mIPCSem = sem; - if (sem >= 0) - mIPCKey = BstrFmt("%u", key); - break; - } - } -# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ - Utf8Str semName = aMachine->mData->m_strConfigFileFull; - char *pszSemName = NULL; - RTStrUtf8ToCurrentCP(&pszSemName, semName); - key_t key = ::ftok(pszSemName, 'V'); - RTStrFree(pszSemName); - - mIPCSem = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT); -# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ + HRESULT rc = S_OK; - int errnoSave = errno; - if (mIPCSem < 0 && errnoSave == ENOSYS) + /* create the machine client token */ + try { - setError(E_FAIL, - tr("Cannot create IPC semaphore. Most likely your host kernel lacks " - "support for SysV IPC. Check the host kernel configuration for " - "CONFIG_SYSVIPC=y")); - return E_FAIL; + mClientToken = new ClientToken(aMachine, this); + if (!mClientToken->isReady()) + { + delete mClientToken; + mClientToken = NULL; + rc = E_FAIL; + } } - /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing - * the IPC semaphores */ - if (mIPCSem < 0 && errnoSave == ENOSPC) - { -#ifdef RT_OS_LINUX - setError(E_FAIL, - tr("Cannot create IPC semaphore because the system limit for the " - "maximum number of semaphore sets (SEMMNI), or the system wide " - "maximum number of semaphores (SEMMNS) would be exceeded. The " - "current set of SysV IPC semaphores can be determined from " - "the file /proc/sysvipc/sem")); -#else - setError(E_FAIL, - tr("Cannot create IPC semaphore because the system-imposed limit " - "on the maximum number of allowed semaphores or semaphore " - "identifiers system-wide would be exceeded")); -#endif - return E_FAIL; + catch (std::bad_alloc &) + { + rc = E_OUTOFMEMORY; } - ComAssertMsgRet(mIPCSem >= 0, ("Cannot create IPC semaphore, errno=%d", errnoSave), - E_FAIL); - /* set the initial value to 1 */ - int rv = ::semctl(mIPCSem, 0, SETVAL, 1); - ComAssertMsgRet(rv == 0, ("Cannot init IPC semaphore, errno=%d", errno), - E_FAIL); -#else -# error "Port me!" -#endif + if (FAILED(rc)) + return rc; /* memorize the peer Machine */ unconst(mPeer) = aMachine; @@ -11663,6 +12816,17 @@ HRESULT SessionMachine::init(Machine *aMachine) mStorageControllers->push_back(ctl); } + mUSBControllers.allocate(); + for (USBControllerList::const_iterator it = aMachine->mUSBControllers->begin(); + it != aMachine->mUSBControllers->end(); + ++it) + { + ComObjPtr ctl; + ctl.createObject(); + ctl->init(this, *it); + mUSBControllers->push_back(ctl); + } + unconst(mBIOSSettings).createObject(); mBIOSSettings->init(this, aMachine->mBIOSSettings); /* create another VRDEServer object that will be mutable */ @@ -11683,9 +12847,10 @@ HRESULT SessionMachine::init(Machine *aMachine) unconst(mParallelPorts[slot]).createObject(); mParallelPorts[slot]->init(this, aMachine->mParallelPorts[slot]); } - /* create another USB controller object that will be mutable */ - unconst(mUSBController).createObject(); - mUSBController->init(this, aMachine->mUSBController); + + /* create another USB device filters object that will be mutable */ + unconst(mUSBDeviceFilters).createObject(); + mUSBDeviceFilters->init(this, aMachine->mUSBDeviceFilters); /* create a list of network adapters that will be mutable */ mNetworkAdapters.resize(aMachine->mNetworkAdapters.size()); @@ -11705,13 +12870,16 @@ HRESULT SessionMachine::init(Machine *aMachine) /* Confirm a successful initialization when it's the case */ autoInitSpan.setSucceeded(); + miNATNetworksStarted = 0; + LogFlowThisFuncLeave(); - return S_OK; + return rc; } /** * Uninitializes this session object. If the reason is other than - * Uninit::Unexpected, then this method MUST be called from #checkForDeath(). + * Uninit::Unexpected, then this method MUST be called from #checkForDeath() + * or the client watcher code. * * @param aReason uninitialization reason * @@ -11747,24 +12915,12 @@ void SessionMachine::uninit(Uninit::Reason aReason) * below, the following is enough. */ LogFlowThisFunc(("Initialization failed.\n")); -#if defined(RT_OS_WINDOWS) - if (mIPCSem) - ::CloseHandle(mIPCSem); - mIPCSem = NULL; -#elif defined(RT_OS_OS2) - if (mIPCSem != NULLHANDLE) - ::DosCloseMutexSem(mIPCSem); - mIPCSem = NULLHANDLE; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - if (mIPCSem >= 0) - ::semctl(mIPCSem, 0, IPC_RMID); - mIPCSem = -1; -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN - mIPCKey = "0"; -# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */ -#else -# error "Port me!" -#endif + /* destroy the machine client token */ + if (mClientToken) + { + delete mClientToken; + mClientToken = NULL; + } uninitDataAndChildObjects(); mData.free(); unconst(mParent) = NULL; @@ -11792,7 +12948,7 @@ void SessionMachine::uninit(Uninit::Reason aReason) * * This is identical to SessionMachine::DetachAllUSBDevices except * for the aAbnormal argument. */ - HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */); + HRESULT rc = mUSBDeviceFilters->notifyProxy(false /* aInsertFilters */); AssertComRC(rc); NOREF(rc); @@ -11803,23 +12959,17 @@ void SessionMachine::uninit(Uninit::Reason aReason) #endif /* VBOX_WITH_USB */ // we need to lock this object in uninit() because the lock is shared - // with mPeer (as well as data we modify below). mParent->addProcessToReap() - // and others need mParent lock, and USB needs host lock. + // with mPeer (as well as data we modify below). mParent lock is needed + // by several calls to it, and USB needs host lock. AutoMultiWriteLock3 multilock(mParent, mParent->host(), this COMMA_LOCKVAL_SRC_POS); -#if 0 - // Trigger async cleanup tasks, avoid doing things here which are not - // vital to be done immediately and maybe need more locks. This calls - // Machine::unregisterMetrics(). - mParent->onMachineUninit(mPeer); -#else +#ifdef VBOX_WITH_RESOURCE_USAGE_API /* * It is safe to call Machine::unregisterMetrics() here because * PerformanceCollector::samplerCallback no longer accesses guest methods * holding the lock. */ unregisterMetrics(mParent->performanceCollector(), mPeer); -#endif /* The guest must be unregistered after its metrics (@bugref{5949}). */ LogAleksey(("{%p} " LOG_FN_FMT ": mCollectorGuest=%p\n", this, __PRETTY_FUNCTION__, mCollectorGuest)); @@ -11829,6 +12979,7 @@ void SessionMachine::uninit(Uninit::Reason aReason) // delete mCollectorGuest; => CollectorGuestManager::destroyUnregistered() mCollectorGuest = NULL; } +#endif if (aReason == Uninit::Abnormal) { @@ -11870,16 +13021,6 @@ void SessionMachine::uninit(Uninit::Reason aReason) releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ ); } - if (!mData->mSession.mType.isEmpty()) - { - /* mType is not null when this machine's process has been started by - * Machine::LaunchVMProcess(), therefore it is our child. We - * need to queue the PID to reap the process (and avoid zombies on - * Linux). */ - Assert(mData->mSession.mPID != NIL_RTPROCESS); - mParent->addProcessToReap(mData->mSession.mPID); - } - mData->mSession.mPID = NIL_RTPROCESS; if (aReason == Uninit::Unexpected) @@ -11910,6 +13051,33 @@ void SessionMachine::uninit(Uninit::Reason aReason) mData->mSession.mRemoteControls.clear(); } + /* Remove all references to the NAT network service. The service will stop + * if all references (also from other VMs) are removed. */ + for (; miNATNetworksStarted > 0; miNATNetworksStarted--) + { + for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) + { + NetworkAttachmentType_T type; + HRESULT hrc; + + hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); + if ( SUCCEEDED(hrc) + && type == NetworkAttachmentType_NATNetwork) + { + Bstr name; + hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); + if (SUCCEEDED(hrc)) + { + multilock.release(); + LogRel(("VM '%s' stops using NAT network '%ls'\n", + mUserData->s.strName.c_str(), name.raw())); + mParent->natNetworkRefDec(name.raw()); + multilock.acquire(); + } + } + } + } + /* * An expected uninitialization can come only from #checkForDeath(). * Otherwise it means that something's gone really wrong (for example, @@ -11957,25 +13125,12 @@ void SessionMachine::uninit(Uninit::Reason aReason) mData->mSession.mState = SessionState_Unlocked; mData->mSession.mType.setNull(); - /* close the interprocess semaphore before leaving the exclusive lock */ -#if defined(RT_OS_WINDOWS) - if (mIPCSem) - ::CloseHandle(mIPCSem); - mIPCSem = NULL; -#elif defined(RT_OS_OS2) - if (mIPCSem != NULLHANDLE) - ::DosCloseMutexSem(mIPCSem); - mIPCSem = NULLHANDLE; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - if (mIPCSem >= 0) - ::semctl(mIPCSem, 0, IPC_RMID); - mIPCSem = -1; -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN - mIPCKey = "0"; -# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */ -#else -# error "Port me!" -#endif + /* destroy the machine client token before leaving the exclusive lock */ + if (mClientToken) + { + delete mClientToken; + mClientToken = NULL; + } /* fire an event */ mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked); @@ -12013,21 +13168,42 @@ RWLockHandle *SessionMachine::lockHandle() const /** * Passes collected guest statistics to performance collector object */ -STDMETHODIMP SessionMachine::ReportGuestStatistics(ULONG aValidStats, ULONG aCpuUser, - ULONG aCpuKernel, ULONG aCpuIdle, - ULONG aMemTotal, ULONG aMemFree, - ULONG aMemBalloon, ULONG aMemShared, - ULONG aMemCache, ULONG aPageTotal, - ULONG aAllocVMM, ULONG aFreeVMM, - ULONG aBalloonedVMM, ULONG aSharedVMM) +STDMETHODIMP SessionMachine::ReportVmStatistics(ULONG aValidStats, ULONG aCpuUser, + ULONG aCpuKernel, ULONG aCpuIdle, + ULONG aMemTotal, ULONG aMemFree, + ULONG aMemBalloon, ULONG aMemShared, + ULONG aMemCache, ULONG aPageTotal, + ULONG aAllocVMM, ULONG aFreeVMM, + ULONG aBalloonedVMM, ULONG aSharedVMM, + ULONG aVmNetRx, ULONG aVmNetTx) { +#ifdef VBOX_WITH_RESOURCE_USAGE_API if (mCollectorGuest) mCollectorGuest->updateStats(aValidStats, aCpuUser, aCpuKernel, aCpuIdle, aMemTotal, aMemFree, aMemBalloon, aMemShared, aMemCache, aPageTotal, aAllocVMM, aFreeVMM, - aBalloonedVMM, aSharedVMM); + aBalloonedVMM, aSharedVMM, aVmNetRx, aVmNetTx); return S_OK; +#else + NOREF(aValidStats); + NOREF(aCpuUser); + NOREF(aCpuKernel); + NOREF(aCpuIdle); + NOREF(aMemTotal); + NOREF(aMemFree); + NOREF(aMemBalloon); + NOREF(aMemShared); + NOREF(aMemCache); + NOREF(aPageTotal); + NOREF(aAllocVMM); + NOREF(aFreeVMM); + NOREF(aBalloonedVMM); + NOREF(aSharedVMM); + NOREF(aVmNetRx); + NOREF(aVmNetTx); + return E_NOTIMPL; +#endif } /** @@ -12053,31 +13229,6 @@ STDMETHODIMP SessionMachine::UpdateState(MachineState_T aMachineState) return setMachineState(aMachineState); } -/** - * @note Locks this object for reading. - */ -STDMETHODIMP SessionMachine::GetIPCId(BSTR *aId) -{ - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - -#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) - mIPCSemName.cloneTo(aId); - return S_OK; -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) -# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN - mIPCKey.cloneTo(aId); -# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ - mData->m_strConfigFileFull.cloneTo(aId); -# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ - return S_OK; -#else -# error "Port me!" -#endif -} - /** * @note Locks this object for writing. */ @@ -12095,6 +13246,37 @@ STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress) if (!mData->mSession.mProgress.isNull()) mData->mSession.mProgress->setOtherProgressObject(aProgress); + /* If we didn't reference the NAT network service yet, add a reference to + * force a start */ + if (miNATNetworksStarted < 1) + { + for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) + { + NetworkAttachmentType_T type; + HRESULT hrc; + hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); + if ( SUCCEEDED(hrc) + && type == NetworkAttachmentType_NATNetwork) + { + Bstr name; + hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); + if (SUCCEEDED(hrc)) + { + LogRel(("VM '%s' starts using NAT network '%ls'\n", + mUserData->s.strName.c_str(), name.raw())); + mPeer->lockHandle()->unlockWrite(); + mParent->natNetworkRefInc(name.raw()); +#ifdef RT_LOCK_STRICT + mPeer->lockHandle()->lockWrite(RT_SRC_POS); +#else + mPeer->lockHandle()->lockWrite(); +#endif + } + } + } + miNATNetworksStarted++; + } + LogFlowThisFunc(("returns S_OK.\n")); return S_OK; } @@ -12240,7 +13422,7 @@ STDMETHODIMP SessionMachine::RunUSBDeviceFilters(IUSBDevice *aUSBDevice, AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); #ifdef VBOX_WITH_USB - *aMatched = mUSBController->hasMatchingFilter(aUSBDevice, aMaskedIfs); + *aMatched = mUSBDeviceFilters->hasMatchingFilter(aUSBDevice, aMaskedIfs); #else NOREF(aUSBDevice); NOREF(aMaskedIfs); @@ -12312,7 +13494,7 @@ STDMETHODIMP SessionMachine::AutoCaptureUSBDevices() AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); #ifdef VBOX_WITH_USB - HRESULT rc = mUSBController->notifyProxy(true /* aInsertFilters */); + HRESULT rc = mUSBDeviceFilters->notifyProxy(true /* aInsertFilters */); AssertComRC(rc); NOREF(rc); @@ -12342,7 +13524,7 @@ STDMETHODIMP SessionMachine::DetachAllUSBDevices(BOOL aDone) AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); #ifdef VBOX_WITH_USB - HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */); + HRESULT rc = mUSBDeviceFilters->notifyProxy(false /* aInsertFilters */); AssertComRC(rc); NOREF(rc); @@ -12591,18 +13773,18 @@ STDMETHODIMP SessionMachine::PullGuestProperties(ComSafeArrayOut(BSTR, aNames), com::SafeArray timestamps(cEntries); com::SafeArray flags(cEntries); unsigned i = 0; - for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin(); + for (HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.begin(); it != mHWData->mGuestProperties.end(); ++it) { char szFlags[MAX_FLAGS_LEN + 1]; - it->strName.cloneTo(&names[i]); - it->strValue.cloneTo(&values[i]); - timestamps[i] = it->mTimestamp; + it->first.cloneTo(&names[i]); + it->second.strValue.cloneTo(&values[i]); + timestamps[i] = it->second.mTimestamp; /* If it is NULL, keep it NULL. */ - if (it->mFlags) + if (it->second.mFlags) { - writeFlags(it->mFlags, szFlags); + writeFlags(it->second.mFlags, szFlags); Bstr(szFlags).cloneTo(&flags[i]); } else @@ -12638,8 +13820,8 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName, /* * Convert input up front. */ - Utf8Str utf8Name(aName); - uint32_t fFlags = NILFLAG; + Utf8Str utf8Name(aName); + uint32_t fFlags = NILFLAG; if (aFlags) { Utf8Str utf8Flags(aFlags); @@ -12665,43 +13847,40 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName, case MachineState_DeletingSnapshotOnline: case MachineState_DeletingSnapshotPaused: case MachineState_Saving: + case MachineState_Stopping: break; default: -#ifndef DEBUG_sunlover AssertMsgFailedReturn(("%s\n", Global::stringifyMachineState(mData->mMachineState)), VBOX_E_INVALID_VM_STATE); -#else - return VBOX_E_INVALID_VM_STATE; -#endif } setModified(IsModified_MachineData); mHWData.backup(); - /** @todo r=bird: The careful memory handling doesn't work out here because - * the catch block won't undo any damage we've done. So, if push_back throws - * bad_alloc then you've lost the value. - * - * Another thing. Doing a linear search here isn't extremely efficient, esp. - * since values that changes actually bubbles to the end of the list. Using - * something that has an efficient lookup and can tolerate a bit of updates - * would be nice. RTStrSpace is one suggestion (it's not perfect). Some - * combination of RTStrCache (for sharing names and getting uniqueness into - * the bargain) and hash/tree is another. */ - for (HWData::GuestPropertyList::iterator iter = mHWData->mGuestProperties.begin(); - iter != mHWData->mGuestProperties.end(); - ++iter) - if (utf8Name == iter->strName) + bool fDelete = !RT_VALID_PTR(aValue) || *(aValue) == '\0'; + HWData::GuestPropertyMap::iterator it = mHWData->mGuestProperties.find(utf8Name); + if (it != mHWData->mGuestProperties.end()) + { + if (!fDelete) { - mHWData->mGuestProperties.erase(iter); - mData->mGuestPropertiesModified = TRUE; - break; + it->second.strValue = aValue; + it->second.mTimestamp = aTimestamp; + it->second.mFlags = fFlags; } - if (aValue != NULL) + else + mHWData->mGuestProperties.erase(it); + + mData->mGuestPropertiesModified = TRUE; + } + else if (!fDelete) { - HWData::GuestProperty property = { aName, aValue, aTimestamp, fFlags }; - mHWData->mGuestProperties.push_back(property); + HWData::GuestProperty prop; + prop.strValue = aValue; + prop.mTimestamp = aTimestamp; + prop.mFlags = fFlags; + + mHWData->mGuestProperties[utf8Name] = prop; mData->mGuestPropertiesModified = TRUE; } @@ -12733,6 +13912,29 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName, #endif } +STDMETHODIMP SessionMachine::LockMedia() +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoMultiWriteLock2 alock(this->lockHandle(), + &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); + + AssertReturn( mData->mMachineState == MachineState_Starting + || mData->mMachineState == MachineState_Restoring + || mData->mMachineState == MachineState_TeleportingIn, E_FAIL); + + clearError(); + alock.release(); + return lockMedia(); +} + +STDMETHODIMP SessionMachine::UnlockMedia() +{ + unlockMedia(); + return S_OK; +} + STDMETHODIMP SessionMachine::EjectMedium(IMediumAttachment *aAttachment, IMediumAttachment **aNewAttachment) { @@ -12815,6 +14017,7 @@ STDMETHODIMP SessionMachine::EjectMedium(IMediumAttachment *aAttachment, // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// +#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER /** * Called from the client watcher thread to check for expected or unexpected * death of the client process that has a direct session to this machine. @@ -12860,47 +14063,56 @@ bool SessionMachine::checkForDeath() Uninit::Normal : Uninit::Abnormal; -#if defined(RT_OS_WINDOWS) - - AssertMsg(mIPCSem, ("semaphore must be created")); - - /* release the IPC mutex */ - ::ReleaseMutex(mIPCSem); - - terminated = true; + if (mClientToken) + terminated = mClientToken->release(); + } /* AutoCaller block */ -#elif defined(RT_OS_OS2) + if (terminated) + uninit(reason); - AssertMsg(mIPCSem, ("semaphore must be created")); + return terminated; +} - /* release the IPC mutex */ - ::DosReleaseMutexSem(mIPCSem); +void SessionMachine::getTokenId(Utf8Str &strTokenId) +{ + LogFlowThisFunc(("\n")); - terminated = true; + strTokenId.setNull(); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); - AssertMsg(mIPCSem >= 0, ("semaphore must be created")); + Assert(mClientToken); + if (mClientToken) + mClientToken->getId(strTokenId); +} +#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ +IToken *SessionMachine::getToken() +{ + LogFlowThisFunc(("\n")); - int val = ::semctl(mIPCSem, 0, GETVAL); - if (val > 0) - { - /* the semaphore is signaled, meaning the session is terminated */ - terminated = true; - } + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), NULL); -#else -# error "Port me!" -#endif + Assert(mClientToken); + if (mClientToken) + return mClientToken->getToken(); + else + return NULL; +} +#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ - } /* AutoCaller block */ +Machine::ClientToken *SessionMachine::getClientToken() +{ + LogFlowThisFunc(("\n")); - if (terminated) - uninit(reason); + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), NULL); - return terminated; + return mClientToken; } + /** * @note Locks this object for reading. */ @@ -13052,7 +14264,7 @@ HRESULT SessionMachine::onCPUChange(ULONG aCPU, BOOL aRemove) LogFlowThisFunc(("\n")); AutoCaller autoCaller(this); - AssertComRCReturn (autoCaller.rc(), autoCaller.rc()); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); ComPtr directControl; { @@ -13072,7 +14284,7 @@ HRESULT SessionMachine::onCPUExecutionCapChange(ULONG aExecutionCap) LogFlowThisFunc(("\n")); AutoCaller autoCaller(this); - AssertComRCReturn (autoCaller.rc(), autoCaller.rc()); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); ComPtr directControl; { @@ -13110,6 +14322,29 @@ HRESULT SessionMachine::onVRDEServerChange(BOOL aRestart) return directControl->OnVRDEServerChange(aRestart); } +/** + * @note Locks this object for reading. + */ +HRESULT SessionMachine::onVideoCaptureChange() +{ + LogFlowThisFunc(("\n")); + + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + ComPtr directControl; + { + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + directControl = mData->mSession.mDirectControl; + } + + /* ignore notifications sent after #OnSessionEnd() is called */ + if (!directControl) + return S_OK; + + return directControl->OnVideoCaptureChange(); +} + /** * @note Locks this object for reading. */ @@ -13210,7 +14445,7 @@ HRESULT SessionMachine::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) LogFlowThisFunc(("\n")); AutoCaller autoCaller(this); - AssertComRCReturn (autoCaller.rc(), autoCaller.rc()); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); ComPtr directControl; { @@ -13228,7 +14463,7 @@ HRESULT SessionMachine::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup) /** * @note Locks this object for reading. */ -HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BOOL aRemove) +HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BOOL aRemove, BOOL aSilent) { LogFlowThisFunc(("\n")); @@ -13245,7 +14480,7 @@ HRESULT SessionMachine::onStorageDeviceChange(IMediumAttachment *aAttachment, BO if (!directControl) return S_OK; - return directControl->OnStorageDeviceChange(aAttachment, aRemove); + return directControl->OnStorageDeviceChange(aAttachment, aRemove, aSilent); } /** @@ -13275,7 +14510,7 @@ bool SessionMachine::hasMatchingUSBFilter(const ComObjPtr &aDevic /** @todo Live Migration: snapshoting & teleporting. Need to fend things of * elsewhere... */ alock.release(); - return mUSBController->hasMatchingFilter(aDevice, aMaskedIfs); + return mUSBDeviceFilters->hasMatchingFilter(aDevice, aMaskedIfs); default: break; } #else @@ -13456,8 +14691,7 @@ void SessionMachine::releaseSavedStateFile(const Utf8Str &strStateFile, * locked as described above; on failure no media is locked at all (all * succeeded individual locks will be undone). * - * This method is intended to be called when the machine is in Starting or - * Restoring state and asserts otherwise. + * The caller is responsible for doing the necessary state sanity checks. * * The locks made by this method must be undone by calling #unlockMedia() when * no more needed. @@ -13470,13 +14704,9 @@ HRESULT SessionMachine::lockMedia() AutoMultiWriteLock2 alock(this->lockHandle(), &mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); - AssertReturn( mData->mMachineState == MachineState_Starting - || mData->mMachineState == MachineState_Restoring - || mData->mMachineState == MachineState_TeleportingIn, E_FAIL); /* bail out if trying to lock things with already set up locking */ AssertReturn(mData->mSession.mLockedMedia.IsEmpty(), E_FAIL); - clearError(); MultiResult mrc(S_OK); /* Collect locking information for all medium objects attached to the VM. */ @@ -13749,13 +14979,13 @@ HRESULT SessionMachine::setMachineState(MachineState_T aMachineState) /* Make sure any transient guest properties get removed from the * property store on shutdown. */ - HWData::GuestPropertyList::iterator it; + HWData::GuestPropertyMap::const_iterator it; BOOL fNeedsSaving = mData->mGuestPropertiesModified; if (!fNeedsSaving) for (it = mHWData->mGuestProperties.begin(); it != mHWData->mGuestProperties.end(); ++it) - if ( (it->mFlags & guestProp::TRANSIENT) - || (it->mFlags & guestProp::TRANSRESET)) + if ( (it->second.mFlags & guestProp::TRANSIENT) + || (it->second.mFlags & guestProp::TRANSRESET)) { fNeedsSaving = true; break; diff --git a/src/VBox/Main/src-server/MachineImplCloneVM.cpp b/src/VBox/Main/src-server/MachineImplCloneVM.cpp index d010a04f..cdc71b82 100644 --- a/src/VBox/Main/src-server/MachineImplCloneVM.cpp +++ b/src/VBox/Main/src-server/MachineImplCloneVM.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011-2012 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -174,11 +174,11 @@ void MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAtta * it. Adding the biggest size in the chain should balance this a * little bit more, i.e. the weight is the sum of the data which * needs to be read and written. */ - uint64_t uMaxSize = 0; + ULONG uMaxWeight = 0; for (size_t e = mtc.chain.size(); e > 0; --e) { MEDIUMTASK &mt = mtc.chain.at(e - 1); - mt.uWeight += uMaxSize; + mt.uWeight += uMaxWeight; /* Calculate progress data */ ++uCount; @@ -186,7 +186,7 @@ void MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAtta /* Save the max size for better weighting of diff image * creation. */ - uMaxSize = RT_MAX(uMaxSize, mt.uWeight); + uMaxWeight = RT_MAX(uMaxWeight, mt.uWeight); } } } @@ -207,7 +207,7 @@ HRESULT MachineCloneVMPrivate::addSaveState(const ComObjPtr &machine, U return p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not query file size of '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), vrc); /* same rule as above: count both the data which needs to * be read and written */ - sst.uWeight = 2 * (cbSize + _1M - 1) / _1M; + sst.uWeight = (ULONG)(2 * (cbSize + _1M - 1) / _1M); llSaveStateFiles.append(sst); ++uCount; uTotalWeight += sst.uWeight; @@ -289,7 +289,7 @@ HRESULT MachineCloneVMPrivate::queryMediasForMachineState(const RTCListsnapshotId.isEmpty()) + + if (d->snapshotId.isValid() && !d->snapshotId.isZero()) if (!d->findSnapshot(trgMCF.llFirstSnapshot, d->snapshotId, sn)) throw p->setError(E_FAIL, p->tr("Could not find data to snapshots '%s'"), d->snapshotId.toString().c_str()); @@ -959,7 +960,7 @@ HRESULT MachineCloneVM::run() if (d->mode == CloneMode_MachineState) { - if (!sn.uuid.isEmpty()) + if (sn.uuid.isValid() && !sn.uuid.isZero()) { trgMCF.hardwareMachine = sn.hardware; trgMCF.storageMachine = sn.storage; @@ -970,7 +971,8 @@ HRESULT MachineCloneVM::run() trgMCF.uuidCurrentSnapshot.clear(); } else if ( d->mode == CloneMode_MachineAndChildStates - && !sn.uuid.isEmpty()) + && sn.uuid.isValid() + && !sn.uuid.isZero()) { if (!d->pOldMachineState.isNull()) { @@ -1087,14 +1089,24 @@ HRESULT MachineCloneVM::run() ComPtr pSrcFormat; rc = pMedium->COMGETTER(MediumFormat)(pSrcFormat.asOutParam()); ULONG uSrcCaps = 0; - rc = pSrcFormat->COMGETTER(Capabilities)(&uSrcCaps); + com::SafeArray mediumFormatCap; + rc = pSrcFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); + if (FAILED(rc)) throw rc; + else + { + for (ULONG j = 0; j < mediumFormatCap.size(); j++) + uSrcCaps |= mediumFormatCap[j]; + } /* Default format? */ Utf8Str strDefaultFormat; p->mParent->getDefaultHardDiskFormat(strDefaultFormat); Bstr bstrSrcFormat(strDefaultFormat); + ULONG srcVar = MediumVariant_Standard; + com::SafeArray mediumVariant; + /* Is the source file based? */ if ((uSrcCaps & MediumFormatCapabilities_File) == MediumFormatCapabilities_File) { @@ -1102,8 +1114,14 @@ HRESULT MachineCloneVM::run() * will be used. */ rc = pMedium->COMGETTER(Format)(bstrSrcFormat.asOutParam()); if (FAILED(rc)) throw rc; - rc = pMedium->COMGETTER(Variant)(&srcVar); + + rc = pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(mediumVariant)); if (FAILED(rc)) throw rc; + else + { + for (size_t j = 0; j < mediumVariant.size(); j++) + srcVar |= mediumVariant[j]; + } } Guid newId; @@ -1128,7 +1146,9 @@ HRESULT MachineCloneVM::run() && strSrcTest.endsWith("}")) { strSrcTest = strSrcTest.substr(1, strSrcTest.length() - 2); - if (isValidGuid(strSrcTest)) + + Guid temp_guid(strSrcTest); + if (temp_guid.isValid() && !temp_guid.isZero()) strNewName = Utf8StrFmt("%s%s", newId.toStringCurly().c_str(), RTPathExt(strNewName.c_str())); } else @@ -1322,7 +1342,7 @@ HRESULT MachineCloneVM::run() } /* Update the path in the configuration either for the current * machine state or the snapshots. */ - if (sst.snapshotUuid.isEmpty()) + if (!sst.snapshotUuid.isValid() || sst.snapshotUuid.isZero()) trgMCF.strStateFile = strTrgSaveState; else d->updateStateFile(trgMCF.llFirstSnapshot, sst.snapshotUuid, strTrgSaveState); diff --git a/src/VBox/Main/src-server/Matching.cpp b/src/VBox/Main/src-server/Matching.cpp index 83174f92..a2e0a4aa 100644 --- a/src/VBox/Main/src-server/Matching.cpp +++ b/src/VBox/Main/src-server/Matching.cpp @@ -36,7 +36,7 @@ void ParsedIntervalFilter_base::parse (const char *aFilter, that->mValid = true; that->mErrorPosition = 0; - if (!aFilter || strncmp (aFilter, "int:", 4) != 0) + if (!aFilter || strncmp(aFilter, RT_STR_TUPLE("int:")) != 0) return; that->mNull = false; diff --git a/src/VBox/Main/src-server/MediumAttachmentImpl.cpp b/src/VBox/Main/src-server/MediumAttachmentImpl.cpp index 26dfeb34..6059ced6 100644 --- a/src/VBox/Main/src-server/MediumAttachmentImpl.cpp +++ b/src/VBox/Main/src-server/MediumAttachmentImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -42,7 +42,8 @@ struct BackupableMediumAttachmentData fTempEject(false), fNonRotational(false), fDiscard(false), - fImplicit(false) + fImplicit(false), + fHotPluggable(false) { } ComObjPtr pMedium; @@ -62,6 +63,7 @@ struct BackupableMediumAttachmentData bool fNonRotational; bool fDiscard; bool fImplicit; + bool fHotPluggable; }; struct MediumAttachment::Data @@ -122,10 +124,11 @@ HRESULT MediumAttachment::init(Machine *aParent, bool aTempEject, bool aNonRotational, bool aDiscard, + bool aHotPluggable, const Utf8Str &strBandwidthGroup) { LogFlowThisFuncEnter(); - LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, strBandwidthGroup.c_str())); + LogFlowThisFunc(("aParent=%p aMedium=%p aControllerName=%ls aPort=%d aDevice=%d aType=%d aImplicit=%d aPassthrough=%d aTempEject=%d aNonRotational=%d aDiscard=%d aHotPluggable=%d strBandwithGroup=%s\n", aParent, aMedium, aControllerName.raw(), aPort, aDevice, aType, aImplicit, aPassthrough, aTempEject, aNonRotational, aDiscard, aHotPluggable, strBandwidthGroup.c_str())); if (aType == DeviceType_HardDisk) AssertReturn(aMedium, E_INVALIDARG); @@ -151,6 +154,7 @@ HRESULT MediumAttachment::init(Machine *aParent, m->bd->fNonRotational = aNonRotational; m->bd->fDiscard = aDiscard; m->bd->fImplicit = aImplicit; + m->bd->fHotPluggable = aHotPluggable; /* Confirm a successful initialization when it's the case */ autoInitSpan.setSucceeded(); @@ -416,6 +420,23 @@ STDMETHODIMP MediumAttachment::COMGETTER(BandwidthGroup) (IBandwidthGroup **aBwG return hrc; } +STDMETHODIMP MediumAttachment::COMGETTER(HotPluggable)(BOOL *aHotPluggable) +{ + LogFlowThisFuncEnter(); + + CheckComArgOutPointerValid(aHotPluggable); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS); + + *aHotPluggable = m->bd->fHotPluggable; + + LogFlowThisFuncLeave(); + return S_OK; +} + /** * @note Locks this object for writing. */ @@ -512,6 +533,12 @@ bool MediumAttachment::getDiscard() const return m->bd->fDiscard; } +bool MediumAttachment::getHotPluggable() const +{ + AutoReadLock lock(this COMMA_LOCKVAL_SRC_POS); + return m->bd->fHotPluggable; +} + const Utf8Str& MediumAttachment::getBandwidthGroup() const { return m->bd->strBandwidthGroup; @@ -582,6 +609,15 @@ void MediumAttachment::updateDiscard(bool aDiscard) m->bd->fDiscard = aDiscard; } +/** Must be called from under this object's write lock. */ +void MediumAttachment::updateHotPluggable(bool aHotPluggable) +{ + Assert(isWriteLockOnCurrentThread()); + + m->bd.backup(); + m->bd->fHotPluggable = aHotPluggable; +} + void MediumAttachment::updateBandwidthGroup(const Utf8Str &aBandwidthGroup) { LogFlowThisFuncEnter(); diff --git a/src/VBox/Main/src-server/MediumFormatImpl.cpp b/src/VBox/Main/src-server/MediumFormatImpl.cpp index 71080e43..bd07fbf1 100644 --- a/src/VBox/Main/src-server/MediumFormatImpl.cpp +++ b/src/VBox/Main/src-server/MediumFormatImpl.cpp @@ -1,11 +1,11 @@ /* $Id: MediumFormatImpl.cpp $ */ /** @file * - * VirtualBox COM class implementation + * MediumFormat COM class implementation */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -75,7 +75,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo) { DeviceType_T devType; - unconst(m.llFileExtensions).push_back(papExtension->pszExtension); + unconst(m.maFileExtensions).push_back(papExtension->pszExtension); switch(papExtension->enmType) { @@ -93,7 +93,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo) return E_INVALIDARG; } - unconst(m.llDeviceTypes).push_back(devType); + unconst(m.maDeviceTypes).push_back(devType); ++papExtension; } } @@ -156,7 +156,7 @@ HRESULT MediumFormat::init(const VDBACKENDINFO *aVDInfo) dt, flags, defaultValue }; - unconst(m.llProperties).push_back(prop); + unconst(m.maProperties).push_back(prop); ++pa; } } @@ -180,9 +180,9 @@ void MediumFormat::uninit() if (autoUninitSpan.uninitDone()) return; - unconst(m.llProperties).clear(); - unconst(m.llFileExtensions).clear(); - unconst(m.llDeviceTypes).clear(); + unconst(m.maProperties).clear(); + unconst(m.maFileExtensions).clear(); + unconst(m.maDeviceTypes).clear(); unconst(m.capabilities) = (MediumFormatCapabilities_T)0; unconst(m.strName).setNull(); unconst(m.strId).setNull(); @@ -191,129 +191,79 @@ void MediumFormat::uninit() // IMediumFormat properties ///////////////////////////////////////////////////////////////////////////// -STDMETHODIMP MediumFormat::COMGETTER(Id)(BSTR *aId) +HRESULT MediumFormat::getId(com::Utf8Str &aId) { - CheckComArgOutPointerValid(aId); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* this is const, no need to lock */ - m.strId.cloneTo(aId); + aId = m.strId; return S_OK; } -STDMETHODIMP MediumFormat::COMGETTER(Name)(BSTR *aName) +HRESULT MediumFormat::getName(com::Utf8Str &aName) { - CheckComArgOutPointerValid(aName); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* this is const, no need to lock */ - m.strName.cloneTo(aName); + aName = m.strName; return S_OK; } -STDMETHODIMP MediumFormat::COMGETTER(Capabilities)(ULONG *aCaps) +HRESULT MediumFormat::getCapabilities(std::vector &aCapabilities) { - CheckComArgOutPointerValid(aCaps); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* m.capabilities is const, no need to lock */ - /// @todo add COMGETTER(ExtendedCapabilities) when we reach the 32 bit - /// limit (or make the argument ULONG64 after checking that COM is capable - /// of defining enums (used to represent bit flags) that contain 64-bit - /// values). Or go away from the enum/ulong hack for bit sets and use - /// a safearray like elsewhere. - ComAssertRet((uint64_t)m.capabilities == ((ULONG)m.capabilities), E_FAIL); - - *aCaps = (ULONG)m.capabilities; + aCapabilities.resize(sizeof(MediumFormatCapabilities_T) * 8); + size_t cCapabilities = 0; + for (size_t i = 0; i < aCapabilities.size(); i++) + { + uint64_t tmp = m.capabilities; + tmp &= 1ULL << i; + if (tmp) + aCapabilities[cCapabilities++] = (MediumFormatCapabilities_T)tmp; + } + aCapabilities.resize(RT_MAX(cCapabilities, 1)); return S_OK; } -STDMETHODIMP MediumFormat::DescribeFileExtensions(ComSafeArrayOut(BSTR, aFileExtensions), - ComSafeArrayOut(DeviceType_T, aDeviceTypes)) -{ - CheckComArgOutSafeArrayPointerValid(aFileExtensions); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); +// IMediumFormat methods +///////////////////////////////////////////////////////////////////////////// +HRESULT MediumFormat::describeFileExtensions(std::vector &aExtensions, + std::vector &aTypes) +{ /* this is const, no need to lock */ - com::SafeArray fileExtentions(m.llFileExtensions.size()); - int i = 0; - for (StrList::const_iterator it = m.llFileExtensions.begin(); - it != m.llFileExtensions.end(); - ++it, ++i) - (*it).cloneTo(&fileExtentions[i]); - fileExtentions.detachTo(ComSafeArrayOutArg(aFileExtensions)); - - com::SafeArray deviceTypes(m.llDeviceTypes.size()); - i = 0; - for (DeviceTypeList::const_iterator it = m.llDeviceTypes.begin(); - it != m.llDeviceTypes.end(); - ++it, ++i) - deviceTypes[i] = (*it); - deviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes)); + aExtensions = m.maFileExtensions; + aTypes = m.maDeviceTypes; return S_OK; } -STDMETHODIMP MediumFormat::DescribeProperties(ComSafeArrayOut(BSTR, aNames), - ComSafeArrayOut(BSTR, aDescriptions), - ComSafeArrayOut(DataType_T, aTypes), - ComSafeArrayOut(ULONG, aFlags), - ComSafeArrayOut(BSTR, aDefaults)) +HRESULT MediumFormat::describeProperties(std::vector &aNames, + std::vector &aDescriptions, + std::vector &aTypes, + std::vector &aFlags, + std::vector &aDefaults) { - CheckComArgOutSafeArrayPointerValid(aNames); - CheckComArgOutSafeArrayPointerValid(aDescriptions); - CheckComArgOutSafeArrayPointerValid(aTypes); - CheckComArgOutSafeArrayPointerValid(aFlags); - CheckComArgOutSafeArrayPointerValid(aDefaults); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* this is const, no need to lock */ - size_t c = m.llProperties.size(); - com::SafeArray propertyNames(c); - com::SafeArray propertyDescriptions(c); - com::SafeArray propertyTypes(c); - com::SafeArray propertyFlags(c); - com::SafeArray propertyDefaults(c); - - int i = 0; - for (PropertyList::const_iterator it = m.llProperties.begin(); - it != m.llProperties.end(); - ++it, ++i) + size_t c = m.maProperties.size(); + aNames.resize(c); + aDescriptions.resize(c); + aTypes.resize(c); + aFlags.resize(c); + aDefaults.resize(c); + for (size_t i = 0; i < c; i++) { - const Property &prop = (*it); - prop.strName.cloneTo(&propertyNames[i]); - prop.strDescription.cloneTo(&propertyDescriptions[i]); - propertyTypes[i] = prop.type; - propertyFlags[i] = prop.flags; - prop.strDefaultValue.cloneTo(&propertyDefaults[i]); + const Property &prop = m.maProperties[i]; + aNames[i] = prop.strName; + aDescriptions[i] = prop.strDescription; + aTypes[i] = prop.type; + aFlags[i] = prop.flags; + aDefaults[i] = prop.strDefaultValue; } - propertyNames.detachTo(ComSafeArrayOutArg(aNames)); - propertyDescriptions.detachTo(ComSafeArrayOutArg(aDescriptions)); - propertyTypes.detachTo(ComSafeArrayOutArg(aTypes)); - propertyFlags.detachTo(ComSafeArrayOutArg(aFlags)); - propertyDefaults.detachTo(ComSafeArrayOutArg(aDefaults)); - return S_OK; } -// IMediumFormat methods -///////////////////////////////////////////////////////////////////////////// - // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/MediumImpl.cpp b/src/VBox/Main/src-server/MediumImpl.cpp index 64edc67f..3e5da5b3 100644 --- a/src/VBox/Main/src-server/MediumImpl.cpp +++ b/src/VBox/Main/src-server/MediumImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2012 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -16,6 +16,7 @@ */ #include "MediumImpl.h" +#include "TokenImpl.h" #include "ProgressImpl.h" #include "SystemPropertiesImpl.h" #include "VirtualBoxImpl.h" @@ -68,9 +69,9 @@ struct BackRef BackRef(const Guid &aMachineId, const Guid &aSnapshotId = Guid::Empty) : machineId(aMachineId), - fInCurState(aSnapshotId.isEmpty()) + fInCurState(aSnapshotId.isZero()) { - if (!aSnapshotId.isEmpty()) + if (aSnapshotId.isValid() && !aSnapshotId.isZero()) llSnapshotIds.push_back(aSnapshotId); } @@ -514,7 +515,7 @@ public: Medium *aTarget, bool fMergeForward, Medium *aParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, Progress *aProgress, MediumLockList *aMediumLockList, bool fKeepMediumLockList = false) @@ -522,55 +523,29 @@ public: mTarget(aTarget), mfMergeForward(fMergeForward), mParentForTarget(aParentForTarget), - mChildrenToReparent(aChildrenToReparent), + mpChildrenToReparent(aChildrenToReparent), mpMediumLockList(aMediumLockList), mTargetCaller(aTarget), mParentForTargetCaller(aParentForTarget), - mfChildrenCaller(false), mfKeepMediumLockList(fKeepMediumLockList) { AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL); - for (MediaList::const_iterator it = mChildrenToReparent.begin(); - it != mChildrenToReparent.end(); - ++it) - { - HRESULT rc2 = (*it)->addCaller(); - if (FAILED(rc2)) - { - mRC = E_FAIL; - for (MediaList::const_iterator it2 = mChildrenToReparent.begin(); - it2 != it; - --it2) - { - (*it2)->releaseCaller(); - } - return; - } - } - mfChildrenCaller = true; } ~MergeTask() { if (!mfKeepMediumLockList && mpMediumLockList) delete mpMediumLockList; - if (mfChildrenCaller) - { - for (MediaList::const_iterator it = mChildrenToReparent.begin(); - it != mChildrenToReparent.end(); - ++it) - { - (*it)->releaseCaller(); - } - } + if (mpChildrenToReparent) + delete mpChildrenToReparent; } const ComObjPtr mTarget; bool mfMergeForward; - /* When mChildrenToReparent is empty then mParentForTarget is non-null. - * In other words: they are used in different cases. */ + /* When mpChildrenToReparent is null then mParentForTarget is non-null and + * vice versa. In other words: they are used in different cases. */ const ComObjPtr mParentForTarget; - MediaList mChildrenToReparent; + MediumLockList *mpChildrenToReparent; MediumLockList *mpMediumLockList; private: @@ -578,7 +553,6 @@ private: AutoCaller mTargetCaller; AutoCaller mParentForTargetCaller; - bool mfChildrenCaller; bool mfKeepMediumLockList; }; @@ -941,7 +915,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, unconst(m->pVirtualBox) = aVirtualBox; - if (!uuidMachineRegistry.isEmpty()) + if (uuidMachineRegistry.isValid() && !uuidMachineRegistry.isZero()) m->llRegistryIDs.push_back(uuidMachineRegistry); /* no storage yet */ @@ -958,7 +932,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, rc = setLocation(aLocation); if (FAILED(rc)) return rc; - if (!(m->formatObj->getCapabilities() & ( MediumFormatCapabilities_CreateFixed + if (!(m->formatObj->i_getCapabilities() & ( MediumFormatCapabilities_CreateFixed | MediumFormatCapabilities_CreateDynamic)) ) { @@ -973,8 +947,29 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); ComObjPtr pMedium; + + /* + * Check whether the UUID is taken already and create a new one + * if required. + * Try this only a limited amount of times in case the PRNG is broken + * in some way to prevent an endless loop. + */ + for (unsigned i = 0; i < 5; i++) + { + bool fInUse; + + fInUse = m->pVirtualBox->isMediaUuidInUse(m->id, DeviceType_HardDisk); + if (fInUse) + { + // create new UUID + unconst(m->id).create(); + } + else + break; + } + rc = m->pVirtualBox->registerMedium(this, &pMedium, DeviceType_HardDisk); - Assert(this == pMedium); + Assert(this == pMedium || FAILED(rc)); } /* Confirm a successful initialization when it's the case */ @@ -1086,7 +1081,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, } else { - AssertStmt(!m->id.isEmpty(), + AssertStmt(!m->id.isZero(), alock.release(); autoCaller.release(); uninit(); return E_FAIL); /* storage format must be detected by Medium::queryInfo if the @@ -1141,7 +1136,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, unconst(m->pVirtualBox) = aVirtualBox; - if (!uuidMachineRegistry.isEmpty()) + if (uuidMachineRegistry.isValid() && !uuidMachineRegistry.isZero()) m->llRegistryIDs.push_back(uuidMachineRegistry); /* register with VirtualBox/parent early, since uninit() will @@ -1218,7 +1213,7 @@ HRESULT Medium::init(VirtualBox *aVirtualBox, } Utf8Str strFull; - if (m->formatObj->getCapabilities() & MediumFormatCapabilities_File) + if (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File) { // compose full path of the medium, if it's not fully qualified... // slightly convoluted logic here. If the caller has given us a @@ -1510,20 +1505,29 @@ STDMETHODIMP Medium::COMGETTER(State)(MediumState_T *aState) return S_OK; } -STDMETHODIMP Medium::COMGETTER(Variant)(ULONG *aVariant) +STDMETHODIMP Medium::COMGETTER(Variant)(ComSafeArrayOut(MediumVariant_T, aVariant)) { - CheckComArgOutPointerValid(aVariant); + CheckComArgOutSafeArrayPointerValid(aVariant); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - *aVariant = m->variant; + + SafeArray variants(sizeof(MediumVariant_T)*8); + + for (ULONG i = 0; i < variants.size(); ++i) + { + ULONG temp = m->variant; + temp &= 1<location on success, then save - /// the global registry (and local registries of portable VMs referring to - /// this medium), this will also require to add the mRegistered flag to data - - ReturnComNotImplemented(); -} - STDMETHODIMP Medium::COMGETTER(Name)(BSTR *aName) { CheckComArgOutPointerValid(aName); @@ -1863,30 +1846,14 @@ STDMETHODIMP Medium::COMGETTER(LogicalSize)(LONG64 *aLogicalSize) { CheckComArgOutPointerValid(aLogicalSize); - { - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* we access mParent */ - AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (m->pParent.isNull()) - { - *aLogicalSize = m->logicalSize; - - return S_OK; - } - } + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* We assume that some backend may decide to return a meaningless value in - * response to VDGetSize() for differencing media and therefore always - * ask the base medium ourselves. */ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - /* base() will do callers/locking */ + *aLogicalSize = m->logicalSize; - return getBase()->COMGETTER(LogicalSize)(aLogicalSize); + return S_OK; } STDMETHODIMP Medium::COMGETTER(AutoReset)(BOOL *aAutoReset) @@ -1999,8 +1966,8 @@ STDMETHODIMP Medium::SetIds(BOOL aSetImageId, else { imageId = Guid(aImageId); - if (imageId.isEmpty()) - return setError(E_INVALIDARG, tr("Argument %s is empty"), "aImageId"); + if (!imageId.isValid()) + return setError(E_INVALIDARG, tr("Argument %s is invalid"), "aImageId"); } } if (aSetParentId) @@ -2060,7 +2027,7 @@ STDMETHODIMP Medium::RefreshState(MediumState_T *aState) STDMETHODIMP Medium::GetSnapshotIds(IN_BSTR aMachineId, ComSafeArrayOut(BSTR, aSnapshotIds)) { - CheckComArgExpr(aMachineId, Guid(aMachineId).isEmpty() == false); + CheckComArgExpr(aMachineId, Guid(aMachineId).isValid()); CheckComArgOutSafeArrayPointerValid(aSnapshotIds); AutoCaller autoCaller(this); @@ -2108,12 +2075,10 @@ STDMETHODIMP Medium::GetSnapshotIds(IN_BSTR aMachineId, return S_OK; } -/** - * @note @a aState may be NULL if the state value is not needed (only for - * in-process calls). - */ -STDMETHODIMP Medium::LockRead(MediumState_T *aState) +STDMETHODIMP Medium::LockRead(IToken **aToken) { + CheckComArgNotNull(aToken); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2137,10 +2102,6 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState) } } - /* return the current state before */ - if (aState) - *aState = m->state; - HRESULT rc = S_OK; switch (m->state) @@ -2160,6 +2121,19 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState) LogFlowThisFunc(("Okay - prev state=%d readers=%d\n", m->state, m->readers)); m->state = MediumState_LockedRead; + ComObjPtr pToken; + rc = pToken.createObject(); + if (SUCCEEDED(rc)) + rc = pToken->init(this, false /* fWrite */); + if (FAILED(rc)) + { + --m->readers; + if (m->readers == 0) + m->state = m->preLockState; + return rc; + } + + pToken.queryInterfaceTo(aToken); break; } default: @@ -2177,7 +2151,7 @@ STDMETHODIMP Medium::LockRead(MediumState_T *aState) * @note @a aState may be NULL if the state value is not needed (only for * in-process calls). */ -STDMETHODIMP Medium::UnlockRead(MediumState_T *aState) +HRESULT Medium::unlockRead(MediumState_T *aState) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2224,12 +2198,10 @@ STDMETHODIMP Medium::UnlockRead(MediumState_T *aState) return rc; } -/** - * @note @a aState may be NULL if the state value is not needed (only for - * in-process calls). - */ -STDMETHODIMP Medium::LockWrite(MediumState_T *aState) +STDMETHODIMP Medium::LockWrite(IToken **aToken) { + CheckComArgNotNull(aToken); + AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2253,10 +2225,6 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState) } } - /* return the current state before */ - if (aState) - *aState = m->state; - HRESULT rc = S_OK; switch (m->state) @@ -2268,6 +2236,18 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState) LogFlowThisFunc(("Okay - prev state=%d locationFull=%s\n", m->state, getLocationFull().c_str())); m->state = MediumState_LockedWrite; + + ComObjPtr pToken; + rc = pToken.createObject(); + if (SUCCEEDED(rc)) + rc = pToken->init(this, true /* fWrite */); + if (FAILED(rc)) + { + m->state = m->preLockState; + return rc; + } + + pToken.queryInterfaceTo(aToken); break; } default: @@ -2285,7 +2265,7 @@ STDMETHODIMP Medium::LockWrite(MediumState_T *aState) * @note @a aState may be NULL if the state value is not needed (only for * in-process calls). */ -STDMETHODIMP Medium::UnlockWrite(MediumState_T *aState) +HRESULT Medium::unlockWrite(MediumState_T *aState) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2351,8 +2331,14 @@ STDMETHODIMP Medium::GetProperty(IN_BSTR aName, BSTR *aValue) settings::StringsMap::const_iterator it = m->mapProperties.find(Utf8Str(aName)); if (it == m->mapProperties.end()) - return setError(VBOX_E_OBJECT_NOT_FOUND, - tr("Property '%ls' does not exist"), aName); + { + if (!Utf8Str(aName).startsWith("Special/")) + return setError(VBOX_E_OBJECT_NOT_FOUND, + tr("Property '%ls' does not exist"), aName); + else + /* be more silent here */ + return VBOX_E_OBJECT_NOT_FOUND; + } it->second.cloneTo(aValue); @@ -2377,13 +2363,32 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue) return setStateError(); } - settings::StringsMap::iterator it = m->mapProperties.find(Utf8Str(aName)); - if (it == m->mapProperties.end()) - return setError(VBOX_E_OBJECT_NOT_FOUND, - tr("Property '%ls' does not exist"), - aName); - - it->second = aValue; + Utf8Str strName(aName); + Utf8Str strValue(aValue); + settings::StringsMap::iterator it = m->mapProperties.find(strName); + if (!strName.startsWith("Special/")) + { + if (it == m->mapProperties.end()) + return setError(VBOX_E_OBJECT_NOT_FOUND, + tr("Property '%s' does not exist"), + strName.c_str()); + it->second = strValue; + } + else + { + if (it == m->mapProperties.end()) + { + if (!strValue.isEmpty()) + m->mapProperties[strName] = strValue; + } + else + { + if (!strValue.isEmpty()) + it->second = aValue; + else + m->mapProperties.erase(it); + } + } // save the settings mlock.release(); @@ -2446,9 +2451,11 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames), i < names.size(); ++i) { - if (m->mapProperties.find(Utf8Str(names[i])) == m->mapProperties.end()) + Utf8Str strName(names[i]); + if ( !strName.startsWith("Special/") + && m->mapProperties.find(strName) == m->mapProperties.end()) return setError(VBOX_E_OBJECT_NOT_FOUND, - tr("Property '%ls' does not exist"), names[i]); + tr("Property '%s' does not exist"), strName.c_str()); } /* second pass: assign */ @@ -2456,10 +2463,29 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames), i < names.size(); ++i) { - settings::StringsMap::iterator it = m->mapProperties.find(Utf8Str(names[i])); - AssertReturn(it != m->mapProperties.end(), E_FAIL); - - it->second = Utf8Str(values[i]); + Utf8Str strName(names[i]); + Utf8Str strValue(values[i]); + settings::StringsMap::iterator it = m->mapProperties.find(strName); + if (!strName.startsWith("Special/")) + { + AssertReturn(it != m->mapProperties.end(), E_FAIL); + it->second = strValue; + } + else + { + if (it == m->mapProperties.end()) + { + if (!strValue.isEmpty()) + m->mapProperties[strName] = strValue; + } + else + { + if (!strValue.isEmpty()) + it->second = strValue; + else + m->mapProperties.erase(it); + } + } } // save the settings @@ -2471,9 +2497,10 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames), } STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize, - ULONG aVariant, + ComSafeArrayIn(MediumVariant_T, aVariant), IProgress **aProgress) { + CheckComArgSafeArrayNotNull(aVariant); CheckComArgOutPointerValid(aProgress); if (aLogicalSize < 0) return setError(E_INVALIDARG, tr("The medium size argument (%lld) is negative"), aLogicalSize); @@ -2482,21 +2509,32 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize, if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; - ComObjPtr pProgress; + ComObjPtr pProgress; Medium::Task *pTask = NULL; try { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - aVariant = (MediumVariant_T)((unsigned)aVariant & (unsigned)~MediumVariant_Diff); - if ( !(aVariant & MediumVariant_Fixed) - && !(m->formatObj->getCapabilities() & MediumFormatCapabilities_CreateDynamic)) + ULONG mediumVariantFlags = 0; + + if (aVariant) + { + com::SafeArray variants(ComSafeArrayInArg(aVariant)); + for (size_t i = 0; i < variants.size(); i++) + mediumVariantFlags |= variants[i]; + } + + mediumVariantFlags &= ((unsigned)~MediumVariant_Diff); + + if ( !(mediumVariantFlags & MediumVariant_Fixed) + && !(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_CreateDynamic)) throw setError(VBOX_E_NOT_SUPPORTED, tr("Medium format '%s' does not support dynamic storage creation"), m->strFormat.c_str()); - if ( (aVariant & MediumVariant_Fixed) - && !(m->formatObj->getCapabilities() & MediumFormatCapabilities_CreateDynamic)) + + if ( (mediumVariantFlags & MediumVariant_Fixed) + && !(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_CreateDynamic)) throw setError(VBOX_E_NOT_SUPPORTED, tr("Medium format '%s' does not support fixed storage creation"), m->strFormat.c_str()); @@ -2507,7 +2545,7 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize, pProgress.createObject(); rc = pProgress->init(m->pVirtualBox, static_cast(this), - (aVariant & MediumVariant_Fixed) + (mediumVariantFlags & MediumVariant_Fixed) ? BstrFmt(tr("Creating fixed medium storage unit '%s'"), m->strLocationFull.c_str()).raw() : BstrFmt(tr("Creating dynamic medium storage unit '%s'"), m->strLocationFull.c_str()).raw(), TRUE /* aCancelable */); @@ -2516,7 +2554,8 @@ STDMETHODIMP Medium::CreateBaseStorage(LONG64 aLogicalSize, /* setup task object to carry out the operation asynchronously */ pTask = new Medium::CreateBaseTask(this, pProgress, aLogicalSize, - (MediumVariant_T)aVariant); + (MediumVariant_T)mediumVariantFlags); + //(MediumVariant_T)aVariant); rc = pTask->rc(); AssertComRC(rc); if (FAILED(rc)) @@ -2560,11 +2599,12 @@ STDMETHODIMP Medium::DeleteStorage(IProgress **aProgress) } STDMETHODIMP Medium::CreateDiffStorage(IMedium *aTarget, - ULONG aVariant, - IProgress **aProgress) + ComSafeArrayIn(MediumVariant_T, aVariant), + IProgress **aProgress) { CheckComArgNotNull(aTarget); CheckComArgOutPointerValid(aProgress); + CheckComArgSafeArrayNotNull(aVariant); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2625,9 +2665,18 @@ STDMETHODIMP Medium::CreateDiffStorage(IMedium *aTarget, alock.release(); - ComObjPtr pProgress; + ComObjPtr pProgress; + + ULONG mediumVariantFlags = 0; + + if (aVariant) + { + com::SafeArray variants(ComSafeArrayInArg(aVariant)); + for (size_t i = 0; i < variants.size(); i++) + mediumVariantFlags |= variants[i]; + } - rc = createDiffStorage(diff, (MediumVariant_T)aVariant, pMediumLockList, + rc = createDiffStorage(diff, (MediumVariant_T)mediumVariantFlags, pMediumLockList, &pProgress, false /* aWait */); if (FAILED(rc)) delete pMediumLockList; @@ -2650,21 +2699,21 @@ STDMETHODIMP Medium::MergeTo(IMedium *aTarget, IProgress **aProgress) bool fMergeForward = false; ComObjPtr pParentForTarget; - MediaList childrenToReparent; + MediumLockList *pChildrenToReparent = NULL; MediumLockList *pMediumLockList = NULL; HRESULT rc = S_OK; rc = prepareMergeTo(pTarget, NULL, NULL, true, fMergeForward, - pParentForTarget, childrenToReparent, pMediumLockList); + pParentForTarget, pChildrenToReparent, pMediumLockList); if (FAILED(rc)) return rc; - ComObjPtr pProgress; + ComObjPtr pProgress; - rc = mergeTo(pTarget, fMergeForward, pParentForTarget, childrenToReparent, + rc = mergeTo(pTarget, fMergeForward, pParentForTarget, pChildrenToReparent, pMediumLockList, &pProgress, false /* aWait */); if (FAILED(rc)) - cancelMergeTo(childrenToReparent, pMediumLockList); + cancelMergeTo(pChildrenToReparent, pMediumLockList); else pProgress.queryInterfaceTo(aProgress); @@ -2672,23 +2721,29 @@ STDMETHODIMP Medium::MergeTo(IMedium *aTarget, IProgress **aProgress) } STDMETHODIMP Medium::CloneToBase(IMedium *aTarget, - ULONG aVariant, - IProgress **aProgress) + ComSafeArrayIn(MediumVariant_T, aVariant), + IProgress **aProgress) { int rc = S_OK; CheckComArgNotNull(aTarget); CheckComArgOutPointerValid(aProgress); - rc = CloneTo(aTarget, aVariant, NULL, aProgress); + CheckComArgSafeArrayNotNull(aVariant); + + com::SafeArray variants(ComSafeArrayInArg(aVariant)); + + rc = CloneTo(aTarget, ComSafeArrayAsInParam(variants), NULL, aProgress); return rc; } STDMETHODIMP Medium::CloneTo(IMedium *aTarget, - ULONG aVariant, + ComSafeArrayIn(MediumVariant_T, aVariant), IMedium *aParent, IProgress **aProgress) { CheckComArgNotNull(aTarget); CheckComArgOutPointerValid(aProgress); + CheckComArgSafeArrayNotNull(aVariant); + ComAssertRet(aTarget != this, E_INVALIDARG); AutoCaller autoCaller(this); @@ -2786,9 +2841,18 @@ STDMETHODIMP Medium::CloneTo(IMedium *aTarget, throw rc; } + ULONG mediumVariantFlags = 0; + + if (aVariant) + { + com::SafeArray variants(ComSafeArrayInArg(aVariant)); + for (size_t i = 0; i < variants.size(); i++) + mediumVariantFlags |= variants[i]; + } + /* setup task object to carry out the operation asynchronously */ pTask = new Medium::CloneTask(this, pProgress, pTarget, - (MediumVariant_T)aVariant, + (MediumVariant_T)mediumVariantFlags, pParent, UINT32_MAX, UINT32_MAX, pSourceMediumLockList, pTargetMediumLockList); rc = pTask->rc(); @@ -2814,6 +2878,29 @@ STDMETHODIMP Medium::CloneTo(IMedium *aTarget, return rc; } +STDMETHODIMP Medium::SetLocation(IN_BSTR aLocation, IProgress **aProgress) +{ + CheckComArgStrNotEmptyOrNull(aLocation); + CheckComArgOutPointerValid(aProgress); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + /// @todo NEWMEDIA for file names, add the default extension if no extension + /// is present (using the information from the VD backend which also implies + /// that one more parameter should be passed to setLocation() requesting + /// that functionality since it is only allowed when called from this method + + /// @todo NEWMEDIA rename the file and set m->location on success, then save + /// the global registry (and local registries of portable VMs referring to + /// this medium), this will also require to add the mRegistered flag to data + + *aProgress = NULL; + ReturnComNotImplemented(); +} + STDMETHODIMP Medium::Compact(IProgress **aProgress) { CheckComArgOutPointerValid(aProgress); @@ -2822,7 +2909,7 @@ STDMETHODIMP Medium::Compact(IProgress **aProgress) if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; - ComObjPtr pProgress; + ComObjPtr pProgress; Medium::Task *pTask = NULL; try @@ -2895,7 +2982,7 @@ STDMETHODIMP Medium::Resize(LONG64 aLogicalSize, IProgress **aProgress) if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; - ComObjPtr pProgress; + ComObjPtr pProgress; Medium::Task *pTask = NULL; try @@ -2968,7 +3055,7 @@ STDMETHODIMP Medium::Reset(IProgress **aProgress) if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; - ComObjPtr pProgress; + ComObjPtr pProgress; Medium::Task *pTask = NULL; try @@ -3038,17 +3125,8 @@ STDMETHODIMP Medium::Reset(IProgress **aProgress) if (SUCCEEDED(rc)) pProgress.queryInterfaceTo(aProgress); } - else - { - /* Note: on success, the task will unlock this */ - { - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - HRESULT rc2 = UnlockWrite(NULL); - AssertComRC(rc2); - } - if (pTask != NULL) - delete pTask; - } + else if (pTask != NULL) + delete pTask; LogFlowThisFunc(("LEAVE, rc=%Rhrc\n", rc)); @@ -3150,7 +3228,7 @@ const ComObjPtr& Medium::getMediumFormat() const bool Medium::isMediumFormatFile() const { if ( m->formatObj - && (m->formatObj->getCapabilities() & MediumFormatCapabilities_File) + && (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File) ) return true; return false; @@ -3382,6 +3460,9 @@ void Medium::markRegistriesModified() llRegistryIDs = m->llRegistryIDs; } + /* Save the error information now, the implicit restore when this goes + * out of scope will throw away spurious additional errors created below. */ + ErrorInfoKeeper eik; for (GuidList::const_iterator it = llRegistryIDs.begin(); it != llRegistryIDs.end(); ++it) @@ -3400,7 +3481,7 @@ void Medium::markRegistriesModified() HRESULT Medium::addBackReference(const Guid &aMachineId, const Guid &aSnapshotId /*= Guid::Empty*/) { - AssertReturn(!aMachineId.isEmpty(), E_FAIL); + AssertReturn(aMachineId.isValid(), E_FAIL); LogFlowThisFunc(("ENTER, aMachineId: {%RTuuid}, aSnapshotId: {%RTuuid}\n", aMachineId.raw(), aSnapshotId.raw())); @@ -3442,7 +3523,8 @@ HRESULT Medium::addBackReference(const Guid &aMachineId, // if the caller has not supplied a snapshot ID, then we're attaching // to a machine a medium which represents the machine's current state, // so set the flag - if (aSnapshotId.isEmpty()) + + if (aSnapshotId.isZero()) { /* sanity: no duplicate attachments */ if (it->fInCurState) @@ -3479,7 +3561,8 @@ HRESULT Medium::addBackReference(const Guid &aMachineId, } it->llSnapshotIds.push_back(aSnapshotId); - it->fInCurState = false; + // Do not touch fInCurState, as the image may be attached to the current + // state *and* a snapshot, otherwise we lose the current state association! LogFlowThisFuncLeave(); @@ -3497,7 +3580,7 @@ HRESULT Medium::addBackReference(const Guid &aMachineId, HRESULT Medium::removeBackReference(const Guid &aMachineId, const Guid &aSnapshotId /*= Guid::Empty*/) { - AssertReturn(!aMachineId.isEmpty(), E_FAIL); + AssertReturn(aMachineId.isValid(), E_FAIL); AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); @@ -3509,7 +3592,7 @@ HRESULT Medium::removeBackReference(const Guid &aMachineId, BackRef::EqualsTo(aMachineId)); AssertReturn(it != m->backRefs.end(), E_FAIL); - if (aSnapshotId.isEmpty()) + if (aSnapshotId.isZero()) { /* remove the current state attachment */ it->fInCurState = false; @@ -4091,7 +4174,7 @@ Utf8Str Medium::getPreferredDiffFormat() AssertComRCReturn(autoCaller.rc(), Utf8Str::Empty); /* check that our own format supports diffs */ - if (!(m->formatObj->getCapabilities() & MediumFormatCapabilities_Differencing)) + if (!(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_Differencing)) { /* use the default format if not */ Utf8Str tmp; @@ -4224,7 +4307,7 @@ HRESULT Medium::deleteStorage(ComObjPtr *aProgress, COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aWait=%RTbool locationFull=%s\n", aWait, getLocationFull().c_str() )); - if ( !(m->formatObj->getCapabilities() & ( MediumFormatCapabilities_CreateDynamic + if ( !(m->formatObj->i_getCapabilities() & ( MediumFormatCapabilities_CreateDynamic | MediumFormatCapabilities_CreateFixed))) throw setError(VBOX_E_NOT_SUPPORTED, tr("Medium format '%s' does not support storage deletion"), @@ -4450,6 +4533,112 @@ HRESULT Medium::unmarkLockedForDeletion() return setStateError(); } +/** + * Queries the preferred merge direction from this to the other medium, i.e. + * the one which requires the least amount of I/O and therefore time and + * disk consumption. + * + * @returns Status code. + * @retval E_FAIL in case determining the merge direction fails for some reason, + * for example if getting the size of the media fails. There is no + * error set though and the caller is free to continue to find out + * what was going wrong later. Leaves fMergeForward unset. + * @retval VBOX_E_INVALID_OBJECT_STATE if both media are not related to each other + * An error is set. + * @param pOther The other medium to merge with. + * @param fMergeForward Resulting preferred merge direction (out). + */ +HRESULT Medium::queryPreferredMergeDirection(const ComObjPtr &pOther, + bool &fMergeForward) +{ + AssertReturn(pOther != NULL, E_FAIL); + AssertReturn(pOther != this, E_FAIL); + + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + AutoCaller otherCaller(pOther); + AssertComRCReturnRC(otherCaller.rc()); + + HRESULT rc = S_OK; + bool fThisParent = false; /**<< Flag whether this medium is the parent of pOther. */ + + try + { + // locking: we need the tree lock first because we access parent pointers + AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); + + /* more sanity checking and figuring out the current merge direction */ + ComObjPtr pMedium = getParent(); + while (!pMedium.isNull() && pMedium != pOther) + pMedium = pMedium->getParent(); + if (pMedium == pOther) + fThisParent = false; + else + { + pMedium = pOther->getParent(); + while (!pMedium.isNull() && pMedium != this) + pMedium = pMedium->getParent(); + if (pMedium == this) + fThisParent = true; + else + { + Utf8Str tgtLoc; + { + AutoReadLock alock(pOther COMMA_LOCKVAL_SRC_POS); + tgtLoc = pOther->getLocationFull(); + } + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + throw setError(VBOX_E_INVALID_OBJECT_STATE, + tr("Media '%s' and '%s' are unrelated"), + m->strLocationFull.c_str(), tgtLoc.c_str()); + } + } + + /* + * Figure out the preferred merge direction. The current way is to + * get the current sizes of file based images and select the merge + * direction depending on the size. + * + * Can't use the VD API to get current size here as the media might + * be write locked by a running VM. Resort to RTFileQuerySize(). + */ + int vrc = VINF_SUCCESS; + uint64_t cbMediumThis = 0; + uint64_t cbMediumOther = 0; + + if (isMediumFormatFile() && pOther->isMediumFormatFile()) + { + vrc = RTFileQuerySize(this->getLocationFull().c_str(), &cbMediumThis); + if (RT_SUCCESS(vrc)) + { + vrc = RTFileQuerySize(pOther->getLocationFull().c_str(), + &cbMediumOther); + } + + if (RT_FAILURE(vrc)) + rc = E_FAIL; + else + { + /* + * Check which merge direction might be more optimal. + * This method is not bullet proof of course as there might + * be overlapping blocks in the images so the file size is + * not the best indicator but it is good enough for our purpose + * and everything else is too complicated, especially when the + * media are used by a running VM. + */ + bool fMergeIntoThis = cbMediumThis > cbMediumOther; + fMergeForward = fMergeIntoThis ^ fThisParent; + } + } + } + catch (HRESULT aRC) { rc = aRC; } + + return rc; +} + /** * Prepares this (source) medium, target medium and all intermediate media * for the merge operation. @@ -4470,8 +4659,9 @@ HRESULT Medium::unmarkLockedForDeletion() * later you must call #cancelMergeTo(). * @param fMergeForward Resulting merge direction (out). * @param pParentForTarget New parent for target medium after merge (out). - * @param aChildrenToReparent List of children of the source which will have - * to be reparented to the target after merge (out). + * @param aChildrenToReparent Medium lock list containing all children of the + * source which will have to be reparented to the target + * after merge (out). * @param aMediumLockList Medium locking information (out). * * @note Locks medium tree for reading. Locks this object, aTarget and all @@ -4483,7 +4673,7 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, bool fLockMedia, bool &fMergeForward, ComObjPtr &pParentForTarget, - MediaList &aChildrenToReparent, + MediumLockList * &aChildrenToReparent, MediumLockList * &aMediumLockList) { AssertReturn(pTarget != NULL, E_FAIL); @@ -4498,7 +4688,8 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, HRESULT rc = S_OK; fMergeForward = false; pParentForTarget.setNull(); - aChildrenToReparent.clear(); + Assert(aChildrenToReparent == NULL); + aChildrenToReparent = NULL; Assert(aMediumLockList == NULL); aMediumLockList = NULL; @@ -4587,9 +4778,9 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, if ( m->backRefs.size() != 0 && ( !aMachineId || m->backRefs.size() != 1 - || aMachineId->isEmpty() + || aMachineId->isZero() || *getFirstMachineBackrefId() != *aMachineId - || ( (!aSnapshotId || !aSnapshotId->isEmpty()) + || ( (!aSnapshotId || !aSnapshotId->isZero()) && *getFirstMachineBackrefSnapshotId() != *aSnapshotId))) throw setError(VBOX_E_OBJECT_IN_USE, tr("Medium '%s' is attached to %d virtual machines"), @@ -4681,19 +4872,21 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, else { /* we will need to reparent children of the source */ + aChildrenToReparent = new MediumLockList(); for (MediaList::const_iterator it = getChildren().begin(); it != getChildren().end(); ++it) { pMedium = *it; - if (fLockMedia) - { - rc = pMedium->LockWrite(NULL); - if (FAILED(rc)) - throw rc; - } - - aChildrenToReparent.push_back(pMedium); + aChildrenToReparent->Append(pMedium, true /* fLockWrite */); + } + if (fLockMedia && aChildrenToReparent) + { + treeLock.release(); + rc = aChildrenToReparent->Lock(); + treeLock.acquire(); + if (FAILED(rc)) + throw rc; } } for (pLast = pLastIntermediate; @@ -4752,8 +4945,16 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, if (FAILED(rc)) { - delete aMediumLockList; - aMediumLockList = NULL; + if (aMediumLockList) + { + delete aMediumLockList; + aMediumLockList = NULL; + } + if (aChildrenToReparent) + { + delete aChildrenToReparent; + aChildrenToReparent = NULL; + } } return rc; @@ -4838,9 +5039,9 @@ HRESULT Medium::prepareMergeTo(const ComObjPtr &pTarget, HRESULT Medium::mergeTo(const ComObjPtr &pTarget, bool fMergeForward, const ComObjPtr &pParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList, - ComObjPtr *aProgress, + ComObjPtr *aProgress, bool aWait) { AssertReturn(pTarget != NULL, E_FAIL); @@ -4855,7 +5056,7 @@ HRESULT Medium::mergeTo(const ComObjPtr &pTarget, AssertComRCReturnRC(targetCaller.rc()); HRESULT rc = S_OK; - ComObjPtr pProgress; + ComObjPtr pProgress; Medium::Task *pTask = NULL; try @@ -4927,7 +5128,7 @@ HRESULT Medium::mergeTo(const ComObjPtr &pTarget, * * @note Locks the media from the chain for writing. */ -void Medium::cancelMergeTo(const MediaList &aChildrenToReparent, +void Medium::cancelMergeTo(MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList) { AutoCaller autoCaller(this); @@ -4959,23 +5160,17 @@ void Medium::cancelMergeTo(const MediaList &aChildrenToReparent, /* the destructor will do the work */ delete aMediumLockList; - /* unlock the children which had to be reparented */ - for (MediaList::const_iterator it = aChildrenToReparent.begin(); - it != aChildrenToReparent.end(); - ++it) - { - const ComObjPtr &pMedium = *it; - - AutoWriteLock alock(pMedium COMMA_LOCKVAL_SRC_POS); - pMedium->UnlockWrite(NULL); - } + /* unlock the children which had to be reparented, the destructor will do + * the work */ + if (aChildrenToReparent) + delete aChildrenToReparent; } /** * Fix the parent UUID of all children to point to this medium as their * parent. */ -HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent) +HRESULT Medium::fixParentUuidOfChildren(MediumLockList *pChildrenToReparent) { Assert(!isWriteLockOnCurrentThread()); Assert(!m->pVirtualBox->getMediaTreeLockHandle().isWriteLockOnCurrentThread()); @@ -5016,16 +5211,19 @@ HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent) throw vrc; } - for (MediaList::const_iterator it = childrenToReparent.begin(); - it != childrenToReparent.end(); + MediumLockList::Base::iterator childrenBegin = pChildrenToReparent->GetBegin(); + MediumLockList::Base::iterator childrenEnd = pChildrenToReparent->GetEnd(); + for (MediumLockList::Base::iterator it = childrenBegin; + it != childrenEnd; ++it) { + Medium *pMedium = it->GetMedium(); /* VD_OPEN_FLAGS_INFO since UUID is wrong yet */ vrc = VDOpen(hdd, - (*it)->m->strFormat.c_str(), - (*it)->m->strLocationFull.c_str(), + pMedium->m->strFormat.c_str(), + pMedium->m->strLocationFull.c_str(), VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef, - (*it)->m->vdImageIfaces); + pMedium->m->vdImageIfaces); if (RT_FAILURE(vrc)) throw vrc; @@ -5036,8 +5234,6 @@ HRESULT Medium::fixParentUuidOfChildren(const MediaList &childrenToReparent) vrc = VDClose(hdd, false /* fDelete */); if (RT_FAILURE(vrc)) throw vrc; - - (*it)->UnlockWrite(NULL); } } catch (HRESULT aRC) { rc = aRC; } @@ -5433,7 +5629,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) /* are we dealing with a new medium constructed using the existing * location? */ - bool isImport = m->id.isEmpty(); + bool isImport = m->id.isZero(); unsigned uOpenFlags = VD_OPEN_FLAGS_INFO; /* Note that we don't use VD_OPEN_FLAGS_READONLY when opening new @@ -5453,10 +5649,11 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) /* Lock the medium, which makes the behavior much more consistent */ alock.release(); + ComPtr pToken; if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE)) - rc = LockRead(NULL); + rc = LockRead(pToken.asOutParam()); else - rc = LockWrite(NULL); + rc = LockWrite(pToken.asOutParam()); if (FAILED(rc)) return rc; alock.acquire(); @@ -5524,7 +5721,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) throw S_OK; } - if (formatObj->getCapabilities() & MediumFormatCapabilities_Uuid) + if (formatObj->i_getCapabilities() & MediumFormatCapabilities_Uuid) { /* Modify the UUIDs if necessary. The associated fields are * not modified by other code, so no need to copy. */ @@ -5533,7 +5730,12 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) alock.acquire(); vrc = VDSetUuid(hdd, 0, m->uuidImage.raw()); alock.release(); - ComAssertRCThrow(vrc, E_FAIL); + if (RT_FAILURE(vrc)) + { + lastAccessError = Utf8StrFmt(tr("Could not update the UUID of medium '%s'%s"), + location.c_str(), vdError(vrc).c_str()); + throw S_OK; + } mediumId = m->uuidImage; } if (fSetParentId) @@ -5541,7 +5743,12 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) alock.acquire(); vrc = VDSetParentUuid(hdd, 0, m->uuidParentImage.raw()); alock.release(); - ComAssertRCThrow(vrc, E_FAIL); + if (RT_FAILURE(vrc)) + { + lastAccessError = Utf8StrFmt(tr("Could not update the parent UUID of medium '%s'%s"), + location.c_str(), vdError(vrc).c_str()); + throw S_OK; + } } /* zap the information, these are no long-term members */ alock.acquire(); @@ -5558,13 +5765,13 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) { mediumId = uuid; - if (mediumId.isEmpty() && (m->hddOpenMode == OpenReadOnly)) + if (mediumId.isZero() && (m->hddOpenMode == OpenReadOnly)) // only when importing a VDMK that has no UUID, create one in memory mediumId.create(); } else { - Assert(!mediumId.isEmpty()); + Assert(!mediumId.isZero()); if (mediumId != uuid) { @@ -5626,7 +5833,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) * Since such images don't support random writes they will not * be created for diff images. Only an overly smart user might * manually create this case. Too bad for him. */ - if ( isImport + if ( (isImport || fSetParentId) && !(uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)) { /* the parent must be known to us. Note that we freely @@ -5636,24 +5843,43 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) * threads yet (and init() will fail if this method reports * MediumState_Inaccessible) */ - Guid id = parentId; ComObjPtr pParent; - rc = m->pVirtualBox->findHardDiskById(id, false /* aSetError */, &pParent); + if (RTUuidIsNull(&parentId)) + rc = VBOX_E_OBJECT_NOT_FOUND; + else + rc = m->pVirtualBox->findHardDiskById(Guid(parentId), false /* aSetError */, &pParent); if (FAILED(rc)) { - lastAccessError = Utf8StrFmt( - tr("Parent medium with UUID {%RTuuid} of the medium '%s' is not found in the media registry ('%s')"), - &parentId, location.c_str(), - m->pVirtualBox->settingsFilePath().c_str()); - throw S_OK; + if (fSetImageId && !fSetParentId) + { + /* If the image UUID gets changed for an existing + * image then the parent UUID can be stale. In such + * cases clear the parent information. The parent + * information may/will be re-set later if the + * API client wants to adjust a complete medium + * hierarchy one by one. */ + rc = S_OK; + alock.acquire(); + RTUuidClear(&parentId); + vrc = VDSetParentUuid(hdd, 0, &parentId); + alock.release(); + ComAssertRCThrow(vrc, E_FAIL); + } + else + { + lastAccessError = Utf8StrFmt(tr("Parent medium with UUID {%RTuuid} of the medium '%s' is not found in the media registry ('%s')"), + &parentId, location.c_str(), + m->pVirtualBox->settingsFilePath().c_str()); + throw S_OK; + } } /* we set mParent & children() */ treeLock.acquire(); - Assert(m->pParent.isNull()); - m->pParent = pParent; - m->pParent->m->llChildren.push_back(this); + if (m->pParent) + deparent(); + setParent(pParent); treeLock.release(); } @@ -5765,13 +5991,9 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) else m->preLockState = MediumState_Inaccessible; - HRESULT rc2; - if (uOpenFlags & (VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SHAREABLE)) - rc2 = UnlockRead(NULL); - else - rc2 = UnlockWrite(NULL); - if (SUCCEEDED(rc) && FAILED(rc2)) - rc = rc2; + pToken->Abandon(); + pToken.setNull(); + if (FAILED(rc)) return rc; /* If this is a base image which incorrectly has a parent UUID set, @@ -5782,7 +6004,7 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) * the diff. Not acceptable. */ if (fRepairImageZeroParentUuid) { - rc = LockWrite(NULL); + rc = LockWrite(pToken.asOutParam()); if (FAILED(rc)) return rc; alock.release(); @@ -5820,9 +6042,8 @@ HRESULT Medium::queryInfo(bool fSetImageId, bool fSetParentId) rc = aRC; } - rc = UnlockWrite(NULL); - if (SUCCEEDED(rc) && FAILED(rc2)) - rc = rc2; + pToken->Abandon(); + pToken.setNull(); if (FAILED(rc)) return rc; } @@ -6013,7 +6234,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, AssertReturn( (!m->strFormat.isEmpty() && !m->formatObj.isNull()) || ( autoCaller.state() == InInit && m->state != MediumState_NotCreated - && m->id.isEmpty() + && m->id.isZero() && m->strFormat.isEmpty() && m->formatObj.isNull()), E_FAIL); @@ -6023,7 +6244,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, bool isImport = m->strFormat.isEmpty(); if ( isImport - || ( (m->formatObj->getCapabilities() & MediumFormatCapabilities_File) + || ( (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File) && !m->hostDrive)) { Guid id; @@ -6033,7 +6254,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, if (m->state == MediumState_NotCreated) { /* must be a file (formatObj must be already known) */ - Assert(m->formatObj->getCapabilities() & MediumFormatCapabilities_File); + Assert(m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File); if (RTPathFilename(aLocation.c_str()) == NULL) { @@ -6041,11 +6262,11 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, * slash), generate a new UUID + file name if the state allows * this */ - ComAssertMsgRet(!m->formatObj->getFileExtensions().empty(), + ComAssertMsgRet(!m->formatObj->i_getFileExtensions().empty(), ("Must be at least one extension if it is MediumFormatCapabilities_File\n"), E_FAIL); - Utf8Str strExt = m->formatObj->getFileExtensions().front(); + Utf8Str strExt = m->formatObj->i_getFileExtensions().front(); ComAssertMsgRet(!strExt.isEmpty(), ("Default extension must not be empty\n"), E_FAIL); @@ -6059,7 +6280,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, // we must always have full paths now (if it refers to a file) if ( ( m->formatObj.isNull() - || m->formatObj->getCapabilities() & MediumFormatCapabilities_File) + || m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File) && !RTPathStartsWithRoot(locationFull.c_str())) return setError(VBOX_E_FILE_ERROR, tr("The given path '%s' is not fully qualified"), @@ -6145,7 +6366,7 @@ HRESULT Medium::setLocation(const Utf8Str &aLocation, m->strLocationFull = locationFull; /* is it still a file? */ - if ( (m->formatObj->getCapabilities() & MediumFormatCapabilities_File) + if ( (m->formatObj->i_getCapabilities() & MediumFormatCapabilities_File) && (m->state == MediumState_NotCreated) ) /* assign a new UUID (this UUID will be used when calling @@ -6193,8 +6414,8 @@ HRESULT Medium::setFormat(const Utf8Str &aFormat) Assert(m->mapProperties.empty()); - for (MediumFormat::PropertyList::const_iterator it = m->formatObj->getProperties().begin(); - it != m->formatObj->getProperties().end(); + for (MediumFormat::PropertyArray::const_iterator it = m->formatObj->i_getProperties().begin(); + it != m->formatObj->i_getProperties().end(); ++it) { m->mapProperties.insert(std::make_pair(it->strName, Utf8Str::Empty)); @@ -6572,7 +6793,8 @@ HRESULT Medium::taskCreateBaseHandler(Medium::CreateBaseTask &task) /* The object may request a specific UUID (through a special form of * the setLocation() argument). Otherwise we have to generate it */ Guid id = m->id; - fGenerateUuid = id.isEmpty(); + + fGenerateUuid = id.isZero(); if (fGenerateUuid) { id.create(); @@ -6582,7 +6804,7 @@ HRESULT Medium::taskCreateBaseHandler(Medium::CreateBaseTask &task) Utf8Str format(m->strFormat); Utf8Str location(m->strLocationFull); - uint64_t capabilities = m->formatObj->getCapabilities(); + uint64_t capabilities = m->formatObj->i_getCapabilities(); ComAssertThrow(capabilities & ( MediumFormatCapabilities_CreateFixed | MediumFormatCapabilities_CreateDynamic), E_FAIL); Assert(m->state == MediumState_Creating); @@ -6709,7 +6931,8 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task) /* The object may request a specific UUID (through a special form of * the setLocation() argument). Otherwise we have to generate it */ Guid targetId = pTarget->m->id; - fGenerateUuid = targetId.isEmpty(); + + fGenerateUuid = targetId.isZero(); if (fGenerateUuid) { targetId.create(); @@ -6721,7 +6944,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task) Utf8Str targetFormat(pTarget->m->strFormat); Utf8Str targetLocation(pTarget->m->strLocationFull); - uint64_t capabilities = pTarget->m->formatObj->getCapabilities(); + uint64_t capabilities = pTarget->m->formatObj->i_getCapabilities(); ComAssertThrow(capabilities & MediumFormatCapabilities_CreateDynamic, E_FAIL); Assert(pTarget->m->state == MediumState_Creating); @@ -6762,7 +6985,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task) vrc = VDOpen(hdd, pMedium->m->strFormat.c_str(), pMedium->m->strLocationFull.c_str(), - VD_OPEN_FLAGS_READONLY | m->uOpenFlagsDef, + VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef, pMedium->m->vdImageIfaces); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, @@ -6988,18 +7211,21 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task) /* we need to update UUIDs of all source's children * which cannot be part of the container at once so * add each one in there individually */ - if (task.mChildrenToReparent.size() > 0) + if (task.mpChildrenToReparent) { - for (MediaList::const_iterator it = task.mChildrenToReparent.begin(); - it != task.mChildrenToReparent.end(); + MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin(); + MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd(); + for (MediumLockList::Base::iterator it = childrenBegin; + it != childrenEnd; ++it) { + Medium *pMedium = it->GetMedium(); /* VD_OPEN_FLAGS_INFO since UUID is wrong yet */ vrc = VDOpen(hdd, - (*it)->m->strFormat.c_str(), - (*it)->m->strLocationFull.c_str(), + pMedium->m->strFormat.c_str(), + pMedium->m->strLocationFull.c_str(), VD_OPEN_FLAGS_INFO | m->uOpenFlagsDef, - (*it)->m->vdImageIfaces); + pMedium->m->vdImageIfaces); if (RT_FAILURE(vrc)) throw vrc; @@ -7011,8 +7237,6 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task) vrc = VDClose(hdd, false /* fDelete */); if (RT_FAILURE(vrc)) throw vrc; - - (*it)->UnlockWrite(NULL); } } } @@ -7075,16 +7299,18 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task) /* reparent source's children and disconnect the deleted * branch at the younger end */ - if (task.mChildrenToReparent.size() > 0) + if (task.mpChildrenToReparent) { /* obey {parent,child} lock order */ AutoWriteLock sourceLock(this COMMA_LOCKVAL_SRC_POS); - for (MediaList::const_iterator it = task.mChildrenToReparent.begin(); - it != task.mChildrenToReparent.end(); - it++) + MediumLockList::Base::iterator childrenBegin = task.mpChildrenToReparent->GetBegin(); + MediumLockList::Base::iterator childrenEnd = task.mpChildrenToReparent->GetEnd(); + for (MediumLockList::Base::iterator it = childrenBegin; + it != childrenEnd; + ++it) { - Medium *pMedium = *it; + Medium *pMedium = it->GetMedium(); AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS); pMedium->deparent(); // removes pMedium from source @@ -7170,10 +7396,7 @@ HRESULT Medium::taskMergeHandler(Medium::MergeTask &task) * in the mergeTo() docs. The latter also implies that we * don't own the merge chain, so release it in this case. */ if (task.isAsync()) - { - Assert(task.mChildrenToReparent.size() == 0); - cancelMergeTo(task.mChildrenToReparent, task.mpMediumLockList); - } + cancelMergeTo(task.mpChildrenToReparent, task.mpMediumLockList); } return mrc; @@ -7213,7 +7436,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task) /* The object may request a specific UUID (through a special form of * the setLocation() argument). Otherwise we have to generate it */ Guid targetId = pTarget->m->id; - fGenerateUuid = targetId.isEmpty(); + + fGenerateUuid = targetId.isZero(); if (fGenerateUuid) { targetId.create(); @@ -7258,7 +7482,7 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task) Utf8Str targetFormat(pTarget->m->strFormat); Utf8Str targetLocation(pTarget->m->strLocationFull); - uint64_t capabilities = pTarget->m->formatObj->getCapabilities(); + uint64_t capabilities = pTarget->m->formatObj->i_getCapabilities(); Assert( pTarget->m->state == MediumState_Creating || pTarget->m->state == MediumState_LockedWrite); @@ -7407,7 +7631,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task) ComObjPtr pMedium; mrc = pParent->m->pVirtualBox->registerMedium(pTarget, &pMedium, DeviceType_HardDisk); - Assert(pTarget == pMedium); + Assert( FAILED(mrc) + || pTarget == pMedium); eik.fetch(); if (FAILED(mrc)) @@ -7421,7 +7646,8 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task) ComObjPtr pMedium; mrc = m->pVirtualBox->registerMedium(pTarget, &pMedium, DeviceType_HardDisk); - Assert(pTarget == pMedium); + Assert( FAILED(mrc) + || pTarget == pMedium); eik.fetch(); } } @@ -7672,15 +7898,8 @@ HRESULT Medium::taskResetHandler(Medium::ResetTask &task) m->logicalSize = logicalSize; m->variant = variant; - if (task.isAsync()) - { - /* unlock ourselves when done */ - HRESULT rc2 = UnlockWrite(NULL); - AssertComRC(rc2); - } - - /* Note that in sync mode, it's the caller's responsibility to - * unlock the medium. */ + /* Everything is explicitly unlocked when the task exits, + * as the task destruction also destroys the media chain. */ return rc; } @@ -7736,7 +7955,7 @@ HRESULT Medium::taskCompactHandler(Medium::CompactTask &task) vrc = VDOpen(hdd, pMedium->m->strFormat.c_str(), pMedium->m->strLocationFull.c_str(), - m->uOpenFlagsDef | (it == mediumListLast) ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY, + m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY), pMedium->m->vdImageIfaces); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, @@ -7792,13 +8011,14 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task) { HRESULT rc = S_OK; - /* Lock all in {parent,child} order. The lock is also used as a - * signal from the task initiator (which releases it only after - * RTThreadCreate()) that we can start the job. */ - AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); + uint64_t size = 0, logicalSize = 0; try { + /* The lock is also used as a signal from the task initiator (which + * releases it only after RTThreadCreate()) that we can start the job */ + AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); + PVBOXHDD hdd; int vrc = VDCreate(m->vdDiskIfaces, convertDeviceType(), &hdd); ComAssertRCThrow(vrc, E_FAIL); @@ -7833,7 +8053,7 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task) vrc = VDOpen(hdd, pMedium->m->strFormat.c_str(), pMedium->m->strLocationFull.c_str(), - m->uOpenFlagsDef | (it == mediumListLast) ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY, + m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY), pMedium->m->vdImageIfaces); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, @@ -7867,6 +8087,8 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task) location.c_str(), vdError(vrc).c_str()); } + size = VDGetFileSize(hdd, VD_LAST_IMAGE); + logicalSize = VDGetSize(hdd, VD_LAST_IMAGE); } catch (HRESULT aRC) { rc = aRC; } @@ -7874,6 +8096,13 @@ HRESULT Medium::taskResizeHandler(Medium::ResizeTask &task) } catch (HRESULT aRC) { rc = aRC; } + if (SUCCEEDED(rc)) + { + AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); + m->size = size; + m->logicalSize = logicalSize; + } + /* Everything is explicitly unlocked when the task exits, * as the task destruction also destroys the media chain. */ @@ -7936,9 +8165,9 @@ HRESULT Medium::taskExportHandler(Medium::ExportTask &task) vdError(vrc).c_str()); } - Utf8Str targetFormat(task.mFormat->getId()); + Utf8Str targetFormat(task.mFormat->i_getId()); Utf8Str targetLocation(task.mFilename); - uint64_t capabilities = task.mFormat->getCapabilities(); + uint64_t capabilities = task.mFormat->i_getCapabilities(); Assert(m->state == MediumState_LockedRead); @@ -8031,7 +8260,8 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task) /* The object may request a specific UUID (through a special form of * the setLocation() argument). Otherwise we have to generate it */ Guid targetId = m->id; - fGenerateUuid = targetId.isEmpty(); + + fGenerateUuid = targetId.isZero(); if (fGenerateUuid) { targetId.create(); @@ -8048,7 +8278,7 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task) { /* Open source medium. */ vrc = VDOpen(hdd, - task.mFormat->getId().c_str(), + task.mFormat->i_getId().c_str(), task.mFilename.c_str(), VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SEQUENTIAL | m->uOpenFlagsDef, task.mVDImageIfaces); @@ -8060,7 +8290,7 @@ HRESULT Medium::taskImportHandler(Medium::ImportTask &task) Utf8Str targetFormat(m->strFormat); Utf8Str targetLocation(m->strLocationFull); - uint64_t capabilities = task.mFormat->getCapabilities(); + uint64_t capabilities = task.mFormat->i_getCapabilities(); Assert( m->state == MediumState_Creating || m->state == MediumState_LockedWrite); diff --git a/src/VBox/Main/src-server/MediumLock.cpp b/src/VBox/Main/src-server/MediumLock.cpp index b8b601ca..567973d4 100644 --- a/src/VBox/Main/src-server/MediumLock.cpp +++ b/src/VBox/Main/src-server/MediumLock.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -74,7 +74,12 @@ bool MediumLock::GetLockRequest() const return mLockWrite; } -HRESULT MediumLock::Lock() +bool MediumLock::IsLocked() const +{ + return mIsLocked; +} + +HRESULT MediumLock::Lock(bool aIgnoreLockedMedia) { if (mIsLocked) return S_OK; @@ -101,9 +106,20 @@ HRESULT MediumLock::Lock() break; default: if (mLockWrite) - rc = mMedium->LockWrite(NULL); + { + if (aIgnoreLockedMedia && ( state == MediumState_LockedRead + || state == MediumState_LockedWrite)) + return S_OK; + else + rc = mMedium->LockWrite(mToken.asOutParam()); + } else - rc = mMedium->LockRead(NULL); + { + if (aIgnoreLockedMedia && state == MediumState_LockedWrite) + return S_OK; + else + rc = mMedium->LockRead(mToken.asOutParam()); + } } if (SUCCEEDED(rc)) { @@ -120,12 +136,10 @@ HRESULT MediumLock::Lock() HRESULT MediumLock::Unlock() { HRESULT rc = S_OK; - if (mIsLocked && !mLockSkipped) + if (mIsLocked && !mLockSkipped && mToken) { - if (mLockWrite) - rc = mMedium->UnlockWrite(NULL); - else - rc = mMedium->UnlockRead(NULL); + mToken->Abandon(); + mToken.setNull(); } mMediumCaller.attach(NULL); mLockSkipped = false; @@ -201,7 +215,7 @@ MediumLockList::Base::iterator MediumLockList::GetEnd() return mMediumLocks.end(); } -HRESULT MediumLockList::Lock() +HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */) { if (mIsLocked) return S_OK; @@ -210,7 +224,7 @@ HRESULT MediumLockList::Lock() it != mMediumLocks.end(); it++) { - rc = it->Lock(); + rc = it->Lock(fSkipOverLockedMedia); if (FAILED(rc)) { for (MediumLockList::Base::iterator it2 = mMediumLocks.begin(); @@ -288,7 +302,9 @@ HRESULT MediumLockListMap::Remove(const ComObjPtr &aMediumAtta MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment); if (it == mMediumLocks.end()) return VBOX_E_INVALID_OBJECT_STATE; + MediumLockList *pMediumLockList = it->second; mMediumLocks.erase(it); + delete pMediumLockList; return S_OK; } diff --git a/src/VBox/Main/src-server/NATEngineImpl.cpp b/src/VBox/Main/src-server/NATEngineImpl.cpp index 7ce08fd8..e58e533a 100644 --- a/src/VBox/Main/src-server/NATEngineImpl.cpp +++ b/src/VBox/Main/src-server/NATEngineImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,6 +26,7 @@ #include #include +#include // constructor / destructor @@ -338,6 +339,7 @@ NATEngine::RemoveRedirect(IN_BSTR aName) mNATRules.erase(it); mParent->setModified(Machine::IsModified_NetworkAdapters); m_fModified = true; + mData.commit(); alock.release(); mParent->onNATRedirectRuleChange(ulSlot, TRUE, aName, proto, Bstr(strHostIP).raw(), u16HostPort, Bstr(strGuestIP).raw(), u16GuestPort); return S_OK; diff --git a/src/VBox/Main/src-server/NATNetworkImpl.cpp b/src/VBox/Main/src-server/NATNetworkImpl.cpp new file mode 100644 index 00000000..65327250 --- /dev/null +++ b/src/VBox/Main/src-server/NATNetworkImpl.cpp @@ -0,0 +1,1115 @@ +/* $Id: NATNetworkImpl.cpp $ */ +/** @file + * INATNetwork implementation. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include "NetworkServiceRunner.h" +#include "DHCPServerImpl.h" +#include "NATNetworkImpl.h" +#include "AutoCaller.h" +#include "Logging.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "EventImpl.h" +#include "VBoxEvents.h" + +#include "VirtualBoxImpl.h" +#include +#include + +#ifndef RT_OS_WINDOWS +# include +#else +# define IN_LOOPBACKNET 127 +#endif + + +// constructor / destructor +///////////////////////////////////////////////////////////////////////////// + +struct NATNetwork::Data +{ + Data() + : fEnabled(TRUE) + , fIPv6Enabled(FALSE) + , fAdvertiseDefaultIPv6Route(FALSE) + , fNeedDhcpServer(TRUE) + , u32LoopbackIp6(0) + , offGateway(0) + , offDhcp(0) + { + IPv4Gateway.setNull(); + IPv4NetworkCidr.setNull(); + IPv6Prefix.setNull(); + IPv4DhcpServer.setNull(); + IPv4NetworkMask.setNull(); + IPv4DhcpServerLowerIp.setNull(); + IPv4DhcpServerUpperIp.setNull(); + } + virtual ~Data(){} + const ComObjPtr pEventSource; +#ifdef VBOX_WITH_NAT_SERVICE + NATNetworkServiceRunner NATRunner; + ComObjPtr dhcpServer; +#endif + Bstr IPv4Gateway; + Bstr IPv4NetworkCidr; + Bstr IPv4NetworkMask; + Bstr IPv4DhcpServer; + Bstr IPv4DhcpServerLowerIp; + Bstr IPv4DhcpServerUpperIp; + BOOL fEnabled; + BOOL fIPv6Enabled; + Bstr IPv6Prefix; + BOOL fAdvertiseDefaultIPv6Route; + BOOL fNeedDhcpServer; + NATRuleMap mapName2PortForwardRule4; + NATRuleMap mapName2PortForwardRule6; + settings::NATLoopbackOffsetList llNATLoopbackOffsetList; + uint32_t u32LoopbackIp6; + uint32_t offGateway; + uint32_t offDhcp; +}; + + +NATNetwork::NATNetwork() + : mVirtualBox(NULL) +{ +} + + +NATNetwork::~NATNetwork() +{ +} + + +HRESULT NATNetwork::FinalConstruct() +{ + return BaseFinalConstruct(); +} + + +void NATNetwork::FinalRelease() +{ + uninit (); + + BaseFinalRelease(); +} + + +void NATNetwork::uninit() +{ + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + delete m; + m = NULL; + unconst(mVirtualBox) = NULL; +} + + +HRESULT NATNetwork::init(VirtualBox *aVirtualBox, IN_BSTR aName) +{ + AssertReturn(aName != NULL, E_INVALIDARG); + + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + /* share VirtualBox weakly (parent remains NULL so far) */ + unconst(mVirtualBox) = aVirtualBox; + unconst(mName) = aName; + m = new Data(); + m->offGateway = 1; + m->IPv4NetworkCidr = "10.0.2.0/24"; + m->IPv6Prefix = "fe80::/64"; + + settings::NATHostLoopbackOffset off; + off.strLoopbackHostAddress = "127.0.0.1"; + off.u32Offset = (uint32_t)2; + m->llNATLoopbackOffsetList.push_back(off); + + recalculateIpv4AddressAssignments(); + + HRESULT hrc = unconst(m->pEventSource).createObject(); + if (FAILED(hrc)) throw hrc; + + hrc = m->pEventSource->init(); + if (FAILED(hrc)) throw hrc; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + + +HRESULT NATNetwork::init(VirtualBox *aVirtualBox, + const settings::NATNetwork &data) +{ + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + /* share VirtualBox weakly (parent remains NULL so far) */ + unconst(mVirtualBox) = aVirtualBox; + + unconst(mName) = data.strNetworkName; + m = new Data(); + m->IPv4NetworkCidr = data.strNetwork; + m->fEnabled = data.fEnabled; + m->fAdvertiseDefaultIPv6Route = data.fAdvertiseDefaultIPv6Route; + m->fNeedDhcpServer = data.fNeedDhcpServer; + m->fIPv6Enabled = data.fIPv6; + + m->u32LoopbackIp6 = data.u32HostLoopback6Offset; + + m->llNATLoopbackOffsetList.clear(); + m->llNATLoopbackOffsetList.assign(data.llHostLoopbackOffsetList.begin(), + data.llHostLoopbackOffsetList.end()); + + recalculateIpv4AddressAssignments(); + + /* IPv4 port-forward rules */ + m->mapName2PortForwardRule4.clear(); + for (settings::NATRuleList::const_iterator it = data.llPortForwardRules4.begin(); + it != data.llPortForwardRules4.end(); ++it) + { + m->mapName2PortForwardRule4.insert(std::make_pair(it->strName.c_str(), *it)); + } + + /* IPv6 port-forward rules */ + m->mapName2PortForwardRule6.clear(); + for (settings::NATRuleList::const_iterator it = data.llPortForwardRules6.begin(); + it != data.llPortForwardRules6.end(); ++it) + { + m->mapName2PortForwardRule6.insert(std::make_pair(it->strName, *it)); + } + + HRESULT hrc = unconst(m->pEventSource).createObject(); + if (FAILED(hrc)) throw hrc; + + hrc = m->pEventSource->init(); + if (FAILED(hrc)) throw hrc; + + autoInitSpan.setSucceeded(); + + return S_OK; +} + + +HRESULT NATNetwork::saveSettings(settings::NATNetwork &data) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + data.strNetworkName = mName; + data.strNetwork = m->IPv4NetworkCidr; + data.fEnabled = RT_BOOL(m->fEnabled); + data.fAdvertiseDefaultIPv6Route = RT_BOOL(m->fAdvertiseDefaultIPv6Route); + data.fNeedDhcpServer = RT_BOOL(m->fNeedDhcpServer); + data.fIPv6 = RT_BOOL(m->fIPv6Enabled); + data.strIPv6Prefix = m->IPv6Prefix; + + /* saving ipv4 port-forward Rules*/ + data.llPortForwardRules4.clear(); + for (NATRuleMap::iterator it = m->mapName2PortForwardRule4.begin(); + it != m->mapName2PortForwardRule4.end(); ++it) + data.llPortForwardRules4.push_back(it->second); + + /* saving ipv6 port-forward Rules*/ + data.llPortForwardRules6.clear(); + for (NATRuleMap::iterator it = m->mapName2PortForwardRule6.begin(); + it != m->mapName2PortForwardRule6.end(); ++it) + data.llPortForwardRules6.push_back(it->second); + + data.u32HostLoopback6Offset = m->u32LoopbackIp6; + + data.llHostLoopbackOffsetList.clear(); + data.llHostLoopbackOffsetList.assign(m->llNATLoopbackOffsetList.begin(), + m->llNATLoopbackOffsetList.end()); + + mVirtualBox->onNATNetworkSetting(mName.raw(), + data.fEnabled ? TRUE : FALSE, + m->IPv4NetworkCidr.raw(), + m->IPv4Gateway.raw(), + data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE, + data.fNeedDhcpServer ? TRUE : FALSE); + + /* Notify listerners listening on this network only */ + fireNATNetworkSettingEvent(m->pEventSource, + mName.raw(), + data.fEnabled ? TRUE : FALSE, + m->IPv4NetworkCidr.raw(), + m->IPv4Gateway.raw(), + data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE, + data.fNeedDhcpServer ? TRUE : FALSE); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(EventSource)(IEventSource ** aEventSource) +{ + CheckComArgOutPointerValid(aEventSource); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* event source is const, no need to lock */ + m->pEventSource.queryInterfaceTo(aEventSource); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(NetworkName)(BSTR *aName) +{ + CheckComArgOutPointerValid(aName); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + mName.cloneTo(aName); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(NetworkName)(IN_BSTR aName) +{ + CheckComArgOutPointerValid(aName); + AutoCaller autoCaller(this); + + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aName == mName) + return S_OK; + + unconst(mName) = aName; + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(Enabled)(BOOL *aEnabled) +{ + CheckComArgOutPointerValid(aEnabled); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *aEnabled = m->fEnabled; + recalculateIpv4AddressAssignments(); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(Enabled)(BOOL aEnabled) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aEnabled == m->fEnabled) + return S_OK; + + m->fEnabled = aEnabled; + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(Gateway)(BSTR *aIPv4Gateway) +{ + CheckComArgOutPointerValid(aIPv4Gateway); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + m->IPv4Gateway.cloneTo(aIPv4Gateway); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(Network)(BSTR *aIPv4NetworkCidr) +{ + CheckComArgOutPointerValid(aIPv4NetworkCidr); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + m->IPv4NetworkCidr.cloneTo(aIPv4NetworkCidr); + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(Network)(IN_BSTR aIPv4NetworkCidr) +{ + CheckComArgOutPointerValid(aIPv4NetworkCidr); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aIPv4NetworkCidr == m->IPv4NetworkCidr) + return S_OK; + + /* silently ignore network cidr update for now. + * todo: keep internally guest address of port forward rule + * as offset from network id. + */ + if (!m->mapName2PortForwardRule4.empty()) + return S_OK; + + unconst(m->IPv4NetworkCidr) = Bstr(aIPv4NetworkCidr); + recalculateIpv4AddressAssignments(); + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(IPv6Enabled)(BOOL *aIPv6Enabled) +{ + CheckComArgOutPointerValid(aIPv6Enabled); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *aIPv6Enabled = m->fIPv6Enabled; + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(IPv6Enabled)(BOOL aIPv6Enabled) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aIPv6Enabled == m->fIPv6Enabled) + return S_OK; + + m->fIPv6Enabled = aIPv6Enabled; + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(IPv6Prefix) (BSTR *aIPv6Prefix) +{ + CheckComArgOutPointerValid(aIPv6Prefix); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + m->IPv6Prefix.cloneTo(aIPv6Prefix); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR aIPv6Prefix) +{ + CheckComArgOutPointerValid(aIPv6Prefix); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aIPv6Prefix == m->IPv6Prefix) + return S_OK; + + /* silently ignore network IPv6 prefix update. + * todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR) + */ + if (!m->mapName2PortForwardRule6.empty()) + return S_OK; + + unconst(m->IPv6Prefix) = Bstr(aIPv6Prefix); + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL *aAdvertiseDefaultIPv6Route) +{ + CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route; + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL aAdvertiseDefaultIPv6Route) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aAdvertiseDefaultIPv6Route == m->fAdvertiseDefaultIPv6Route) + return S_OK; + + m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route; + + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(NeedDhcpServer)(BOOL *aNeedDhcpServer) +{ + CheckComArgOutPointerValid(aNeedDhcpServer); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + *aNeedDhcpServer = m->fNeedDhcpServer; + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(NeedDhcpServer)(BOOL aNeedDhcpServer) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aNeedDhcpServer == m->fNeedDhcpServer) + return S_OK; + + m->fNeedDhcpServer = aNeedDhcpServer; + + recalculateIpv4AddressAssignments(); + + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMGETTER(LocalMappings)(ComSafeArrayOut(BSTR, aLocalMappings)) +{ + CheckComArgOutSafeArrayPointerValid(aLocalMappings); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + com::SafeArray sf(m->llNATLoopbackOffsetList.size()); + + size_t i = 0; + settings::NATLoopbackOffsetList::const_iterator it; + + for (it = m->llNATLoopbackOffsetList.begin(); + it != m->llNATLoopbackOffsetList.end(); ++it, ++i) + { + BstrFmt bstr("%s=%d", + (*it).strLoopbackHostAddress.c_str(), + (*it).u32Offset); + bstr.detachTo(&sf[i]); + } + sf.detachTo(ComSafeArrayOutArg(aLocalMappings)); + + return S_OK; +} + + +STDMETHODIMP NATNetwork::AddLocalMapping(IN_BSTR aHostId, LONG aOffset) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + //AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + RTNETADDRIPV4 addr, net, mask; + + int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr); + if (RT_FAILURE(rc)) + return E_INVALIDARG; + + /* check against 127/8 */ + if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET) + return E_INVALIDARG; + + /* check against networkid vs network mask */ + rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr).c_str(), &net, &mask); + if (RT_FAILURE(rc)) + return E_INVALIDARG; + + if (((net.u + aOffset) & mask.u) != net.u) + return E_INVALIDARG; + + settings::NATLoopbackOffsetList::iterator it; + + it = std::find(m->llNATLoopbackOffsetList.begin(), + m->llNATLoopbackOffsetList.end(), + Utf8Str(aHostId).c_str()); + + if (it != m->llNATLoopbackOffsetList.end()) + { + if (aOffset == 0) /* erase */ + m->llNATLoopbackOffsetList.erase(it, it); + else /* modify */ + { + settings::NATLoopbackOffsetList::iterator it1; + it1 = std::find(m->llNATLoopbackOffsetList.begin(), + m->llNATLoopbackOffsetList.end(), + (uint32_t)aOffset); + if (it1 != m->llNATLoopbackOffsetList.end()) + return E_INVALIDARG; /* this offset is already registered. */ + + (*it).u32Offset = aOffset; + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); + } + + /* injection */ + it = std::find(m->llNATLoopbackOffsetList.begin(), + m->llNATLoopbackOffsetList.end(), + (uint32_t)aOffset); + + if (it != m->llNATLoopbackOffsetList.end()) + return E_INVALIDARG; /* offset is already registered. */ + + settings::NATHostLoopbackOffset off; + off.strLoopbackHostAddress = aHostId; + off.u32Offset = (uint32_t)aOffset; + m->llNATLoopbackOffsetList.push_back(off); + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); +} + + +STDMETHODIMP NATNetwork::COMGETTER(LoopbackIp6)(LONG *aLoopbackIp6) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aLoopbackIp6 = m->u32LoopbackIp6; + return S_OK; +} + + +STDMETHODIMP NATNetwork::COMSETTER(LoopbackIp6)(LONG aLoopbackIp6) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (aLoopbackIp6 < 0) + return E_INVALIDARG; + + if (static_cast(aLoopbackIp6) == m->u32LoopbackIp6) + return S_OK; + + m->u32LoopbackIp6 = aLoopbackIp6; + } + + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + return mVirtualBox->saveSettings(); +} + + +STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4)) +{ + CheckComArgOutSafeArrayPointerValid(aPortForwardRules4); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4), + m->mapName2PortForwardRule4); + return S_OK; +} + +STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR, + aPortForwardRules6)) +{ + CheckComArgOutSafeArrayPointerValid(aPortForwardRules6); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6); + return S_OK; +} + + +STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6, + IN_BSTR aPortForwardRuleName, + NATProtocol_T aProto, + IN_BSTR aHostIp, + USHORT aHostPort, + IN_BSTR aGuestIp, + USHORT aGuestPort) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + Utf8Str name = aPortForwardRuleName; + Utf8Str proto; + settings::NATRule r; + NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4; + switch (aProto) + { + case NATProtocol_TCP: + proto = "tcp"; + break; + case NATProtocol_UDP: + proto = "udp"; + break; + default: + return E_INVALIDARG; + } + if (name.isEmpty()) + name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(), + Utf8Str(aHostIp).c_str(), aHostPort, + Utf8Str(aGuestIp).c_str(), aGuestPort); + + NATRuleMap::iterator it; + + for (it = mapRules.begin(); it != mapRules.end(); ++it) + { + r = it->second; + if (it->first == name) + return setError(E_INVALIDARG, + tr("A NAT rule of this name already exists")); + if ( r.strHostIP == Utf8Str(aHostIp) + && r.u16HostPort == aHostPort + && r.proto == aProto) + return setError(E_INVALIDARG, + tr("A NAT rule for this host port and this host IP already exists")); + } + + r.strName = name.c_str(); + r.proto = aProto; + r.strHostIP = aHostIp; + r.u16HostPort = aHostPort; + r.strGuestIP = aGuestIp; + r.u16GuestPort = aGuestPort; + mapRules.insert(std::make_pair(name, r)); + } + + { + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + } + + mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6, + aPortForwardRuleName, aProto, + aHostIp, aHostPort, + aGuestIp, aGuestPort); + + /* Notify listerners listening on this network only */ + fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE, + aIsIpv6, aPortForwardRuleName, aProto, + aHostIp, aHostPort, + aGuestIp, aGuestPort); + return S_OK; +} + + +STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); + + Utf8Str strHostIP; + Utf8Str strGuestIP; + uint16_t u16HostPort; + uint16_t u16GuestPort; + NATProtocol_T proto; + + + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 + : m->mapName2PortForwardRule4; + + NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName); + + if (it == mapRules.end()) + return E_INVALIDARG; + + strHostIP = it->second.strHostIP; + strGuestIP = it->second.strGuestIP; + u16HostPort = it->second.u16HostPort; + u16GuestPort = it->second.u16GuestPort; + proto = it->second.proto; + + mapRules.erase(it); + } + + { + AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mVirtualBox->saveSettings(); + ComAssertComRCRetRC(rc); + } + + mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6, + aPortForwardRuleName, proto, + Bstr(strHostIP).raw(), u16HostPort, + Bstr(strGuestIP).raw(), u16GuestPort); + + /* Notify listerners listening on this network only */ + fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE, + aIsIpv6, aPortForwardRuleName, proto, + Bstr(strHostIP).raw(), u16HostPort, + Bstr(strGuestIP).raw(), u16GuestPort); + return S_OK; +} + + +STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType) +{ +#ifdef VBOX_WITH_NAT_SERVICE + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + if (!m->fEnabled) return S_OK; + + m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(mName).c_str()); + m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str()); + m->NATRunner.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPv4Gateway).c_str()); + m->NATRunner.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->IPv4NetworkMask).c_str()); + + /* No portforwarding rules from command-line, all will be fetched via API */ + + if (m->fNeedDhcpServer) + { + /* + * Just to as idea... via API (on creation user pass the cidr of network and) + * and we calculate it's addreses (mutable?). + */ + + /* + * Configuration and running DHCP server: + * 1. find server first createDHCPServer + * 2. if return status is E_INVALARG => server already exists just find and start. + * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL + * 4. if return status S_OK proceed to DHCP server configuration + * 5. call setConfiguration() and pass all required parameters + * 6. start dhcp server. + */ + HRESULT hrc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(), + m->dhcpServer.asOutParam()); + switch (hrc) + { + case E_INVALIDARG: + /* server haven't beeen found let create it then */ + hrc = mVirtualBox->CreateDHCPServer(mName.raw(), + m->dhcpServer.asOutParam()); + if (FAILED(hrc)) + return E_FAIL; + /* breakthrough */ + + { + LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n", + Utf8Str(m->IPv4Gateway.raw()).c_str(), + Utf8Str(m->IPv4DhcpServer.raw()).c_str(), + Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(), + Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str())); + + hrc = m->dhcpServer->COMSETTER(Enabled)(true); + + BSTR dhcpip = NULL; + BSTR netmask = NULL; + BSTR lowerip = NULL; + BSTR upperip = NULL; + + m->IPv4DhcpServer.cloneTo(&dhcpip); + m->IPv4NetworkMask.cloneTo(&netmask); + m->IPv4DhcpServerLowerIp.cloneTo(&lowerip); + m->IPv4DhcpServerUpperIp.cloneTo(&upperip); + hrc = m->dhcpServer->SetConfiguration(dhcpip, + netmask, + lowerip, + upperip); + } + case S_OK: + break; + + default: + return E_FAIL; + } + + /* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main. */ + m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw()); + + hrc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType); + if (FAILED(hrc)) + { + m->dhcpServer.setNull(); + return E_FAIL; + } + } + + if (RT_SUCCESS(m->NATRunner.start())) + { + mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE); + return S_OK; + } + /** @todo missing setError()! */ + return E_FAIL; +#else + NOREF(aTrunkType); + ReturnComNotImplemented(); +#endif +} + + +STDMETHODIMP NATNetwork::Stop() +{ +#ifdef VBOX_WITH_NAT_SERVICE + if (!m->dhcpServer.isNull()) + m->dhcpServer->Stop(); + + if (RT_SUCCESS(m->NATRunner.stop())) + { + mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE); + return S_OK; + } + /** @todo missing setError()! */ + return E_FAIL; +#else + ReturnComNotImplemented(); +#endif +} + + +void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules) +{ + com::SafeArray sf(aRules.size()); + size_t i = 0; + NATRuleMap::const_iterator it; + for (it = aRules.begin(); + it != aRules.end(); ++it, ++i) + { + settings::NATRule r = it->second; + BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d", + r.strName.c_str(), + (r.proto == NATProtocol_TCP? "tcp" : "udp"), + r.strHostIP.c_str(), + r.u16HostPort, + r.strGuestIP.c_str(), + r.u16GuestPort); + bstr.detachTo(&sf[i]); + } + sf.detachTo(ComSafeArrayOutArg(aPortForwardRules)); +} + + +int NATNetwork::findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff) +{ + RTNETADDRIPV4 network, netmask; + + int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(), + &network, + &netmask); + AssertRCReturn(rc, rc); + + uint32_t off; + settings::NATLoopbackOffsetList::iterator it; + for (off = 1; off < ~netmask.u; ++off) + { + + bool skip = false; + for (it = m->llNATLoopbackOffsetList.begin(); + it != m->llNATLoopbackOffsetList.end(); + ++it) + { + if ((*it).u32Offset == off) + { + skip = true; + break; + } + + } + + if (skip) + continue; + + if (off == m->offGateway) + { + if (addrType == ADDR_GATEWAY) + break; + else + continue; + } + + if (off == m->offDhcp) + { + if (addrType == ADDR_DHCP) + break; + else + continue; + } + + if (!skip) + break; + } + + if (poff) + *poff = off; + + return VINF_SUCCESS; +} + + +int NATNetwork::recalculateIpv4AddressAssignments() +{ + RTNETADDRIPV4 network, netmask; + int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(), + &network, + &netmask); + AssertRCReturn(rc, rc); + + findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway); + if (m->fNeedDhcpServer) + findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp); + + /* I don't remember the reason CIDR calculated on the host. */ + RTNETADDRIPV4 gateway = network; + gateway.u += m->offGateway; + gateway.u = RT_H2N_U32(gateway.u); + char szTmpIp[16]; + RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway); + m->IPv4Gateway = szTmpIp; + + if (m->fNeedDhcpServer) + { + RTNETADDRIPV4 dhcpserver = network; + dhcpserver.u += m->offDhcp; + + /* XXX: adding more services should change the math here */ + RTNETADDRIPV4 dhcplowerip = network; + uint32_t offDhcpLowerIp; + findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp); + dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp); + + RTNETADDRIPV4 dhcpupperip; + dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1); + + dhcpserver.u = RT_H2N_U32(dhcpserver.u); + network.u = RT_H2N_U32(network.u); + + RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver); + m->IPv4DhcpServer = szTmpIp; + RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip); + m->IPv4DhcpServerLowerIp = szTmpIp; + RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip); + m->IPv4DhcpServerUpperIp = szTmpIp; + + LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n", + network, dhcpserver, dhcplowerip, dhcpupperip)); + } + + /* we need IPv4NetworkMask for NAT's gw service start */ + netmask.u = RT_H2N_U32(netmask.u); + RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask); + m->IPv4NetworkMask = szTmpIp; + + LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask)); + return VINF_SUCCESS; +} diff --git a/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp new file mode 100644 index 00000000..5b51db5b --- /dev/null +++ b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp @@ -0,0 +1,149 @@ +/* $Id: NATNetworkServiceRunner.cpp $ */ +/** @file + * VirtualBox Main - interface for VBox NAT Network service + */ + +/* + * Copyright (C) 2009-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#include "NATNetworkServiceRunner.h" +#include +#include +#include + +struct ARGDEF +{ + NATSCCFG Type; + const char * Name; +}; + +#ifdef RT_OS_WINDOWS +# define NATSR_EXECUTABLE_NAME "VBoxNetNAT.exe" +#else +# define NATSR_EXECUTABLE_NAME "VBoxNetNAT" +#endif + +static const ARGDEF g_aArgDefs[] = +{ + {NATSCCFG_NAME, "-n"}, + {NATSCCFG_TRUNKTYPE, "--trunk-type"}, + {NATSCCFG_MACADDRESS, "--mac-address"}, + {NATSCCFG_IPADDRESS, "--ip-address"}, + {NATSCCFG_NETMASK, "--netmask"}, + {NATSCCFG_PORTFORWARD4, "--pf4"}, + {NATSCCFG_PORTFORWARD6, "--pf6"} + +}; + +static const ARGDEF * getArgDef(NATSCCFG type) +{ + for (unsigned i = 0; i < RT_ELEMENTS(g_aArgDefs); i++) + if (g_aArgDefs[i].Type == type) + return &g_aArgDefs[i]; + + return NULL; +} + +NATNetworkServiceRunner::NATNetworkServiceRunner() +{ + mProcess = NIL_RTPROCESS; + for (unsigned i = 0; i < NATSCCFG_NOTOPT_MAXVAL; i++) + { + mOptionEnabled[i] = false; + } +} + +void NATNetworkServiceRunner::detachFromServer() +{ + mProcess = NIL_RTPROCESS; +} + +int NATNetworkServiceRunner::start() +{ + if (isRunning()) + return VINF_ALREADY_INITIALIZED; + + const char * args[NATSCCFG_NOTOPT_MAXVAL * 2]; + + /* get the path to the executable */ + char exePathBuf[RTPATH_MAX]; + const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX); + char *substrSl = strrchr(exePathBuf, '/'); + char *substrBs = strrchr(exePathBuf, '\\'); + char *suffix = substrSl ? substrSl : substrBs; + + if (suffix) + { + suffix++; + strcpy(suffix, NATSR_EXECUTABLE_NAME); + } + else + exePath = NATSR_EXECUTABLE_NAME; + + int index = 0; + + args[index++] = exePath; + + for (unsigned i = 0; i < NATSCCFG_NOTOPT_MAXVAL; i++) + { + if (mOptionEnabled[i]) + { + const ARGDEF *pArgDef = getArgDef((NATSCCFG)i); + if (!pArgDef) + continue; + args[index++] = pArgDef->Name; // e.g. "--network" + + /* value can be null for e.g. --begin-config has no value + * and thus check the mOptions string length here + */ + if (mOptions[i].length()) + args[index++] = mOptions[i].c_str(); // value + } + } + + args[index++] = NULL; + RTENV env; + int rc = RTEnvCreate(&env); + AssertRCReturn(rc,rc); + + RTEnvPutEx(env, "VBOX_LOG=e.l.f"); + + rc = RTProcCreate(exePath, args, RTENV_DEFAULT, 0, &mProcess); + if (RT_FAILURE(rc)) + mProcess = NIL_RTPROCESS; + RTEnvDestroy(env); + return rc; +} + +int NATNetworkServiceRunner::stop() +{ + if (!isRunning()) + return VINF_OBJECT_DESTROYED; + + int rc = RTProcTerminate(mProcess); + mProcess = NIL_RTPROCESS; + return rc; +} + +bool NATNetworkServiceRunner::isRunning() +{ + if (mProcess == NIL_RTPROCESS) + return false; + + RTPROCSTATUS status; + int rc = RTProcWait(mProcess, RTPROCWAIT_FLAGS_NOBLOCK, &status); + + if (rc == VERR_PROCESS_RUNNING) + return true; + + mProcess = NIL_RTPROCESS; + return false; +} diff --git a/src/VBox/Main/src-server/NetworkAdapterImpl.cpp b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp index c7e1fa17..e3908bb3 100644 --- a/src/VBox/Main/src-server/NetworkAdapterImpl.cpp +++ b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,6 +23,7 @@ #include "GuestOSTypeImpl.h" #include "HostImpl.h" #include "SystemPropertiesImpl.h" +#include "VirtualBoxImpl.h" #include #include @@ -439,8 +440,7 @@ STDMETHODIMP NetworkAdapter::COMSETTER(MACAddress)(IN_BSTR aMACAddress) return rc; } -STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)( - NetworkAttachmentType_T *aAttachmentType) +STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(NetworkAttachmentType_T *aAttachmentType) { CheckComArgOutPointerValid(aAttachmentType); @@ -454,8 +454,7 @@ STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)( return S_OK; } -STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)( - NetworkAttachmentType_T aAttachmentType) +STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)(NetworkAttachmentType_T aAttachmentType) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -477,6 +476,14 @@ STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)( mData->mInternalNetwork = "intnet"; } + /* there must a NAT network name */ + if (mData->mNATNetwork.isEmpty()) + { + Log(("NAT network name not defined, setting to default \"NatNetwork\"\n")); + mData->mNATNetwork = "NatNetwork"; + } + + NetworkAttachmentType_T oldAttachmentType = mData->mAttachmentType; mData->mAttachmentType = aAttachmentType; m_fModified = true; @@ -487,6 +494,12 @@ STDMETHODIMP NetworkAdapter::COMSETTER(AttachmentType)( mParent->setModified(Machine::IsModified_NetworkAdapters); mlock.release(); + if (oldAttachmentType == NetworkAttachmentType_NATNetwork) + checkAndSwitchFromNatNetworking(mData->mNATNetwork.raw()); + + if (aAttachmentType == NetworkAttachmentType_NATNetwork) + switchToNatNetworking(mData->mNATNetwork.raw()); + /* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */ mParent->onNetworkAdapterChange(this, TRUE); } @@ -525,6 +538,15 @@ STDMETHODIMP NetworkAdapter::COMSETTER(BridgedInterface)(IN_BSTR aBridgedInterfa if (mData->mBridgedInterface != aBridgedInterface) { + /* if an empty/null string is to be set, bridged interface must be + * turned off */ + if ( (aBridgedInterface == NULL || *aBridgedInterface == '\0') + && mData->mAttachmentType == NetworkAttachmentType_Bridged) + { + return setError(E_FAIL, + tr("Empty or null bridged interface name is not valid")); + } + mData.backup(); mData->mBridgedInterface = aBridgedInterface; @@ -576,6 +598,15 @@ STDMETHODIMP NetworkAdapter::COMSETTER(HostOnlyInterface)(IN_BSTR aHostOnlyInter if (mData->mHostOnlyInterface != aHostOnlyInterface) { + /* if an empty/null string is to be set, host only interface must be + * turned off */ + if ( (aHostOnlyInterface == NULL || *aHostOnlyInterface == '\0') + && mData->mAttachmentType == NetworkAttachmentType_HostOnly) + { + return setError(E_FAIL, + tr("Empty or null host only interface name is not valid")); + } + mData.backup(); mData->mHostOnlyInterface = aHostOnlyInterface; @@ -683,7 +714,19 @@ STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork)(IN_BSTR aNATNetwork) if (mData->mNATNetwork != aNATNetwork) { + + /* if an empty/null string is to be set, host only interface must be + * turned off */ + if ( (aNATNetwork == NULL || *aNATNetwork == '\0') + && mData->mAttachmentType == NetworkAttachmentType_NATNetwork) + { + return setError(E_FAIL, + tr("Empty or null NAT network name is not valid")); + } + mData.backup(); + + Bstr oldNatNetworkName = mData->mNATNetwork; mData->mNATNetwork = aNATNetwork; m_fModified = true; @@ -694,9 +737,14 @@ STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork)(IN_BSTR aNATNetwork) mParent->setModified(Machine::IsModified_NetworkAdapters); mlock.release(); - /* Changing the NAT network isn't allowed during runtime, therefore - * no immediate replug in CFGM logic => changeAdapter=FALSE */ - mParent->onNetworkAdapterChange(this, FALSE); + checkAndSwitchFromNatNetworking(oldNatNetworkName.raw()); + + switchToNatNetworking(aNATNetwork); + + /* When changing the host adapter, adapt the CFGM logic to make this + * change immediately effect and to notify the guest that the network + * might have changed, therefore changeAdapter=TRUE. */ + mParent->onNetworkAdapterChange(this, TRUE); } return S_OK; @@ -1208,6 +1256,7 @@ HRESULT NetworkAdapter::loadSettings(BandwidthControl *bwctl, mData->mHostOnlyInterface = data.strHostOnlyName; mData->mGenericDriver = data.strGenericDriver; mData->mGenericProperties = data.genericProperties; + mData->mNATNetwork = data.strNATNetworkName; // leave the lock before setting attachment type alock.release(); @@ -1268,6 +1317,8 @@ HRESULT NetworkAdapter::saveSettings(settings::NetworkAdapter &data) data.strGenericDriver = mData->mGenericDriver; data.genericProperties = mData->mGenericProperties; + data.strNATNetworkName = mData->mNATNetwork; + // after saving settings, we are no longer different from the XML on disk m_fModified = false; @@ -1511,4 +1562,48 @@ void NetworkAdapter::updateBandwidthGroup(BandwidthGroup *aBwGroup) LogFlowThisFuncLeave(); } + + +HRESULT NetworkAdapter::checkAndSwitchFromNatNetworking(IN_BSTR networkName) +{ + MachineState_T state; + + HRESULT hrc = mParent->COMGETTER(State)(&state); + if (FAILED(hrc)) + return hrc; + + if (state == MachineState_Running) + { + Bstr bstrName; + hrc = mParent->COMGETTER(Name)(bstrName.asOutParam()); + LogRel(("VM '%ls' stops using NAT network '%ls'\n", bstrName.raw(), networkName)); + int natCount = mParent->getVirtualBox()->natNetworkRefDec(networkName); + if (natCount == -1) + return E_INVALIDARG; /* no such network */ + } + + return S_OK; +} + + +HRESULT NetworkAdapter::switchToNatNetworking(IN_BSTR aNatNetworkName) +{ + MachineState_T state; + + HRESULT hrc = mParent->COMGETTER(State)(&state); + if (FAILED(hrc)) + return hrc; + + if (state == MachineState_Running) + { + Bstr bstrName; + hrc = mParent->COMGETTER(Name)(bstrName.asOutParam()); + LogRel(("VM '%ls' starts using NAT network '%ls'\n", bstrName.raw(), aNatNetworkName)); + int natCount = mParent->getVirtualBox()->natNetworkRefInc(aNatNetworkName); + if (natCount == -1) + return E_INVALIDARG; /* not found */ + } + + return S_OK; +} /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/NetworkServiceRunner.cpp b/src/VBox/Main/src-server/NetworkServiceRunner.cpp new file mode 100644 index 00000000..14610e5a --- /dev/null +++ b/src/VBox/Main/src-server/NetworkServiceRunner.cpp @@ -0,0 +1,138 @@ +/* $Id: NetworkServiceRunner.cpp $ */ +/** @file + * VirtualBox Main - interface for VBox DHCP server + */ + +/* + * Copyright (C) 2009-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include "NetworkServiceRunner.h" +#include +#include +#include + + +const std::string NetworkServiceRunner::kNsrKeyName = "--name"; +const std::string NetworkServiceRunner::kNsrKeyNetwork = "--network"; +const std::string NetworkServiceRunner::kNsrKeyTrunkType = "--trunk-type"; +const std::string NetworkServiceRunner::kNsrTrunkName = "--trunk-name"; +const std::string NetworkServiceRunner::kNsrMacAddress = "--mac-address"; +const std::string NetworkServiceRunner::kNsrIpAddress = "--ip-address"; +const std::string NetworkServiceRunner::kNsrIpNetmask = "--netmask"; +const std::string NetworkServiceRunner::kNsrKeyNeedMain = "--need-main"; + +struct NetworkServiceRunner::Data +{ + Data(const char* aProcName):mProcName(aProcName), mProcess(NIL_RTPROCESS){} + const char *mProcName; + RTPROCESS mProcess; + std::map mOptions; +}; + +NetworkServiceRunner::NetworkServiceRunner(const char *aProcName) +{ + m = new NetworkServiceRunner::Data(aProcName); + +} + + +NetworkServiceRunner::~NetworkServiceRunner() +{ + stop(); + delete m; + m = NULL; +} + + +int NetworkServiceRunner::setOption(const std::string& key, const std::string& val) +{ + m->mOptions.insert(std::map::value_type(key, val)); + return VINF_SUCCESS; +} + + +void NetworkServiceRunner::detachFromServer() +{ + m->mProcess = NIL_RTPROCESS; +} + + +int NetworkServiceRunner::start() +{ + if (isRunning()) + return VINF_ALREADY_INITIALIZED; + + const char * args[10*2]; + + AssertReturn(m->mOptions.size() < 10, VERR_INTERNAL_ERROR); + + /* get the path to the executable */ + char exePathBuf[RTPATH_MAX]; + const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX); + char *substrSl = strrchr(exePathBuf, '/'); + char *substrBs = strrchr(exePathBuf, '\\'); + char *suffix = substrSl ? substrSl : substrBs; + + if (suffix) + { + suffix++; + strcpy(suffix, m->mProcName); + } + + int index = 0; + + args[index++] = exePath; + + std::map::const_iterator it; + for(it = m->mOptions.begin(); it != m->mOptions.end(); ++it) + { + args[index++] = it->first.c_str(); + args[index++] = it->second.c_str(); + } + + args[index++] = NULL; + + int rc = RTProcCreate(suffix ? exePath : m->mProcName, args, RTENV_DEFAULT, 0, &m->mProcess); + if (RT_FAILURE(rc)) + m->mProcess = NIL_RTPROCESS; + + return rc; +} + + +int NetworkServiceRunner::stop() +{ + if (!isRunning()) + return VINF_OBJECT_DESTROYED; + + int rc = RTProcTerminate(m->mProcess); + RTProcWait(m->mProcess, RTPROCWAIT_FLAGS_BLOCK, NULL); + m->mProcess = NIL_RTPROCESS; + return rc; +} + +bool NetworkServiceRunner::isRunning() +{ + if (m->mProcess == NIL_RTPROCESS) + return false; + + RTPROCSTATUS status; + int rc = RTProcWait(m->mProcess, RTPROCWAIT_FLAGS_NOBLOCK, &status); + + if (rc == VERR_PROCESS_RUNNING) + return true; + + m->mProcess = NIL_RTPROCESS; + return false; +} diff --git a/src/VBox/Main/src-server/ParallelPortImpl.cpp b/src/VBox/Main/src-server/ParallelPortImpl.cpp index 56743a08..e9ce1d0d 100644 --- a/src/VBox/Main/src-server/ParallelPortImpl.cpp +++ b/src/VBox/Main/src-server/ParallelPortImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/Performance.cpp b/src/VBox/Main/src-server/Performance.cpp index 465bfa1c..41ace847 100644 --- a/src/VBox/Main/src-server/Performance.cpp +++ b/src/VBox/Main/src-server/Performance.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,8 +24,12 @@ #ifndef VBOX_COLLECTOR_TEST_CASE #include "VirtualBoxImpl.h" #include "MachineImpl.h" +#include "MediumImpl.h" +#include "AutoCaller.h" #endif #include "Performance.h" +#include "HostNetworkInterfaceImpl.h" +#include "netif.h" #include #include @@ -45,47 +49,57 @@ using namespace pm; int CollectorHAL::getHostCpuLoad(ULONG * /* user */, ULONG * /* kernel */, ULONG * /* idle */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getProcessCpuLoad(RTPROCESS /* process */, ULONG * /* user */, ULONG * /* kernel */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getRawHostCpuLoad(uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* idle */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getRawHostNetworkLoad(const char * /* name */, uint64_t * /* rx */, uint64_t * /* tx */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getRawHostDiskLoad(const char * /* name */, uint64_t * /* disk_ms */, uint64_t * /* total_ms */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getRawProcessCpuLoad(RTPROCESS /* process */, uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* total */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getHostMemoryUsage(ULONG * /* total */, ULONG * /* used */, ULONG * /* available */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getHostFilesystemUsage(const char * /* name */, ULONG * /* total */, ULONG * /* used */, ULONG * /* available */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; +} + +int CollectorHAL::getHostDiskSize(const char * /* name */, uint64_t * /* size */) +{ + return VERR_NOT_IMPLEMENTED; } int CollectorHAL::getProcessMemoryUsage(RTPROCESS /* process */, ULONG * /* used */) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; +} + +int CollectorHAL::getDiskListByFs(const char * /* name */, DiskList& /* listUsage */, DiskList& /* listLoad */) +{ + return VERR_NOT_IMPLEMENTED; } /* Generic implementations */ @@ -169,7 +183,7 @@ CollectorGuestRequest* CollectorGuestQueue::pop() return NULL; } -int CGRQEnable::execute() +HRESULT CGRQEnable::execute() { Assert(mCGuest); return mCGuest->enableInternal(mMask); @@ -184,7 +198,7 @@ void CGRQEnable::debugPrint(void *aObject, const char *aFunction, const char *aT aObject, aFunction, mMask, aText)); } -int CGRQDisable::execute() +HRESULT CGRQDisable::execute() { Assert(mCGuest); return mCGuest->disableInternal(mMask); @@ -199,7 +213,7 @@ void CGRQDisable::debugPrint(void *aObject, const char *aFunction, const char *a aObject, aFunction, mMask, aText)); } -int CGRQAbort::execute() +HRESULT CGRQAbort::execute() { return E_ABORT; } @@ -217,7 +231,7 @@ CollectorGuest::CollectorGuest(Machine *machine, RTPROCESS process) : mUnregistered(false), mEnabled(false), mValid(false), mMachine(machine), mProcess(process), mCpuUser(0), mCpuKernel(0), mCpuIdle(0), mMemTotal(0), mMemFree(0), mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0), - mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0) + mAllocVMM(0), mFreeVMM(0), mBalloonedVMM(0), mSharedVMM(0), mVmNetRx(0), mVmNetTx(0) { Assert(mMachine); /* cannot use ComObjPtr in Performance.h, do it manually */ @@ -267,7 +281,7 @@ int CollectorGuest::disable(ULONG mask) return enqueueRequest(new CGRQDisable(mask)); } -int CollectorGuest::enableInternal(ULONG mask) +HRESULT CollectorGuest::enableInternal(ULONG mask) { HRESULT ret = S_OK; @@ -306,7 +320,7 @@ int CollectorGuest::enableInternal(ULONG mask) this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed")); } } - if ((mask & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM) + if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM) enableVMMStats(true); mEnabled |= mask; @@ -318,7 +332,7 @@ int CollectorGuest::disableInternal(ULONG mask) if (!(mEnabled & mask)) return E_UNEXPECTED; - if ((mask & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM) + if ((mask & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM) enableVMMStats(false); mEnabled &= ~mask; if (!mEnabled) @@ -328,7 +342,7 @@ int CollectorGuest::disableInternal(ULONG mask) NOREF(ret); LogAleksey(("{%p} " LOG_FN_FMT ": Set guest statistics update interval to 0 sec (%s)\n", this, __PRETTY_FUNCTION__, SUCCEEDED(ret)?"success":"failed")); - invalidate(GUESTSTATS_ALL); + invalidate(VMSTATS_ALL); } return S_OK; @@ -353,15 +367,16 @@ void CollectorGuest::updateStats(ULONG aValidStats, ULONG aCpuUser, ULONG aMemBalloon, ULONG aMemShared, ULONG aMemCache, ULONG aPageTotal, ULONG aAllocVMM, ULONG aFreeVMM, - ULONG aBalloonedVMM, ULONG aSharedVMM) + ULONG aBalloonedVMM, ULONG aSharedVMM, + ULONG aVmNetRx, ULONG aVmNetTx) { - if ((aValidStats & GUESTSTATS_CPULOAD) == GUESTSTATS_CPULOAD) + if ((aValidStats & VMSTATS_GUEST_CPULOAD) == VMSTATS_GUEST_CPULOAD) { mCpuUser = aCpuUser; mCpuKernel = aCpuKernel, mCpuIdle = aCpuIdle; } - if ((aValidStats & GUESTSTATS_RAMUSAGE) == GUESTSTATS_RAMUSAGE) + if ((aValidStats & VMSTATS_GUEST_RAMUSAGE) == VMSTATS_GUEST_RAMUSAGE) { mMemTotal = aMemTotal; mMemFree = aMemFree; @@ -370,13 +385,18 @@ void CollectorGuest::updateStats(ULONG aValidStats, ULONG aCpuUser, mMemCache = aMemCache; mPageTotal = aPageTotal; } - if ((aValidStats & GUESTSTATS_VMMRAM) == GUESTSTATS_VMMRAM) + if ((aValidStats & VMSTATS_VMM_RAM) == VMSTATS_VMM_RAM) { mAllocVMM = aAllocVMM; mFreeVMM = aFreeVMM; mBalloonedVMM = aBalloonedVMM; mSharedVMM = aSharedVMM; } + if ((aValidStats & VMSTATS_NET_RATE) == VMSTATS_NET_RATE) + { + mVmNetRx = aVmNetRx; + mVmNetTx = aVmNetTx; + } mValid = aValidStats; } @@ -446,7 +466,7 @@ void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest) { /* Found the guest already collecting stats, elect it */ mVMMStatsProvider = *it; - rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(GUESTSTATS_VMMRAM)); + rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM)); if (FAILED(rc)) { /* This is not a good candidate -- try to find another */ @@ -466,8 +486,8 @@ void CollectorGuestManager::unregisterGuest(CollectorGuest* pGuest) continue; mVMMStatsProvider = *it; - //mVMMStatsProvider->enable(GUESTSTATS_VMMRAM); - rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(GUESTSTATS_VMMRAM)); + //mVMMStatsProvider->enable(VMSTATS_VMM_RAM); + rc = mVMMStatsProvider->enqueueRequest(new CGRQEnable(VMSTATS_VMM_RAM)); if (SUCCEEDED(rc)) break; /* This was not a good candidate -- try to find another */ @@ -508,7 +528,7 @@ int CollectorGuestManager::enqueueRequest(CollectorGuestRequest *aRequest) */ if (aRequest->getGuest() && aRequest->getGuest() == mGuestBeingCalled) { - /* + /* * Before we can declare a guest blocked we need to wait for a while * and then check again as it may never had a chance to process * the previous request. Half a second is an eternity for processes @@ -619,6 +639,12 @@ void HostCpuLoad::collect() } } +void HostCpuLoadRaw::init(ULONG period, ULONG length) +{ + HostCpuLoad::init(period, length); + mHAL->getRawHostCpuLoad(&mUserPrev, &mKernelPrev, &mIdlePrev); +} + void HostCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */) { hints.collectHostCpuLoad(); @@ -659,13 +685,50 @@ void HostCpuLoadRaw::collect() } } +#ifndef VBOX_COLLECTOR_TEST_CASE +static bool getLinkSpeed(const char *szShortName, uint32_t *pSpeed) +{ + NETIFSTATUS enmState = NETIF_S_UNKNOWN; + int rc = NetIfGetState(szShortName, &enmState); + if (RT_FAILURE(rc)) + return false; + if (enmState != NETIF_S_UP) + *pSpeed = 0; + else + { + rc = NetIfGetLinkSpeed(szShortName, pSpeed); + if (RT_FAILURE(rc)) + return false; + } + return true; +} + +void HostNetworkSpeed::init(ULONG period, ULONG length) +{ + mPeriod = period; + mLength = length; + mLinkSpeed->init(length); + /* + * Retrieve the link speed now as it may be wrong if the metric was + * registered at boot (see @bugref{6613}). + */ + getLinkSpeed(mShortName.c_str(), &mSpeed); +} + void HostNetworkLoadRaw::init(ULONG period, ULONG length) { mPeriod = period; mLength = length; mRx->init(mLength); mTx->init(mLength); - int rc = mHAL->getRawHostNetworkLoad(mShortName.c_str(), &mRxPrev, &mTxPrev); + /* + * Retrieve the link speed now as it may be wrong if the metric was + * registered at boot (see @bugref{6613}). + */ + uint32_t uSpeedMbit = 65535; + if (getLinkSpeed(mShortName.c_str(), &uSpeedMbit)) + mSpeed = (uint64_t)uSpeedMbit * (1000000/8); /* Convert to bytes/sec */ + /*int rc =*/ mHAL->getRawHostNetworkLoad(mShortName.c_str(), &mRxPrev, &mTxPrev); //AssertRC(rc); } @@ -686,25 +749,23 @@ void HostNetworkLoadRaw::preCollect(CollectorHints& /* hints */, uint64_t /* iTi void HostNetworkLoadRaw::collect() { - uint64_t rx, tx; + uint64_t rx = mRxPrev; + uint64_t tx = mTxPrev; + if (RT_UNLIKELY(mSpeed * getPeriod() == 0)) + { + LogFlowThisFunc(("Check cable for %s! speed=%llu period=%d.\n", mShortName.c_str(), mSpeed, getPeriod())); + /* We do not collect host network metrics for unplugged interfaces! */ + return; + } mRc = mHAL->getRawHostNetworkLoad(mShortName.c_str(), &rx, &tx); if (RT_SUCCESS(mRc)) { uint64_t rxDiff = rx - mRxPrev; uint64_t txDiff = tx - mTxPrev; - if (RT_UNLIKELY(mSpeed * getPeriod() == 0)) - { - LogFlowThisFunc(("Check cable for %s! speed=%llu period=%d.\n", mShortName.c_str(), mSpeed, getPeriod())); - mRx->put(0); - mTx->put(0); - } - else - { - mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (mSpeed * getPeriod()))); - mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (mSpeed * getPeriod()))); - } + mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (mSpeed * getPeriod()))); + mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (mSpeed * getPeriod()))); mRxPrev = rx; mTxPrev = tx; @@ -713,6 +774,7 @@ void HostNetworkLoadRaw::collect() LogFlowThisFunc(("Failed to collect data: %Rrc (%d)." " Will update the list of interfaces...\n", mRc,mRc)); } +#endif /* !VBOX_COLLECTOR_TEST_CASE */ void HostDiskLoadRaw::init(ULONG period, ULONG length) { @@ -815,7 +877,6 @@ void HostRamUsage::collect() mTotal->put(total); mUsed->put(used); mAvailable->put(available); - } } @@ -841,10 +902,28 @@ void HostFilesystemUsage::collect() mTotal->put(total); mUsed->put(used); mAvailable->put(available); - } } +void HostDiskUsage::init(ULONG period, ULONG length) +{ + mPeriod = period; + mLength = length; + mTotal->init(mLength); +} + +void HostDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */) +{ +} + +void HostDiskUsage::collect() +{ + uint64_t total; + int rc = mHAL->getHostDiskSize(mDiskName.c_str(), &total); + if (RT_SUCCESS(rc)) + mTotal->put((ULONG)(total / _1M)); +} + #ifndef VBOX_COLLECTOR_TEST_CASE void HostRamVmm::init(ULONG period, ULONG length) { @@ -861,7 +940,7 @@ int HostRamVmm::enable() int rc = S_OK; CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider(); if (provider) - rc = provider->enable(GUESTSTATS_VMMRAM); + rc = provider->enable(VMSTATS_VMM_RAM); BaseMetric::enable(); return rc; } @@ -872,7 +951,7 @@ int HostRamVmm::disable() BaseMetric::disable(); CollectorGuest *provider = mCollectorGuestManager->getVMMStatsProvider(); if (provider) - rc = provider->disable(GUESTSTATS_VMMRAM); + rc = provider->disable(VMSTATS_VMM_RAM); return rc; } @@ -888,15 +967,15 @@ void HostRamVmm::collect() { LogAleksey(("{%p} " LOG_FN_FMT ": provider=%p enabled=%s valid=%s...\n", this, __PRETTY_FUNCTION__, provider, provider->isEnabled()?"y":"n", - provider->isValid(GUESTSTATS_VMMRAM)?"y":"n")); - if (provider->isValid(GUESTSTATS_VMMRAM)) + provider->isValid(VMSTATS_VMM_RAM)?"y":"n")); + if (provider->isValid(VMSTATS_VMM_RAM)) { /* Provider is ready, get updated stats */ mAllocCurrent = provider->getAllocVMM(); mFreeCurrent = provider->getFreeVMM(); mBalloonedCurrent = provider->getBalloonedVMM(); mSharedCurrent = provider->getSharedVMM(); - provider->invalidate(GUESTSTATS_VMMRAM); + provider->invalidate(VMSTATS_VMM_RAM); } /* * Note that if there are no new values from the provider we will use @@ -994,6 +1073,76 @@ void MachineRamUsage::collect() #ifndef VBOX_COLLECTOR_TEST_CASE +void MachineDiskUsage::init(ULONG period, ULONG length) +{ + mPeriod = period; + mLength = length; + mUsed->init(mLength); +} + +void MachineDiskUsage::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */) +{ +} + +void MachineDiskUsage::collect() +{ + ULONG used = 0; + + for (MediaList::iterator it = mDisks.begin(); it != mDisks.end(); ++it) + { + ComObjPtr pMedium = *it; + + /* just in case */ + AssertStmt(!pMedium.isNull(), continue); + + AutoCaller localAutoCaller(pMedium); + if (FAILED(localAutoCaller.rc())) continue; + + AutoReadLock local_alock(pMedium COMMA_LOCKVAL_SRC_POS); + + used += (ULONG)(pMedium->getSize() / _1M); + } + + mUsed->put(used); +} + +void MachineNetRate::init(ULONG period, ULONG length) +{ + mPeriod = period; + mLength = length; + + mRx->init(mLength); + mTx->init(mLength); +} + +void MachineNetRate::collect() +{ + if (mCGuest->isValid(VMSTATS_NET_RATE)) + { + mRx->put(mCGuest->getVmNetRx()); + mTx->put(mCGuest->getVmNetTx()); + mCGuest->invalidate(VMSTATS_NET_RATE); + } +} + +int MachineNetRate::enable() +{ + int rc = mCGuest->enable(VMSTATS_NET_RATE); + BaseMetric::enable(); + return rc; +} + +int MachineNetRate::disable() +{ + BaseMetric::disable(); + return mCGuest->disable(VMSTATS_NET_RATE); +} + +void MachineNetRate::preCollect(CollectorHints& hints, uint64_t /* iTick */) +{ + hints.collectGuestStats(mCGuest->getProcess()); +} + void GuestCpuLoad::init(ULONG period, ULONG length) { mPeriod = period; @@ -1011,18 +1160,18 @@ void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t /* iTick */) void GuestCpuLoad::collect() { - if (mCGuest->isValid(GUESTSTATS_CPULOAD)) + if (mCGuest->isValid(VMSTATS_GUEST_CPULOAD)) { mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuUser()) / 100); mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuKernel()) / 100); mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * mCGuest->getCpuIdle()) / 100); - mCGuest->invalidate(GUESTSTATS_CPULOAD); + mCGuest->invalidate(VMSTATS_GUEST_CPULOAD); } } int GuestCpuLoad::enable() { - int rc = mCGuest->enable(GUESTSTATS_CPULOAD); + int rc = mCGuest->enable(VMSTATS_GUEST_CPULOAD); BaseMetric::enable(); return rc; } @@ -1030,7 +1179,7 @@ int GuestCpuLoad::enable() int GuestCpuLoad::disable() { BaseMetric::disable(); - return mCGuest->disable(GUESTSTATS_CPULOAD); + return mCGuest->disable(VMSTATS_GUEST_CPULOAD); } void GuestRamUsage::init(ULONG period, ULONG length) @@ -1048,7 +1197,7 @@ void GuestRamUsage::init(ULONG period, ULONG length) void GuestRamUsage::collect() { - if (mCGuest->isValid(GUESTSTATS_RAMUSAGE)) + if (mCGuest->isValid(VMSTATS_GUEST_RAMUSAGE)) { mTotal->put(mCGuest->getMemTotal()); mFree->put(mCGuest->getMemFree()); @@ -1056,13 +1205,13 @@ void GuestRamUsage::collect() mShared->put(mCGuest->getMemShared()); mCache->put(mCGuest->getMemCache()); mPagedTotal->put(mCGuest->getPageTotal()); - mCGuest->invalidate(GUESTSTATS_RAMUSAGE); + mCGuest->invalidate(VMSTATS_GUEST_RAMUSAGE); } } int GuestRamUsage::enable() { - int rc = mCGuest->enable(GUESTSTATS_RAMUSAGE); + int rc = mCGuest->enable(VMSTATS_GUEST_RAMUSAGE); BaseMetric::enable(); return rc; } @@ -1070,7 +1219,7 @@ int GuestRamUsage::enable() int GuestRamUsage::disable() { BaseMetric::disable(); - return mCGuest->disable(GUESTSTATS_RAMUSAGE); + return mCGuest->disable(VMSTATS_GUEST_RAMUSAGE); } void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */) diff --git a/src/VBox/Main/src-server/PerformanceImpl.cpp b/src/VBox/Main/src-server/PerformanceImpl.cpp index b233f0a7..87ad1c4c 100644 --- a/src/VBox/Main/src-server/PerformanceImpl.cpp +++ b/src/VBox/Main/src-server/PerformanceImpl.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/ProgressProxyImpl.cpp b/src/VBox/Main/src-server/ProgressProxyImpl.cpp index a6628760..60750d6f 100644 --- a/src/VBox/Main/src-server/ProgressProxyImpl.cpp +++ b/src/VBox/Main/src-server/ProgressProxyImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/SerialPortImpl.cpp b/src/VBox/Main/src-server/SerialPortImpl.cpp index 81234c49..5bbf4ba3 100644 --- a/src/VBox/Main/src-server/SerialPortImpl.cpp +++ b/src/VBox/Main/src-server/SerialPortImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/SnapshotImpl.cpp b/src/VBox/Main/src-server/SnapshotImpl.cpp index 4740b122..411cdd56 100644 --- a/src/VBox/Main/src-server/SnapshotImpl.cpp +++ b/src/VBox/Main/src-server/SnapshotImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,6 +29,7 @@ // to remove them and put that code in shared code in MachineImplcpp #include "SharedFolderImpl.h" #include "USBControllerImpl.h" +#include "USBDeviceFiltersImpl.h" #include "VirtualBoxImpl.h" #include "AutoCaller.h" @@ -41,6 +42,7 @@ #include + //////////////////////////////////////////////////////////////////////////////// // // Snapshot private data definition @@ -113,7 +115,7 @@ HRESULT Snapshot::init(VirtualBox *aVirtualBox, { LogFlowThisFunc(("uuid=%s aParent->uuid=%s\n", aId.toString().c_str(), (aParent) ? aParent->m->uuid.toString().c_str() : "")); - ComAssertRet(!aId.isEmpty() && !aName.isEmpty() && aMachine, E_INVALIDARG); + ComAssertRet(!aId.isZero() && aId.isValid() && !aName.isEmpty() && aMachine, E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -327,7 +329,8 @@ STDMETHODIMP Snapshot::COMSETTER(Name)(IN_BSTR aName) // prohibit setting a UUID only as the machine name, or else it can // never be found by findMachine() Guid test(aName); - if (test.isNotEmpty()) + + if (!test.isZero() && test.isValid()) return setError(E_INVALIDARG, tr("A machine cannot have a UUID as its name")); AutoCaller autoCaller(this); @@ -492,6 +495,31 @@ const Utf8Str& Snapshot::getStateFilePath() const return m->pMachine->mSSData->strStateFilePath; } +/** + * Returns the depth in the snapshot tree for this snapshot. + * + * @note takes the snapshot tree lock + */ + +uint32_t Snapshot::getDepth() +{ + AutoCaller autoCaller(this); + AssertComRC(autoCaller.rc()); + + // snapshots tree is protected by machine lock + AutoReadLock alock(m->pMachine COMMA_LOCKVAL_SRC_POS); + + uint32_t cDepth = 0; + ComObjPtr pSnap(this); + while (!pSnap.isNull()) + { + pSnap = pSnap->m->pParent; + cDepth++; + } + + return cDepth; +} + /** * Returns the number of direct child snapshots, without grandchildren. * Does not recurse. @@ -788,11 +816,19 @@ HRESULT Snapshot::saveSnapshotImpl(settings::Snapshot &data, bool aAttrsOnly) it != m->llChildren.end(); ++it) { - settings::Snapshot snap; - rc = (*it)->saveSnapshotImpl(snap, aAttrsOnly); - if (FAILED(rc)) return rc; + // Use the heap to reduce the stack footprint. Each recursion needs + // over 1K, and there can be VMs with deeply nested snapshots. The + // stack can be quite small, especially with XPCOM. - data.llChildSnapshots.push_back(snap); + settings::Snapshot *snap = new settings::Snapshot(); + rc = (*it)->saveSnapshotImpl(*snap, aAttrsOnly); + if (FAILED(rc)) + { + delete snap; + return rc; + } + data.llChildSnapshots.push_back(*snap); + delete snap; } } @@ -954,7 +990,8 @@ HRESULT SnapshotMachine::init(SessionMachine *aSessionMachine, LogFlowThisFuncEnter(); LogFlowThisFunc(("mName={%s}\n", aSessionMachine->mUserData->s.strName.c_str())); - AssertReturn(aSessionMachine && !Guid(aSnapshotId).isEmpty(), E_INVALIDARG); + Guid l_guid(aSnapshotId); + AssertReturn(aSessionMachine && (!l_guid.isZero() && l_guid.isValid()), E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -1040,8 +1077,22 @@ HRESULT SnapshotMachine::init(SessionMachine *aSessionMachine, unconst(mAudioAdapter).createObject(); mAudioAdapter->initCopy(this, pMachine->mAudioAdapter); - unconst(mUSBController).createObject(); - mUSBController->initCopy(this, pMachine->mUSBController); + /* create copies of all USB controllers (mUSBControllerData + * after attaching a copy contains just references to original objects) */ + mUSBControllers.allocate(); + for (USBControllerList::const_iterator + it = aSessionMachine->mUSBControllers->begin(); + it != aSessionMachine->mUSBControllers->end(); + ++it) + { + ComObjPtr ctrl; + ctrl.createObject(); + ctrl->initCopy(this, *it); + mUSBControllers->push_back(ctrl); + } + + unconst(mUSBDeviceFilters).createObject(); + mUSBDeviceFilters->initCopy(this, pMachine->mUSBDeviceFilters); mNetworkAdapters.resize(pMachine->mNetworkAdapters.size()); for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) @@ -1095,7 +1146,8 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine, LogFlowThisFuncEnter(); LogFlowThisFunc(("mName={%s}\n", aMachine->mUserData->s.strName.c_str())); - AssertReturn(aMachine && !Guid(aSnapshotId).isEmpty(), E_INVALIDARG); + Guid l_guid(aSnapshotId); + AssertReturn(aMachine && (!l_guid.isZero() && l_guid.isValid()), E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -1122,6 +1174,7 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine, mHWData.allocate(); mMediaData.allocate(); mStorageControllers.allocate(); + mUSBControllers.allocate(); /* SSData is always unique for SnapshotMachine */ mSSData.allocate(); @@ -1138,8 +1191,8 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine, unconst(mAudioAdapter).createObject(); mAudioAdapter->init(this); - unconst(mUSBController).createObject(); - mUSBController->init(this); + unconst(mUSBDeviceFilters).createObject(); + mUSBDeviceFilters->init(this); mNetworkAdapters.resize(Global::getMaxNetworkAdapters(mHWData->mChipsetType)); for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) @@ -1381,7 +1434,7 @@ struct SessionMachine::DeleteSnapshotTask * * When the console is done, it calls SessionMachine::EndTakingSnapshot(). * - * @note Locks mParent + this object for writing. + * @note Locks mParent + this object for writing. * * @param aInitiator in: The console on which Console::TakeSnapshot was called. * @param aName in: The name for the new snapshot. @@ -1416,6 +1469,14 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator, AssertReturn(mConsoleTaskData.mLastState == MachineState_Null, E_FAIL); AssertReturn(mConsoleTaskData.mSnapshot.isNull(), E_FAIL); + if ( mData->mCurrentSnapshot + && mData->mCurrentSnapshot->getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX) + { + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"), + mUserData->s.strName.c_str()); + } + if ( !fTakingSnapshotOnline && mData->mMachineState != MachineState_Saved ) @@ -1435,8 +1496,16 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator, Utf8Str strStateFilePath; /* stateFilePath is null when the machine is not online nor saved */ if (fTakingSnapshotOnline) - // creating a new online snapshot: then we need a fresh saved state file - composeSavedStateFilename(strStateFilePath); + { + Bstr value; + HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(), + value.asOutParam()); + if (FAILED(rc) || value != "1") + { + // creating a new online snapshot: we need a fresh saved state file + composeSavedStateFilename(strStateFilePath); + } + } else if (mData->mMachineState == MachineState_Saved) // taking an online snapshot from machine in "saved" state: then use existing state file strStateFilePath = mSSData->strStateFilePath; @@ -1499,9 +1568,9 @@ STDMETHODIMP SessionMachine::BeginTakingSnapshot(IConsole *aInitiator, if (FAILED(rc)) throw rc; - // if we got this far without an error, then save the media registries - // that got modified for the diff images - mParent->saveModifiedRegistries(); + // MUST NOT save the settings or the media registry here, because + // this causes trouble with rolling back settings if the user cancels + // taking the snapshot after the diff images have been created. } catch (HRESULT hrc) { @@ -1608,11 +1677,14 @@ STDMETHODIMP SessionMachine::EndTakingSnapshot(BOOL aSuccess) /* inform callbacks */ mParent->onSnapshotTaken(mData->mUuid, mConsoleTaskData.mSnapshot->getId()); + machineLock.release(); } else { /* delete all differencing hard disks created (this will also attach * their parents back by rolling back mMediaData) */ + machineLock.release(); + rollbackMedia(); mData->mFirstSnapshot = pOldFirstSnap; // might have been changed above @@ -1624,15 +1696,19 @@ STDMETHODIMP SessionMachine::EndTakingSnapshot(BOOL aSuccess) // snapshot means that a new saved state file was created, which we must // clean up now RTFileDelete(mConsoleTaskData.mSnapshot->getStateFilePath().c_str()); + machineLock.acquire(); + mConsoleTaskData.mSnapshot->uninit(); + machineLock.release(); + } /* clear out the snapshot data */ mConsoleTaskData.mLastState = MachineState_Null; mConsoleTaskData.mSnapshot.setNull(); - machineLock.release(); + /* machineLock has been released already */ mParent->saveModifiedRegistries(); @@ -2027,7 +2103,7 @@ void SessionMachine::restoreSnapshotHandler(RestoreSnapshotTask &aTask) //////////////////////////////////////////////////////////////////////////////// /** - * Implementation for IInternalMachineControl::deleteSnapshot(). + * Implementation for IInternalMachineControl::DeleteSnapshot(). * * Gets called from Console::DeleteSnapshot(), and that's basically the * only thing Console does initially. Deleting a snapshot happens entirely on @@ -2053,7 +2129,9 @@ STDMETHODIMP SessionMachine::DeleteSnapshot(IConsole *aInitiator, Guid startId(aStartId); Guid endId(aEndId); - AssertReturn(aInitiator && !startId.isEmpty() && !endId.isEmpty(), E_INVALIDARG); + + AssertReturn(aInitiator && !startId.isZero() && !endId.isZero() && startId.isValid() && endId.isValid(), E_INVALIDARG); + AssertReturn(aMachineState && aProgress, E_POINTER); /** @todo implement the "and all children" and "range" variants */ @@ -2086,10 +2164,15 @@ STDMETHODIMP SessionMachine::DeleteSnapshot(IConsole *aInitiator, size_t childrenCount = pSnapshot->getChildrenCount(); if (childrenCount > 1) return setError(VBOX_E_INVALID_OBJECT_STATE, - tr("Snapshot '%s' of the machine '%s' cannot be deleted. because it has %d child snapshots, which is more than the one snapshot allowed for deletion"), + tr("Snapshot '%s' of the machine '%s' cannot be deleted, because it has %d child snapshots, which is more than the one snapshot allowed for deletion"), pSnapshot->getName().c_str(), mUserData->s.strName.c_str(), childrenCount); + if (pSnapshot == mData->mCurrentSnapshot && childrenCount >= 1) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("Snapshot '%s' of the machine '%s' cannot be deleted, because it is the current snapshot and has one child snapshot"), + pSnapshot->getName().c_str(), + mUserData->s.strName.c_str()); /* If the snapshot being deleted is the current one, ensure current * settings are committed and saved. @@ -2215,18 +2298,20 @@ struct MediumDeleteRec const ComObjPtr &aOnlineMediumAttachment, bool fMergeForward, const ComObjPtr &aParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, bool fNeedsOnlineMerge, - MediumLockList *aMediumLockList) + MediumLockList *aMediumLockList, + const ComPtr &aHDLockToken) : mpHD(aHd), mpSource(aSource), mpTarget(aTarget), mpOnlineMediumAttachment(aOnlineMediumAttachment), mfMergeForward(fMergeForward), mpParentForTarget(aParentForTarget), - mChildrenToReparent(aChildrenToReparent), + mpChildrenToReparent(aChildrenToReparent), mfNeedsOnlineMerge(fNeedsOnlineMerge), - mpMediumLockList(aMediumLockList) + mpMediumLockList(aMediumLockList), + mpHDLockToken(aHDLockToken) {} MediumDeleteRec(const ComObjPtr &aHd, @@ -2235,9 +2320,10 @@ struct MediumDeleteRec const ComObjPtr &aOnlineMediumAttachment, bool fMergeForward, const ComObjPtr &aParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, bool fNeedsOnlineMerge, MediumLockList *aMediumLockList, + const ComPtr &aHDLockToken, const Guid &aMachineId, const Guid &aSnapshotId) : mpHD(aHd), @@ -2246,9 +2332,10 @@ struct MediumDeleteRec mpOnlineMediumAttachment(aOnlineMediumAttachment), mfMergeForward(fMergeForward), mpParentForTarget(aParentForTarget), - mChildrenToReparent(aChildrenToReparent), + mpChildrenToReparent(aChildrenToReparent), mfNeedsOnlineMerge(fNeedsOnlineMerge), mpMediumLockList(aMediumLockList), + mpHDLockToken(aHDLockToken), mMachineId(aMachineId), mSnapshotId(aSnapshotId) {} @@ -2259,9 +2346,11 @@ struct MediumDeleteRec ComObjPtr mpOnlineMediumAttachment; bool mfMergeForward; ComObjPtr mpParentForTarget; - MediaList mChildrenToReparent; + MediumLockList *mpChildrenToReparent; bool mfNeedsOnlineMerge; MediumLockList *mpMediumLockList; + /** optional lock token, used only in case mpHD is not merged/deleted */ + ComPtr mpHDLockToken; /* these are for reattaching the hard disk in case of a failure: */ Guid mMachineId; Guid mSnapshotId; @@ -2371,11 +2460,12 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) ComObjPtr pSource; bool fMergeForward = false; ComObjPtr pParentForTarget; - MediaList childrenToReparent; + MediumLockList *pChildrenToReparent = NULL; bool fNeedsOnlineMerge = false; bool fOnlineMergePossible = aTask.m_fDeleteOnline; MediumLockList *pMediumLockList = NULL; MediumLockList *pVMMALockList = NULL; + ComPtr pHDLockToken; ComObjPtr pOnlineMediumAttachment; if (fOnlineMergePossible) { @@ -2408,9 +2498,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) fOnlineMergePossible, pVMMALockList, pSource, pTarget, fMergeForward, pParentForTarget, - childrenToReparent, + pChildrenToReparent, fNeedsOnlineMerge, - pMediumLockList); + pMediumLockList, + pHDLockToken); treeLock.acquire(); if (FAILED(rc)) throw rc; @@ -2433,7 +2524,6 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) // then do a backward merge, i.e. merge its only child onto the // base disk. Here we need then to update the attachment that // refers to the child and have it point to the parent instead - Assert(pHD->getParent().isNull()); Assert(pHD->getChildren().size() == 1); ComObjPtr pReplaceHD = pHD->getChildren().front(); @@ -2454,7 +2544,7 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) if (pSnapshotId) replaceSnapshotId = *pSnapshotId; - if (!replaceMachineId.isEmpty()) + if (replaceMachineId.isValid() && !replaceMachineId.isZero()) { // Adjust the backreferences, otherwise merging will assert. // Note that the medium attachment object stays associated @@ -2467,9 +2557,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) pOnlineMediumAttachment, fMergeForward, pParentForTarget, - childrenToReparent, + pChildrenToReparent, fNeedsOnlineMerge, pMediumLockList, + pHDLockToken, replaceMachineId, replaceSnapshotId)); } @@ -2478,9 +2569,116 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) pOnlineMediumAttachment, fMergeForward, pParentForTarget, - childrenToReparent, + pChildrenToReparent, fNeedsOnlineMerge, - pMediumLockList)); + pMediumLockList, + pHDLockToken)); + } + + { + /*check available place on the storage*/ + RTFOFF pcbTotal = 0; + RTFOFF pcbFree = 0; + uint32_t pcbBlock = 0; + uint32_t pcbSector = 0; + std::multimap neededStorageFreeSpace; + std::map serialMapToStoragePath; + + MediumDeleteRecList::const_iterator it_md = toDelete.begin(); + + while (it_md != toDelete.end()) + { + uint64_t diskSize = 0; + uint32_t pu32Serial = 0; + ComObjPtr pSource_local = it_md->mpSource; + ComObjPtr pTarget_local = it_md->mpTarget; + ComPtr pTargetFormat; + + { + if ( pSource_local.isNull() + || pSource_local == pTarget_local) + { + ++it_md; + continue; + } + } + + rc = pTarget_local->COMGETTER(MediumFormat)(pTargetFormat.asOutParam()); + if (FAILED(rc)) + throw rc; + + if(pTarget_local->isMediumFormatFile()) + { + int vrc = RTFsQuerySerial(pTarget_local->getLocationFull().c_str(), &pu32Serial); + if (RT_FAILURE(vrc)) + { + rc = setError(E_FAIL, + tr(" Unable to merge storage '%s'. Can't get storage UID "), + pTarget_local->getLocationFull().c_str()); + throw rc; + } + + pSource_local->COMGETTER(Size)((LONG64*)&diskSize); + + /* store needed free space in multimap */ + neededStorageFreeSpace.insert(std::make_pair(pu32Serial,diskSize)); + /* linking storage UID with snapshot path, it is a helper container (just for easy finding needed path) */ + serialMapToStoragePath.insert(std::make_pair(pu32Serial,pTarget_local->getLocationFull().c_str())); + } + + ++it_md; + } + + while (!neededStorageFreeSpace.empty()) + { + std::pair::iterator,std::multimap::iterator> ret; + uint64_t commonSourceStoragesSize = 0; + + /* find all records in multimap with identical storage UID*/ + ret = neededStorageFreeSpace.equal_range(neededStorageFreeSpace.begin()->first); + std::multimap::const_iterator it_ns = ret.first; + + for (; it_ns != ret.second ; ++it_ns) + { + commonSourceStoragesSize += it_ns->second; + } + + /* find appropriate path by storage UID*/ + std::map::const_iterator it_sm = serialMapToStoragePath.find(ret.first->first); + /* get info about a storage */ + if (it_sm == serialMapToStoragePath.end()) + { + LogFlowThisFunc((" Path to the storage wasn't found...\n ")); + + rc = setError(E_INVALIDARG, + tr(" Unable to merge storage '%s'. Path to the storage wasn't found. "), + it_sm->second); + throw rc; + } + + int vrc = RTFsQuerySizes(it_sm->second, &pcbTotal, &pcbFree,&pcbBlock, &pcbSector); + if (RT_FAILURE(vrc)) + { + rc = setError(E_FAIL, + tr(" Unable to merge storage '%s'. Can't get the storage size. "), + it_sm->second); + throw rc; + } + + if (commonSourceStoragesSize > (uint64_t)pcbFree) + { + LogFlowThisFunc((" Not enough free space to merge...\n ")); + + rc = setError(E_OUTOFMEMORY, + tr(" Unable to merge storage '%s' - not enough free storage space. "), + it_sm->second); + throw rc; + } + + neededStorageFreeSpace.erase(ret.first, ret.second); + } + + serialMapToStoragePath.clear(); } // we can release the locks now since the machine state is MachineState_DeletingSnapshot @@ -2572,16 +2770,22 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) bool fNeedsSave = false; if (it->mfNeedsOnlineMerge) { + // Put the medium merge information (MediumDeleteRec) where + // SessionMachine::FinishOnlineMergeMedium can get at it. + // This callback will arrive while onlineMergeMedium is + // still executing, and there can't be two tasks. + mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it); // online medium merge, in the direction decided earlier rc = onlineMergeMedium(it->mpOnlineMediumAttachment, it->mpSource, it->mpTarget, it->mfMergeForward, it->mpParentForTarget, - it->mChildrenToReparent, + it->mpChildrenToReparent, it->mpMediumLockList, aTask.pProgress, &fNeedsSave); + mConsoleTaskData.mDeleteSnapshotInfo = NULL; } else { @@ -2589,7 +2793,7 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) rc = it->mpSource->mergeTo(it->mpTarget, it->mfMergeForward, it->mpParentForTarget, - it->mChildrenToReparent, + it->mpChildrenToReparent, it->mpMediumLockList, &aTask.pProgress, true /* aWait */); @@ -2708,7 +2912,9 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) mParent->markRegistryModified(getId()); } } - catch (HRESULT aRC) { rc = aRC; } + catch (HRESULT aRC) { + rc = aRC; + } if (FAILED(rc)) { @@ -2726,10 +2932,10 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) ++it) { cancelDeleteSnapshotMedium(it->mpHD, it->mpSource, - it->mChildrenToReparent, + it->mpChildrenToReparent, it->mfNeedsOnlineMerge, - it->mpMediumLockList, it->mMachineId, - it->mSnapshotId); + it->mpMediumLockList, it->mpHDLockToken, + it->mMachineId, it->mSnapshotId); } } @@ -2780,14 +2986,16 @@ void SessionMachine::deleteSnapshotHandler(DeleteSnapshotTask &aTask) * @param aTarget Target hard disk for merge (out). * @param aMergeForward Merge direction decision (out). * @param aParentForTarget New parent if target needs to be reparented (out). - * @param aChildrenToReparent Children which have to be reparented to the - * target (out). + * @param aChildrenToReparent MediumLockList with children which have to be + * reparented to the target (out). * @param fNeedsOnlineMerge Whether this merge needs to be done online (out). * If this is set to @a true then the @a aVMMALockList * parameter has been modified and is returned as * @a aMediumLockList. * @param aMediumLockList Where to store the created medium lock list (may * return NULL if no real merge is necessary). + * @param aHDLockToken Where to store the write lock token for aHD, in case + * it is not merged or deleted (out). * * @note Caller must hold media tree lock for writing. This locks this object * and every medium object on the merge chain for writing. @@ -2801,9 +3009,10 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD ComObjPtr &aTarget, bool &aMergeForward, ComObjPtr &aParentForTarget, - MediaList &aChildrenToReparent, + MediumLockList * &aChildrenToReparent, bool &fNeedsOnlineMerge, - MediumLockList * &aMediumLockList) + MediumLockList * &aMediumLockList, + ComPtr &aHDLockToken) { Assert(!mParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread()); Assert(!fOnlineMergePossible || VALID_PTR(aVMMALockList)); @@ -2816,6 +3025,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD && type != MediumType_Shareable && type != MediumType_Readonly, E_FAIL); + aChildrenToReparent = NULL; aMediumLockList = NULL; fNeedsOnlineMerge = false; @@ -2832,7 +3042,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD /* lock only, to prevent any usage until the snapshot deletion * is completed */ alock.release(); - return aHD->LockWrite(NULL); + return aHD->LockWrite(aHDLockToken.asOutParam()); } /* the differencing hard disk w/o children will be deleted, protect it @@ -2863,7 +3073,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD * deletion, so lock only, to prevent any usage */ childLock.release(); alock.release(); - return aHD->LockWrite(NULL); + return aHD->LockWrite(aHDLockToken.asOutParam()); } aSource = pChild; @@ -2871,9 +3081,30 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD } else { - /* forward merge */ - aSource = aHD; - aTarget = pChild; + /* Determine best merge direction. */ + bool fMergeForward = true; + + childLock.release(); + alock.release(); + HRESULT rc = aHD->queryPreferredMergeDirection(pChild, fMergeForward); + alock.acquire(); + childLock.acquire(); + + if (FAILED(rc) && rc != E_FAIL) + return rc; + + if (fMergeForward) + { + aSource = aHD; + aTarget = pChild; + LogFlowFunc(("Forward merging selected\n")); + } + else + { + aSource = pChild; + aTarget = aHD; + LogFlowFunc(("Backward merging selected\n")); + } } HRESULT rc; @@ -2939,39 +3170,37 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD if (fOnlineMergePossible) { /* we will lock the children of the source for reparenting */ - for (MediaList::const_iterator it = aChildrenToReparent.begin(); - it != aChildrenToReparent.end(); - ++it) + if (aChildrenToReparent && !aChildrenToReparent->IsEmpty()) { - ComObjPtr pMedium = *it; - AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS); - if (pMedium->getState() == MediumState_Created) - { - mediumLock.release(); - childLock.release(); - alock.release(); - rc = pMedium->LockWrite(NULL); - alock.acquire(); - childLock.acquire(); - mediumLock.acquire(); - if (FAILED(rc)) - throw rc; - } - else + /* Cannot just call aChildrenToReparent->Lock(), as one of + * the children is the one under which the current state of + * the VM is located, and this means it is already locked + * (for reading). Note that no special unlocking is needed, + * because cancelMergeTo will unlock everything locked in + * its context (using the unlock on destruction), and both + * cancelDeleteSnapshotMedium (in case something fails) and + * FinishOnlineMergeMedium re-define the read/write lock + * state of everything which the VM need, search for the + * UpdateLock method calls. */ + childLock.release(); + alock.release(); + rc = aChildrenToReparent->Lock(true /* fSkipOverLockedMedia */); + alock.acquire(); + childLock.acquire(); + MediumLockList::Base::iterator childrenToReparentBegin = aChildrenToReparent->GetBegin(); + MediumLockList::Base::iterator childrenToReparentEnd = aChildrenToReparent->GetEnd(); + for (MediumLockList::Base::iterator it = childrenToReparentBegin; + it != childrenToReparentEnd; + ++it) { - mediumLock.release(); - childLock.release(); - alock.release(); - rc = aVMMALockList->Update(pMedium, true); - alock.acquire(); - childLock.acquire(); - mediumLock.acquire(); - if (FAILED(rc)) + ComObjPtr pMedium = it->GetMedium(); + AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS); + if (!it->IsLocked()) { mediumLock.release(); childLock.release(); alock.release(); - rc = pMedium->LockWrite(NULL); + rc = aVMMALockList->Update(pMedium, true); alock.acquire(); childLock.acquire(); mediumLock.acquire(); @@ -3058,6 +3287,7 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD * @param aChildrenToReparent Children to unlock. * @param fNeedsOnlineMerge Whether this merge needs to be done online. * @param aMediumLockList Medium locks to cancel. + * @param aHDLockToken Optional write lock token for aHD. * @param aMachineId Machine id to attach the medium to. * @param aSnapshotId Snapshot id to attach the medium to. * @@ -3065,9 +3295,10 @@ HRESULT SessionMachine::prepareDeleteSnapshotMedium(const ComObjPtr &aHD */ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr &aHD, const ComObjPtr &aSource, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, bool fNeedsOnlineMerge, MediumLockList *aMediumLockList, + const ComPtr &aHDLockToken, const Guid &aMachineId, const Guid &aSnapshotId) { @@ -3079,8 +3310,12 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr &aHD, if (aHD->getParent().isNull()) { - HRESULT rc = aHD->UnlockWrite(NULL); - AssertComRC(rc); + Assert(!aHDLockToken.isNull()); + if (!aHDLockToken.isNull()) + { + HRESULT rc = aHDLockToken->Abandon(); + AssertComRC(rc); + } } else { @@ -3128,7 +3363,7 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr &aHD, } } - if (!aMachineId.isEmpty()) + if (aMachineId.isValid() && !aMachineId.isZero()) { // reattach the source media to the snapshot HRESULT rc = aSource->addBackReference(aMachineId, aSnapshotId); @@ -3147,8 +3382,8 @@ void SessionMachine::cancelDeleteSnapshotMedium(const ComObjPtr &aHD, * @param aTarget Target hard disk for merge. * @param aMergeForward Merge direction. * @param aParentForTarget New parent if target needs to be reparented. - * @param aChildrenToReparent Children which have to be reparented to the - * target. + * @param aChildrenToReparent Medium lock list with children which have to be + * reparented to the target. * @param aMediumLockList Where to store the created medium lock list (may * return NULL if no real merge is necessary). * @param aProgress Progress indicator. @@ -3159,7 +3394,7 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe const ComObjPtr &aTarget, bool fMergeForward, const ComObjPtr &aParentForTarget, - const MediaList &aChildrenToReparent, + MediumLockList *aChildrenToReparent, MediumLockList *aMediumLockList, ComObjPtr &aProgress, bool *pfNeedsMachineSaveSettings) @@ -3168,6 +3403,9 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe AssertReturn(aTarget != NULL, E_FAIL); AssertReturn(aSource != aTarget, E_FAIL); AssertReturn(aMediumLockList != NULL, E_FAIL); + NOREF(fMergeForward); + NOREF(aParentForTarget); + NOREF(aChildrenToReparent); HRESULT rc = S_OK; @@ -3208,12 +3446,6 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe ComAssertThrow( uSourceIdx != (unsigned)-1 && uTargetIdx != (unsigned)-1, E_FAIL); - // For forward merges, tell the VM what images need to have their - // parent UUID updated. This cannot be done in VBoxSVC, as opening - // the required parent images is not safe while the VM is running. - // For backward merges this will be simply an array of size 0. - com::SafeIfaceArray childrenToReparent(aChildrenToReparent); - ComPtr directControl; { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -3229,9 +3461,6 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe // updating the medium attachment, chain linking and state. rc = directControl->OnlineMergeMedium(aMediumAttachment, uSourceIdx, uTargetIdx, - aSource, aTarget, - fMergeForward, aParentForTarget, - ComSafeArrayAsInParam(childrenToReparent), aProgress); if (FAILED(rc)) throw rc; @@ -3247,7 +3476,7 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe } /** - * Implementation for IInternalMachineControl::finishOnlineMergeMedium(). + * Implementation for IInternalMachineControl::FinishOnlineMergeMedium(). * * Gets called after the successful completion of an online merge from * Console::onlineMergeMedium(), which gets invoked indirectly above in @@ -3256,17 +3485,11 @@ HRESULT SessionMachine::onlineMergeMedium(const ComObjPtr &aMe * This updates the medium information and medium state so that the VM * can continue with the updated state of the medium chain. */ -STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumAttachment, - IMedium *aSource, - IMedium *aTarget, - BOOL aMergeForward, - IMedium *aParentForTarget, - ComSafeArrayIn(IMedium *, aChildrenToReparent)) +STDMETHODIMP SessionMachine::FinishOnlineMergeMedium() { HRESULT rc = S_OK; - ComObjPtr pSource(static_cast(aSource)); - ComObjPtr pTarget(static_cast(aTarget)); - ComObjPtr pParentForTarget(static_cast(aParentForTarget)); + MediumDeleteRec *pDeleteRec = (MediumDeleteRec *)mConsoleTaskData.mDeleteSnapshotInfo; + AssertReturn(pDeleteRec, E_FAIL); bool fSourceHasChildren = false; // all hard disks but the target were successfully deleted by @@ -3279,36 +3502,35 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA // we delete the last reference to the no longer existing medium object. ComObjPtr targetChild; - if (aMergeForward) + if (pDeleteRec->mfMergeForward) { // first, unregister the target since it may become a base // hard disk which needs re-registration - rc = mParent->unregisterMedium(pTarget); + rc = mParent->unregisterMedium(pDeleteRec->mpTarget); AssertComRC(rc); // then, reparent it and disconnect the deleted branch at // both ends (chain->parent() is source's parent) - pTarget->deparent(); - pTarget->setParent(pParentForTarget); - if (pParentForTarget) - pSource->deparent(); + pDeleteRec->mpTarget->deparent(); + pDeleteRec->mpTarget->setParent(pDeleteRec->mpParentForTarget); + if (pDeleteRec->mpParentForTarget) + pDeleteRec->mpSource->deparent(); // then, register again - rc = mParent->registerMedium(pTarget, &pTarget, DeviceType_HardDisk); + rc = mParent->registerMedium(pDeleteRec->mpTarget, &pDeleteRec->mpTarget, DeviceType_HardDisk); AssertComRC(rc); } else { - Assert(pTarget->getChildren().size() == 1); - targetChild = pTarget->getChildren().front(); + Assert(pDeleteRec->mpTarget->getChildren().size() == 1); + targetChild = pDeleteRec->mpTarget->getChildren().front(); // disconnect the deleted branch at the elder end targetChild->deparent(); // Update parent UUIDs of the source's children, reparent them and // disconnect the deleted branch at the younger end - com::SafeIfaceArray childrenToReparent(ComSafeArrayInArg(aChildrenToReparent)); - if (childrenToReparent.size() > 0) + if (pDeleteRec->mpChildrenToReparent && !pDeleteRec->mpChildrenToReparent->IsEmpty()) { fSourceHasChildren = true; // Fix the parent UUID of the images which needs to be moved to @@ -3316,35 +3538,35 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA // but only for reading since the VM is paused. If anything fails // we must continue. The worst possible result is that the images // need manual fixing via VBoxManage to adjust the parent UUID. - MediaList toReparent; - for (size_t i = 0; i < childrenToReparent.size(); i++) - { - Medium *pMedium = static_cast(childrenToReparent[i]); - toReparent.push_back(pMedium); - } treeLock.release(); - pTarget->fixParentUuidOfChildren(toReparent); + pDeleteRec->mpTarget->fixParentUuidOfChildren(pDeleteRec->mpChildrenToReparent); + // The childen are still write locked, unlock them now and don't + // rely on the destructor doing it very late. + pDeleteRec->mpChildrenToReparent->Unlock(); treeLock.acquire(); // obey {parent,child} lock order - AutoWriteLock sourceLock(pSource COMMA_LOCKVAL_SRC_POS); + AutoWriteLock sourceLock(pDeleteRec->mpSource COMMA_LOCKVAL_SRC_POS); - for (size_t i = 0; i < childrenToReparent.size(); i++) + MediumLockList::Base::iterator childrenBegin = pDeleteRec->mpChildrenToReparent->GetBegin(); + MediumLockList::Base::iterator childrenEnd = pDeleteRec->mpChildrenToReparent->GetEnd(); + for (MediumLockList::Base::iterator it = childrenBegin; + it != childrenEnd; + ++it) { - Medium *pMedium = static_cast(childrenToReparent[i]); + Medium *pMedium = it->GetMedium(); AutoWriteLock childLock(pMedium COMMA_LOCKVAL_SRC_POS); pMedium->deparent(); // removes pMedium from source - pMedium->setParent(pTarget); + pMedium->setParent(pDeleteRec->mpTarget); } } } /* unregister and uninitialize all hard disks removed by the merge */ MediumLockList *pMediumLockList = NULL; - MediumAttachment *pMediumAttachment = static_cast(aMediumAttachment); - rc = mData->mSession.mLockedMedia.Get(pMediumAttachment, pMediumLockList); - const ComObjPtr &pLast = aMergeForward ? pTarget : pSource; + rc = mData->mSession.mLockedMedia.Get(pDeleteRec->mpOnlineMediumAttachment, pMediumLockList); + const ComObjPtr &pLast = pDeleteRec->mfMergeForward ? pDeleteRec->mpTarget : pDeleteRec->mpSource; AssertReturn(SUCCEEDED(rc) && pMediumLockList, E_FAIL); MediumLockList::Base::iterator lockListBegin = pMediumLockList->GetBegin(); @@ -3360,7 +3582,7 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA const ComObjPtr pMedium = mediumLock.GetMedium(); /* The target and all images not merged (readonly) are skipped */ - if ( pMedium == pTarget + if ( pMedium == pDeleteRec->mpTarget || pMedium->getState() == MediumState_LockedRead) { ++it; @@ -3382,10 +3604,10 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA * caller may still hold an AutoCaller instance for it * and therefore we cannot uninit() it (it's therefore * the caller's responsibility) */ - if (pMedium == aSource) + if (pMedium == pDeleteRec->mpSource) { - Assert(pSource->getChildren().size() == 0); - Assert(pSource->getFirstMachineBackrefId() == NULL); + Assert(pDeleteRec->mpSource->getChildren().size() == 0); + Assert(pDeleteRec->mpSource->getFirstMachineBackrefId() == NULL); } /* Delete the medium lock list entry, which also releases the @@ -3421,11 +3643,12 @@ STDMETHODIMP SessionMachine::FinishOnlineMergeMedium(IMediumAttachment *aMediumA * source has no children) then update the medium associated with the * attachment, as the previously associated one (source) is now deleted. * Without the immediate update the VM could not continue running. */ - if (!aMergeForward && !fSourceHasChildren) + if (!pDeleteRec->mfMergeForward && !fSourceHasChildren) { - AutoWriteLock attLock(pMediumAttachment COMMA_LOCKVAL_SRC_POS); - pMediumAttachment->updateMedium(pTarget); + AutoWriteLock attLock(pDeleteRec->mpOnlineMediumAttachment COMMA_LOCKVAL_SRC_POS); + pDeleteRec->mpOnlineMediumAttachment->updateMedium(pDeleteRec->mpTarget); } return S_OK; } + diff --git a/src/VBox/Main/src-server/StorageControllerImpl.cpp b/src/VBox/Main/src-server/StorageControllerImpl.cpp index 100c5b22..b5686933 100644 --- a/src/VBox/Main/src-server/StorageControllerImpl.cpp +++ b/src/VBox/Main/src-server/StorageControllerImpl.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/SystemPropertiesImpl.cpp b/src/VBox/Main/src-server/SystemPropertiesImpl.cpp index 380f7574..3e0ff614 100644 --- a/src/VBox/Main/src-server/SystemPropertiesImpl.cpp +++ b/src/VBox/Main/src-server/SystemPropertiesImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -90,6 +90,7 @@ HRESULT SystemProperties::init(VirtualBox *aParent) unconst(mParent) = aParent; setDefaultMachineFolder(Utf8Str::Empty); + setLoggingLevel(Utf8Str::Empty); setDefaultHardDiskFormat(Utf8Str::Empty); setVRDEAuthLibrary(Utf8Str::Empty); @@ -97,6 +98,18 @@ HRESULT SystemProperties::init(VirtualBox *aParent) m->ulLogHistoryCount = 3; + + /* On Windows and OS X, HW virtualization use isn't exclusive by + * default so that VT-x or AMD-V can be shared with other + * hypervisors without requiring user intervention. + * NB: See also SystemProperties constructor in settings.h + */ +#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) + m->fExclusiveHwVirt = false; +#else + m->fExclusiveHwVirt = true; +#endif + HRESULT rc = S_OK; /* Fetch info of all available hd backends. */ @@ -313,6 +326,36 @@ STDMETHODIMP SystemProperties::COMGETTER(MaxBootPosition)(ULONG *aMaxBootPositio } +STDMETHODIMP SystemProperties::COMGETTER(ExclusiveHwVirt)(BOOL *aExclusiveHwVirt) +{ + CheckComArgOutPointerValid(aExclusiveHwVirt); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aExclusiveHwVirt = m->fExclusiveHwVirt; + + return S_OK; +} + +STDMETHODIMP SystemProperties::COMSETTER(ExclusiveHwVirt)(BOOL aExclusiveHwVirt) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + m->fExclusiveHwVirt = !!aExclusiveHwVirt; + alock.release(); + + // VirtualBox::saveSettings() needs vbox write lock + AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS); + HRESULT rc = mParent->saveSettings(); + + return rc; +} + STDMETHODIMP SystemProperties::GetMaxNetworkAdapters(ChipsetType_T aChipset, ULONG *count) { CheckComArgOutPointerValid(count); @@ -346,6 +389,7 @@ STDMETHODIMP SystemProperties::GetMaxNetworkAdaptersOfType(ChipsetType_T aChipse { case NetworkAttachmentType_NAT: case NetworkAttachmentType_Internal: + case NetworkAttachmentType_NATNetwork: /* chipset default is OK */ break; case NetworkAttachmentType_Bridged: @@ -531,6 +575,8 @@ STDMETHODIMP SystemProperties::GetDeviceTypesForStorageBus(StorageBus_T aBus, { case StorageBus_IDE: case StorageBus_SATA: + case StorageBus_SCSI: + case StorageBus_SAS: { com::SafeArray saDeviceTypes(2); saDeviceTypes[0] = DeviceType_DVD; @@ -538,14 +584,6 @@ STDMETHODIMP SystemProperties::GetDeviceTypesForStorageBus(StorageBus_T aBus, saDeviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes)); break; } - case StorageBus_SCSI: - case StorageBus_SAS: - { - com::SafeArray saDeviceTypes(1); - saDeviceTypes[0] = DeviceType_HardDisk; - saDeviceTypes.detachTo(ComSafeArrayOutArg(aDeviceTypes)); - break; - } case StorageBus_Floppy: { com::SafeArray saDeviceTypes(1); @@ -588,6 +626,36 @@ STDMETHODIMP SystemProperties::GetDefaultIoCacheSettingForStorageController(Stor return S_OK; } +STDMETHODIMP SystemProperties::GetMaxInstancesOfUSBControllerType(ChipsetType_T aChipset, + USBControllerType_T aType, + ULONG *aMaxInstances) +{ + NOREF(aChipset); + CheckComArgOutPointerValid(aMaxInstances); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + ULONG cCtrs = 0; + + /* no need to lock, this is const */ + switch (aType) + { + case USBControllerType_OHCI: + case USBControllerType_EHCI: + { + cCtrs = 1; + break; + } + default: + AssertMsgFailed(("Invalid bus type %d\n", aType)); + } + + *aMaxInstances = cCtrs; + + return S_OK; +} + STDMETHODIMP SystemProperties::COMGETTER(DefaultMachineFolder)(BSTR *aDefaultMachineFolder) { CheckComArgOutPointerValid(aDefaultMachineFolder); @@ -621,6 +689,44 @@ STDMETHODIMP SystemProperties::COMSETTER(DefaultMachineFolder)(IN_BSTR aDefaultM return rc; } +STDMETHODIMP SystemProperties::COMGETTER(LoggingLevel)(BSTR *aLoggingLevel) +{ + CheckComArgOutPointerValid(aLoggingLevel); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + Utf8Str useLoggingLevel(m->strLoggingLevel); + if (useLoggingLevel.isEmpty()) + useLoggingLevel = VBOXSVC_LOG_DEFAULT; + + useLoggingLevel.cloneTo(aLoggingLevel); + return S_OK; +} + + +STDMETHODIMP SystemProperties::COMSETTER(LoggingLevel)(IN_BSTR aLoggingLevel) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + HRESULT rc = setLoggingLevel(aLoggingLevel); + alock.release(); + + if (SUCCEEDED(rc)) + { + AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS); + rc = mParent->saveSettings(); + } + else + LogRel(("Cannot set passed logging level=%ls, or the default one - Error=%Rhrc \n", aLoggingLevel, rc)); + + return rc; +} + STDMETHODIMP SystemProperties::COMGETTER(MediumFormats)(ComSafeArrayOut(IMediumFormat *, aMediumFormats)) { CheckComArgOutSafeArrayPointerValid(aMediumFormats); @@ -997,6 +1103,40 @@ STDMETHODIMP SystemProperties::COMSETTER(DefaultAdditionsISO)(IN_BSTR aDefaultAd return rc; } +STDMETHODIMP SystemProperties::COMGETTER(DefaultFrontend)(BSTR *aDefaultFrontend) +{ + CheckComArgOutPointerValid(aDefaultFrontend); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + m->strDefaultFrontend.cloneTo(aDefaultFrontend); + + return S_OK; +} + +STDMETHODIMP SystemProperties::COMSETTER(DefaultFrontend)(IN_BSTR aDefaultFrontend) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->strDefaultFrontend == Utf8Str(aDefaultFrontend)) + return S_OK; + HRESULT rc = setDefaultFrontend(aDefaultFrontend); + alock.release(); + + if (SUCCEEDED(rc)) + { + // VirtualBox::saveSettings() needs vbox write lock + AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS); + rc = mParent->saveSettings(); + } + + return rc; +} + // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// @@ -1012,6 +1152,9 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data) rc = setDefaultMachineFolder(data.strDefaultMachineFolder); if (FAILED(rc)) return rc; + rc = setLoggingLevel(data.strLoggingLevel); + if (FAILED(rc)) return rc; + rc = setDefaultHardDiskFormat(data.strDefaultHardDiskFormat); if (FAILED(rc)) return rc; @@ -1025,6 +1168,7 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data) if (FAILED(rc)) return rc; m->ulLogHistoryCount = data.ulLogHistoryCount; + m->fExclusiveHwVirt = data.fExclusiveHwVirt; rc = setAutostartDatabasePath(data.strAutostartDatabasePath); if (FAILED(rc)) return rc; @@ -1036,6 +1180,9 @@ HRESULT SystemProperties::loadSettings(const settings::SystemProperties &data) (void)setDefaultAdditionsISO(data.strDefaultAdditionsISO); } + rc = setDefaultFrontend(data.strDefaultFrontend); + if (FAILED(rc)) return rc; + return S_OK; } @@ -1074,7 +1221,7 @@ ComObjPtr SystemProperties::mediumFormat(const Utf8Str &aFormat) { /* MediumFormat is all const, no need to lock */ - if ((*it)->getId().compare(aFormat, Utf8Str::CaseInsensitive) == 0) + if ((*it)->i_getId().compare(aFormat, Utf8Str::CaseInsensitive) == 0) { format = *it; break; @@ -1107,8 +1254,8 @@ ComObjPtr SystemProperties::mediumFormatFromExtension(const Utf8St ++it) { /* MediumFormat is all const, no need to lock */ - MediumFormat::StrList aFileList = (*it)->getFileExtensions(); - for (MediumFormat::StrList::const_iterator it1 = aFileList.begin(); + MediumFormat::StrArray aFileList = (*it)->i_getFileExtensions(); + for (MediumFormat::StrArray::const_iterator it1 = aFileList.begin(); it1 != aFileList.end(); ++it1) { @@ -1177,6 +1324,31 @@ HRESULT SystemProperties::setDefaultMachineFolder(const Utf8Str &strPath) return S_OK; } +HRESULT SystemProperties::setLoggingLevel(const Utf8Str &aLoggingLevel) +{ + Utf8Str useLoggingLevel(aLoggingLevel); + int rc = RTLogGroupSettings(RTLogRelDefaultInstance(), useLoggingLevel.c_str()); + // If failed and not the default logging level - try to use the default logging level. + if (RT_FAILURE(rc)) + { + // If failed write message to the release log. + LogRel(("Cannot set passed logging level=%s Error=%Rrc \n", useLoggingLevel.c_str(), rc)); + // If attempted logging level not the default one then try the default one. + if (!useLoggingLevel.equals(VBOXSVC_LOG_DEFAULT)) + { + rc = RTLogGroupSettings(RTLogRelDefaultInstance(), VBOXSVC_LOG_DEFAULT); + // If failed report this to the release log. + if (RT_FAILURE(rc)) + LogRel(("Cannot set default logging level Error=%Rrc \n", rc)); + } + // On any failure - set default level as the one to be stored. + useLoggingLevel = VBOXSVC_LOG_DEFAULT; + } + // Set to passed value or if default used/attempted (even if error condition) use empty string. + m->strLoggingLevel = (useLoggingLevel.equals(VBOXSVC_LOG_DEFAULT) ? "" : useLoggingLevel); + return RT_SUCCESS(rc) ? S_OK : E_FAIL; +} + HRESULT SystemProperties::setDefaultHardDiskFormat(const Utf8Str &aFormat) { if (!aFormat.isEmpty()) @@ -1288,3 +1460,10 @@ HRESULT SystemProperties::setDefaultAdditionsISO(const Utf8Str &aPath) return S_OK; } + +HRESULT SystemProperties::setDefaultFrontend(const Utf8Str &aDefaultFrontend) +{ + m->strDefaultFrontend = aDefaultFrontend; + + return S_OK; +} diff --git a/src/VBox/Main/src-server/TokenImpl.cpp b/src/VBox/Main/src-server/TokenImpl.cpp new file mode 100644 index 00000000..29802e7b --- /dev/null +++ b/src/VBox/Main/src-server/TokenImpl.cpp @@ -0,0 +1,217 @@ +/* $Id: TokenImpl.cpp $ */ +/** @file + * + * Token COM class implementation: MachineToken and MediumLockToken + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "TokenImpl.h" +#include "MachineImpl.h" +#include "MediumImpl.h" +#include "AutoCaller.h" +#include "Logging.h" + +// constructor / destructor +///////////////////////////////////////////////////////////////////////////// + +DEFINE_EMPTY_CTOR_DTOR(MachineToken) + +HRESULT MachineToken::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void MachineToken::FinalRelease() +{ + uninit(false); + + BaseFinalRelease(); +} + +// public initializer/uninitializer for internal purposes only +///////////////////////////////////////////////////////////////////////////// + +/** + * Initializes the token object. + * + * @param pSessionMachine Pointer to a SessionMachine object. + */ +HRESULT MachineToken::init(const ComObjPtr &pSessionMachine) +{ + LogFlowThisFunc(("pSessionMachine=%p\n", &pSessionMachine)); + + ComAssertRet(!pSessionMachine.isNull(), E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m.pSessionMachine = pSessionMachine; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + +/** + * Uninitializes the instance and sets the ready flag to FALSE. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void MachineToken::uninit(bool fAbandon) +{ + LogFlowThisFunc(("\n")); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + + /* Destroy the SessionMachine object, check is paranoia */ + if (!m.pSessionMachine.isNull()) + { + m.pSessionMachine->uninit(fAbandon ? SessionMachine::Uninit::Normal : SessionMachine::Uninit::Abnormal); + m.pSessionMachine.setNull(); + } +} + +// IToken methods +///////////////////////////////////////////////////////////////////////////// + +HRESULT MachineToken::abandon(AutoCaller &aAutoCaller) +{ + /* have to release the AutoCaller before calling uninit(), self-deadlock */ + aAutoCaller.release(); + + /* uninit does everything we need */ + uninit(true); + return S_OK; +} + +HRESULT MachineToken::dummy() +{ + /* Remember, the wrapper contains the AutoCaller, which means that after + * uninit() this code won't be reached any more. */ + + /* this is a NOOP, no need to lock */ + + return S_OK; +} + +// public methods only for internal purposes +///////////////////////////////////////////////////////////////////////////// + + +// constructor / destructor +///////////////////////////////////////////////////////////////////////////// + +DEFINE_EMPTY_CTOR_DTOR(MediumLockToken) + +HRESULT MediumLockToken::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void MediumLockToken::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + +// public initializer/uninitializer for internal purposes only +///////////////////////////////////////////////////////////////////////////// + +/** + * Initializes the token object. + * + * @param pMedium Pointer to a Medium object. + * @param fWrite True if this is a write lock, false otherwise. + */ +HRESULT MediumLockToken::init(const ComObjPtr &pMedium, bool fWrite) +{ + LogFlowThisFunc(("pMedium=%p\n", &pMedium)); + + ComAssertRet(!pMedium.isNull(), E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m.pMedium = pMedium; + m.fWrite = fWrite; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + +/** + * Uninitializes the instance and sets the ready flag to FALSE. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void MediumLockToken::uninit() +{ + LogFlowThisFunc(("\n")); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + + /* Release the appropriate lock, check is paranoia */ + if (!m.pMedium.isNull()) + { + if (m.fWrite) + { + HRESULT rc = m.pMedium->unlockWrite(NULL); + AssertComRC(rc); + } + else + { + HRESULT rc = m.pMedium->unlockRead(NULL); + AssertComRC(rc); + } + m.pMedium.setNull(); + } +} + +// IToken methods +///////////////////////////////////////////////////////////////////////////// + +HRESULT MediumLockToken::abandon(AutoCaller &aAutoCaller) +{ + /* have to release the AutoCaller before calling uninit(), self-deadlock */ + aAutoCaller.release(); + + /* uninit does everything we need */ + uninit(); + return S_OK; +} + +HRESULT MediumLockToken::dummy() +{ + /* Remember, the wrapper contains the AutoCaller, which means that after + * uninit() this code won't be reached any more. */ + + /* this is a NOOP, no need to lock */ + + return S_OK; +} + +// public methods only for internal purposes +///////////////////////////////////////////////////////////////////////////// + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/USBControllerImpl.cpp b/src/VBox/Main/src-server/USBControllerImpl.cpp index 8f4d1c48..18c4f43e 100644 --- a/src/VBox/Main/src-server/USBControllerImpl.cpp +++ b/src/VBox/Main/src-server/USBControllerImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2012 Oracle Corporation + * Copyright (C) 2005-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,18 +21,13 @@ #include "MachineImpl.h" #include "VirtualBoxImpl.h" #include "HostImpl.h" -#ifdef VBOX_WITH_USB -# include "USBDeviceImpl.h" -# include "HostUSBDeviceImpl.h" -# include "USBProxyService.h" -# include "USBDeviceFilterImpl.h" -#endif #include #include #include #include +#include #include @@ -43,41 +38,31 @@ // defines ///////////////////////////////////////////////////////////////////////////// -typedef std::list< ComObjPtr > DeviceFilterList; - struct BackupableUSBData { BackupableUSBData() - : fEnabled(false), - fEnabledEHCI(false) + : enmType(USBControllerType_Null) { } - BOOL fEnabled; - BOOL fEnabledEHCI; + Utf8Str strName; + USBControllerType_T enmType; }; struct USBController::Data { Data(Machine *pMachine) - : pParent(pMachine), - pHost(pMachine->getVirtualBox()->host()) + : pParent(pMachine) { } ~Data() {}; Machine * const pParent; - Host * const pHost; // peer machine's USB controller const ComObjPtr pPeer; Backupable bd; -#ifdef VBOX_WITH_USB - // the following fields need special backup/rollback/commit handling, - // so they cannot be a part of BackupableData - Backupable llDeviceFilters; -#endif }; @@ -106,12 +91,18 @@ void USBController::FinalRelease() * * @returns COM result indicator. * @param aParent Pointer to our parent object. + * @param aName The name of the USB controller. + * @param enmType The USB controller type. */ -HRESULT USBController::init(Machine *aParent) +HRESULT USBController::init(Machine *aParent, const Utf8Str &aName, USBControllerType_T enmType) { - LogFlowThisFunc(("aParent=%p\n", aParent)); + LogFlowThisFunc(("aParent=%p aName=\"%s\"\n", aParent, aName.c_str())); - ComAssertRet(aParent, E_INVALIDARG); + ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG); + if ( (enmType <= USBControllerType_Null) + || (enmType > USBControllerType_EHCI)) + return setError(E_INVALIDARG, + tr("Invalid USB controller type")); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -122,9 +113,8 @@ HRESULT USBController::init(Machine *aParent) /* mPeer is left null */ m->bd.allocate(); -#ifdef VBOX_WITH_USB - m->llDeviceFilters.allocate(); -#endif + m->bd->strName = aName; + m->bd->enmType = enmType; /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -140,13 +130,22 @@ HRESULT USBController::init(Machine *aParent) * @returns COM result indicator. * @param aParent Pointer to our parent object. * @param aPeer The object to share. + * @param aReshare + * When false, the original object will remain a data owner. + * Otherwise, data ownership will be transferred from the original + * object to this one. + * + * @note This object must be destroyed before the original object + * it shares data with is destroyed. * - * @note This object must be destroyed before the original object - * it shares data with is destroyed. + * @note Locks @a aThat object for writing if @a aReshare is @c true, or for + * reading if @a aReshare is false. */ -HRESULT USBController::init(Machine *aParent, USBController *aPeer) +HRESULT USBController::init(Machine *aParent, USBController *aPeer, + bool fReshare /* = false */) { - LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer)); + LogFlowThisFunc(("aParent=%p, aPeer=%p, fReshare=%RTbool\n", + aParent, aPeer, fReshare)); ComAssertRet(aParent && aPeer, E_INVALIDARG); @@ -156,24 +155,24 @@ HRESULT USBController::init(Machine *aParent, USBController *aPeer) m = new Data(aParent); - unconst(m->pPeer) = aPeer; + /* sanity */ + AutoCaller peerCaller(aPeer); + AssertComRCReturnRC(peerCaller.rc()); - AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); - m->bd.share(aPeer->m->bd); + if (fReshare) + { + AutoWriteLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS); -#ifdef VBOX_WITH_USB - /* create copies of all filters */ - m->llDeviceFilters.allocate(); - DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); - while (it != aPeer->m->llDeviceFilters->end()) + unconst(aPeer->m->pPeer) = this; + m->bd.attach (aPeer->m->bd); + } + else { - ComObjPtr filter; - filter.createObject(); - filter->init(this, *it); - m->llDeviceFilters->push_back(filter); - ++it; + unconst(m->pPeer) = aPeer; + + AutoReadLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS); + m->bd.share (aPeer->m->bd); } -#endif /* VBOX_WITH_USB */ /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -204,20 +203,6 @@ HRESULT USBController::initCopy(Machine *aParent, USBController *aPeer) AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); m->bd.attachCopy(aPeer->m->bd); -#ifdef VBOX_WITH_USB - /* create private copies of all filters */ - m->llDeviceFilters.allocate(); - DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); - while (it != aPeer->m->llDeviceFilters->end()) - { - ComObjPtr filter; - filter.createObject(); - filter->initCopy(this, *it); - m->llDeviceFilters->push_back(filter); - ++it; - } -#endif /* VBOX_WITH_USB */ - /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -238,16 +223,6 @@ void USBController::uninit() if (autoUninitSpan.uninitDone()) return; -#ifdef VBOX_WITH_USB - // uninit all device filters on the list (it's a standard std::list not an ObjectsList - // so we must uninit() manually) - for (DeviceFilterList::iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - (*it)->uninit(); - - m->llDeviceFilters.free(); -#endif m->bd.free(); unconst(m->pPeer) = NULL; @@ -260,112 +235,29 @@ void USBController::uninit() // IUSBController properties ///////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP USBController::COMGETTER(Enabled)(BOOL *aEnabled) -{ - CheckComArgOutPointerValid(aEnabled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - *aEnabled = m->bd->fEnabled; - - return S_OK; -} - - -STDMETHODIMP USBController::COMSETTER(Enabled)(BOOL aEnabled) -{ - LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (m->bd->fEnabled != aEnabled) - { - m->bd.backup(); - m->bd->fEnabled = aEnabled; - - // leave the lock for safety - alock.release(); - - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - m->pParent->onUSBControllerChange(); - } - - return S_OK; -} - -STDMETHODIMP USBController::COMGETTER(EnabledEHCI)(BOOL *aEnabled) -{ - CheckComArgOutPointerValid(aEnabled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - *aEnabled = m->bd->fEnabledEHCI; - - return S_OK; -} - -STDMETHODIMP USBController::COMSETTER(EnabledEHCI)(BOOL aEnabled) +STDMETHODIMP USBController::COMGETTER(Name) (BSTR *aName) { - LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled)); + CheckComArgOutPointerValid(aName); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (m->bd->fEnabledEHCI != aEnabled) - { - m->bd.backup(); - m->bd->fEnabledEHCI = aEnabled; - - // leave the lock for safety - alock.release(); - - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - m->pParent->onUSBControllerChange(); - } + /* strName is constant during life time, no need to lock */ + m->bd->strName.cloneTo(aName); return S_OK; } -STDMETHODIMP USBController::COMGETTER(ProxyAvailable)(BOOL *aEnabled) +STDMETHODIMP USBController::COMGETTER(Type)(USBControllerType_T *aType) { - CheckComArgOutPointerValid(aEnabled); + CheckComArgOutPointerValid(aType); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); -#ifdef VBOX_WITH_USB - *aEnabled = true; -#else - *aEnabled = false; -#endif + *aType = m->bd->enmType; return S_OK; } @@ -377,366 +269,27 @@ STDMETHODIMP USBController::COMGETTER(USBStandard)(USHORT *aUSBStandard) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* not accessing data -- no need to lock */ - - /** @todo This is no longer correct */ - *aUSBStandard = 0x0101; - - return S_OK; -} - -#ifndef VBOX_WITH_USB -/** - * Fake class for build without USB. - * We need an empty collection & enum for deviceFilters, that's all. - */ -class ATL_NO_VTABLE USBDeviceFilter : - public VirtualBoxBase, - VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter) -{ -public: - DECLARE_NOT_AGGREGATABLE(USBDeviceFilter) - DECLARE_PROTECT_FINAL_CONSTRUCT() - BEGIN_COM_MAP(USBDeviceFilter) - VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilter) - END_COM_MAP() - - DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter) - - // IUSBDeviceFilter properties - STDMETHOD(COMGETTER(Name))(BSTR *aName); - STDMETHOD(COMSETTER(Name))(IN_BSTR aName); - STDMETHOD(COMGETTER(Active))(BOOL *aActive); - STDMETHOD(COMSETTER(Active))(BOOL aActive); - STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId); - STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId); - STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId); - STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId); - STDMETHOD(COMGETTER(Revision))(BSTR *aRevision); - STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision); - STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer); - STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer); - STDMETHOD(COMGETTER(Product))(BSTR *aProduct); - STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct); - STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber); - STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber); - STDMETHOD(COMGETTER(Port))(BSTR *aPort); - STDMETHOD(COMSETTER(Port))(IN_BSTR aPort); - STDMETHOD(COMGETTER(Remote))(BSTR *aRemote); - STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote); - STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs); - STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs); -}; -#endif /* !VBOX_WITH_USB */ - - -STDMETHODIMP USBController::COMGETTER(DeviceFilters)(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters)) -{ -#ifdef VBOX_WITH_USB - CheckComArgOutSafeArrayPointerValid(aDevicesFilters); - - AutoCaller autoCaller(this); - if(FAILED(autoCaller.rc())) return autoCaller.rc(); - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - SafeIfaceArray collection(*m->llDeviceFilters.data()); - collection.detachTo(ComSafeArrayOutArg(aDevicesFilters)); - - return S_OK; -#else - NOREF(aDevicesFilters); -# ifndef RT_OS_WINDOWS - NOREF(aDevicesFiltersSize); -# endif - ReturnComNotImplemented(); -#endif -} - -// IUSBController methods -///////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP USBController::CreateDeviceFilter(IN_BSTR aName, - IUSBDeviceFilter **aFilter) -{ -#ifdef VBOX_WITH_USB - CheckComArgOutPointerValid(aFilter); - - CheckComArgStrNotEmptyOrNull(aName); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - ComObjPtr filter; - filter.createObject(); - HRESULT rc = filter->init(this, aName); - ComAssertComRCRetRC(rc); - rc = filter.queryInterfaceTo(aFilter); - AssertComRCReturnRC(rc); - - return S_OK; -#else - NOREF(aName); - NOREF(aFilter); - ReturnComNotImplemented(); -#endif -} - -STDMETHODIMP USBController::InsertDeviceFilter(ULONG aPosition, - IUSBDeviceFilter *aFilter) -{ -#ifdef VBOX_WITH_USB - - CheckComArgNotNull(aFilter); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - ComObjPtr filter = static_cast(aFilter); - // @todo r=dj make sure the input object is actually from us -// if (!filter) -// return setError(E_INVALIDARG, -// tr("The given USB device filter is not created within " -// "this VirtualBox instance")); - - if (filter->mInList) - return setError(VBOX_E_INVALID_OBJECT_STATE, - tr("The given USB device filter is already in the list")); - - /* backup the list before modification */ - m->llDeviceFilters.backup(); - - /* iterate to the position... */ - DeviceFilterList::iterator it; - if (aPosition < m->llDeviceFilters->size()) + switch (m->bd->enmType) { - it = m->llDeviceFilters->begin(); - std::advance(it, aPosition); - } - else - it = m->llDeviceFilters->end(); - /* ...and insert */ - m->llDeviceFilters->insert(it, filter); - filter->mInList = true; - - /* notify the proxy (only when it makes sense) */ - if (filter->getData().mActive && Global::IsOnline(adep.machineState()) - && filter->getData().mRemote.isMatch(false)) - { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - ComAssertRet(filter->getId() == NULL, E_FAIL); - filter->getId() = service->insertFilter(&filter->getData().mUSBFilter); + case USBControllerType_OHCI: + *aUSBStandard = 0x0101; + break; + case USBControllerType_EHCI: + *aUSBStandard = 0x0200; + break; + default: + AssertMsgFailedReturn(("Invalid controller type %d\n", m->bd->enmType), + E_FAIL); } - alock.release(); - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - return S_OK; - -#else /* VBOX_WITH_USB */ - - NOREF(aPosition); - NOREF(aFilter); - ReturnComNotImplemented(); - -#endif /* VBOX_WITH_USB */ -} - -STDMETHODIMP USBController::RemoveDeviceFilter(ULONG aPosition, - IUSBDeviceFilter **aFilter) -{ -#ifdef VBOX_WITH_USB - - CheckComArgOutPointerValid(aFilter); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (!m->llDeviceFilters->size()) - return setError(E_INVALIDARG, - tr("The USB device filter list is empty")); - - if (aPosition >= m->llDeviceFilters->size()) - return setError(E_INVALIDARG, - tr("Invalid position: %lu (must be in range [0, %lu])"), - aPosition, m->llDeviceFilters->size() - 1); - - /* backup the list before modification */ - m->llDeviceFilters.backup(); - - ComObjPtr filter; - { - /* iterate to the position... */ - DeviceFilterList::iterator it = m->llDeviceFilters->begin(); - std::advance(it, aPosition); - /* ...get an element from there... */ - filter = *it; - /* ...and remove */ - filter->mInList = false; - m->llDeviceFilters->erase(it); - } - - /* cancel sharing (make an independent copy of data) */ - filter->unshare(); - - filter.queryInterfaceTo(aFilter); - - /* notify the proxy (only when it makes sense) */ - if (filter->getData().mActive && Global::IsOnline(adep.machineState()) - && filter->getData().mRemote.isMatch(false)) - { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - ComAssertRet(filter->getId() != NULL, E_FAIL); - service->removeFilter(filter->getId()); - filter->getId() = NULL; - } - - alock.release(); - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - return S_OK; - -#else /* VBOX_WITH_USB */ - - NOREF(aPosition); - NOREF(aFilter); - ReturnComNotImplemented(); - -#endif /* VBOX_WITH_USB */ } // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// -/** - * Loads settings from the given machine node. - * May be called once right after this object creation. - * - * @param aMachineNode node. - * - * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either. - */ -HRESULT USBController::loadSettings(const settings::USBController &data) -{ - AutoCaller autoCaller(this); - AssertComRCReturnRC(autoCaller.rc()); - - /* Note: we assume that the default values for attributes of optional - * nodes are assigned in the Data::Data() constructor and don't do it - * here. It implies that this method may only be called after constructing - * a new BIOSSettings object while all its data fields are in the default - * values. Exceptions are fields whose creation time defaults don't match - * values that should be applied when these fields are not explicitly set - * in the settings file (for backwards compatibility reasons). This takes - * place when a setting of a newly created object must default to A while - * the same setting of an object loaded from the old settings file must - * default to B. */ - - m->bd->fEnabled = data.fEnabled; - m->bd->fEnabledEHCI = data.fEnabledEHCI; - -#ifdef VBOX_WITH_USB - for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin(); - it != data.llDeviceFilters.end(); - ++it) - { - const settings::USBDeviceFilter &f = *it; - ComObjPtr pFilter; - pFilter.createObject(); - HRESULT rc = pFilter->init(this, // parent - f); - if (FAILED(rc)) return rc; - - m->llDeviceFilters->push_back(pFilter); - pFilter->mInList = true; - } -#endif /* VBOX_WITH_USB */ - - return S_OK; -} - -/** - * Saves settings to the given machine node. - * - * @param aMachineNode node. - * - * @note Locks this object for reading. - */ -HRESULT USBController::saveSettings(settings::USBController &data) -{ - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - data.fEnabled = !!m->bd->fEnabled; - data.fEnabledEHCI = !!m->bd->fEnabledEHCI; - -#ifdef VBOX_WITH_USB - data.llDeviceFilters.clear(); - - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - const USBDeviceFilter::Data &filterData = (*it)->getData(); - - Bstr str; - - settings::USBDeviceFilter f; - f.strName = filterData.mName; - f.fActive = !!filterData.mActive; - (*it)->COMGETTER(VendorId)(str.asOutParam()); - f.strVendorId = str; - (*it)->COMGETTER(ProductId)(str.asOutParam()); - f.strProductId = str; - (*it)->COMGETTER(Revision)(str.asOutParam()); - f.strRevision = str; - (*it)->COMGETTER(Manufacturer)(str.asOutParam()); - f.strManufacturer = str; - (*it)->COMGETTER(Product)(str.asOutParam()); - f.strProduct = str; - (*it)->COMGETTER(SerialNumber)(str.asOutParam()); - f.strSerialNumber = str; - (*it)->COMGETTER(Port)(str.asOutParam()); - f.strPort = str; - f.strRemote = filterData.mRemote.string(); - f.ulMaskedInterfaces = filterData.mMaskedIfs; - - data.llDeviceFilters.push_back(f); - } -#endif /* VBOX_WITH_USB */ - - return S_OK; -} - /** @note Locks objects for writing! */ void USBController::rollback() { @@ -750,82 +303,6 @@ void USBController::rollback() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); m->bd.rollback(); - -#ifdef VBOX_WITH_USB - - if (m->llDeviceFilters.isBackedUp()) - { - USBProxyService *service = m->pHost->usbProxyService(); - Assert(service); - - /* uninitialize all new filters (absent in the backed up list) */ - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - DeviceFilterList *backedList = m->llDeviceFilters.backedUpData(); - while (it != m->llDeviceFilters->end()) - { - if (std::find(backedList->begin(), backedList->end(), *it) == - backedList->end()) - { - /* notify the proxy (only when it makes sense) */ - if ((*it)->getData().mActive && - Global::IsOnline(adep.machineState()) - && (*it)->getData().mRemote.isMatch(false)) - { - USBDeviceFilter *filter = *it; - Assert(filter->getId() != NULL); - service->removeFilter(filter->getId()); - filter->getId() = NULL; - } - - (*it)->uninit(); - } - ++it; - } - - if (Global::IsOnline(adep.machineState())) - { - /* find all removed old filters (absent in the new list) - * and insert them back to the USB proxy */ - it = backedList->begin(); - while (it != backedList->end()) - { - if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) == - m->llDeviceFilters->end()) - { - /* notify the proxy (only when necessary) */ - if ((*it)->getData().mActive - && (*it)->getData().mRemote.isMatch(false)) - { - USBDeviceFilter *flt = *it; /* resolve ambiguity */ - Assert(flt->getId() == NULL); - flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); - } - } - ++it; - } - } - - /* restore the list */ - m->llDeviceFilters.rollback(); - } - - /* here we don't depend on the machine state any more */ - adep.release(); - - /* rollback any changes to filters after restoring the list */ - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - if ((*it)->isModified()) - { - (*it)->rollback(); - /* call this to notify the USB proxy about changes */ - onDeviceFilterChange(*it); - } - ++it; - } - -#endif /* VBOX_WITH_USB */ } /** @@ -856,82 +333,6 @@ void USBController::commit() m->pPeer->m->bd.attach(m->bd); } } - -#ifdef VBOX_WITH_USB - bool commitFilters = false; - - if (m->llDeviceFilters.isBackedUp()) - { - m->llDeviceFilters.commit(); - - /* apply changes to peer */ - if (m->pPeer) - { - AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS); - - /* commit all changes to new filters (this will reshare data with - * peers for those who have peers) */ - DeviceFilterList *newList = new DeviceFilterList(); - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - (*it)->commit(); - - /* look if this filter has a peer filter */ - ComObjPtr peer = (*it)->peer(); - if (!peer) - { - /* no peer means the filter is a newly created one; - * create a peer owning data this filter share it with */ - peer.createObject(); - peer->init(m->pPeer, *it, true /* aReshare */); - } - else - { - /* remove peer from the old list */ - m->pPeer->m->llDeviceFilters->remove(peer); - } - /* and add it to the new list */ - newList->push_back(peer); - - ++it; - } - - /* uninit old peer's filters that are left */ - it = m->pPeer->m->llDeviceFilters->begin(); - while (it != m->pPeer->m->llDeviceFilters->end()) - { - (*it)->uninit(); - ++it; - } - - /* attach new list of filters to our peer */ - m->pPeer->m->llDeviceFilters.attach(newList); - } - else - { - /* we have no peer (our parent is the newly created machine); - * just commit changes to filters */ - commitFilters = true; - } - } - else - { - /* the list of filters itself is not changed, - * just commit changes to filters themselves */ - commitFilters = true; - } - - if (commitFilters) - { - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - (*it)->commit(); - ++it; - } - } -#endif /* VBOX_WITH_USB */ } /** @@ -963,295 +364,56 @@ void USBController::copyFrom(USBController *aThat) /* this will back up current data */ m->bd.assignCopy(aThat->m->bd); - -#ifdef VBOX_WITH_USB - - /* Note that we won't inform the USB proxy about new filters since the VM is - * not running when we are here and therefore no need to do so */ - - /* create private copies of all filters */ - m->llDeviceFilters.backup(); - m->llDeviceFilters->clear(); - for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin(); - it != aThat->m->llDeviceFilters->end(); - ++it) - { - ComObjPtr filter; - filter.createObject(); - filter->initCopy(this, *it); - m->llDeviceFilters->push_back(filter); - } - -#endif /* VBOX_WITH_USB */ } -#ifdef VBOX_WITH_USB - /** - * Called by setter methods of all USB device filters. + * Cancels sharing (if any) by making an independent copy of data. + * This operation also resets this object's peer to NULL. * - * @note Locks nothing. + * @note Locks this object for writing, together with the peer object + * represented by @a aThat (locked for reading). */ -HRESULT USBController::onDeviceFilterChange(USBDeviceFilter *aFilter, - BOOL aActiveChanged /* = FALSE */) +void USBController::unshare() { + /* sanity */ AutoCaller autoCaller(this); - AssertComRCReturnRC(autoCaller.rc()); + AssertComRCReturnVoid (autoCaller.rc()); - /* we need the machine state */ - AutoAnyStateDependency adep(m->pParent); - AssertComRCReturnRC(adep.rc()); - - /* nothing to do if the machine isn't running */ - if (!Global::IsOnline(adep.machineState())) - return S_OK; + /* sanity too */ + AutoCaller peerCaller (m->pPeer); + AssertComRCReturnVoid (peerCaller.rc()); - /* we don't modify our data fields -- no need to lock */ + /* peer is not modified, lock it for reading (m->pPeer is "master" so locked + * first) */ + AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS); + AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS); - if ( aFilter->mInList - && m->pParent->isRegistered()) + if (m->bd.isShared()) { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - if (aActiveChanged) - { - if (aFilter->getData().mRemote.isMatch(false)) - { - /* insert/remove the filter from the proxy */ - if (aFilter->getData().mActive) - { - ComAssertRet(aFilter->getId() == NULL, E_FAIL); - aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); - } - else - { - ComAssertRet(aFilter->getId() != NULL, E_FAIL); - service->removeFilter(aFilter->getId()); - aFilter->getId() = NULL; - } - } - } - else - { - if (aFilter->getData().mActive) - { - /* update the filter in the proxy */ - ComAssertRet(aFilter->getId() != NULL, E_FAIL); - service->removeFilter(aFilter->getId()); - if (aFilter->getData().mRemote.isMatch(false)) - { - aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); - } - } - } - } - - return S_OK; -} - -/** - * Returns true if the given USB device matches to at least one of - * this controller's USB device filters. - * - * A HostUSBDevice specific version. - * - * @note Locks this object for reading. - */ -bool USBController::hasMatchingFilter(const ComObjPtr &aDevice, ULONG *aMaskedIfs) -{ - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); + if (!m->bd.isBackedUp()) + m->bd.backup(); - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* Disabled USB controllers cannot actually work with USB devices */ - if (!m->bd->fEnabled) - return false; - - /* apply self filters */ - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - if (aDevice->isMatch((*it)->getData())) - { - *aMaskedIfs = (*it)->getData().mMaskedIfs; - return true; - } + m->bd.commit(); } - return false; + unconst(m->pPeer) = NULL; } -/** - * Returns true if the given USB device matches to at least one of - * this controller's USB device filters. - * - * A generic version that accepts any IUSBDevice on input. - * - * @note - * This method MUST correlate with HostUSBDevice::isMatch() - * in the sense of the device matching logic. - * - * @note Locks this object for reading. - */ -bool USBController::hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs) +const Utf8Str& USBController::getName() const { - LogFlowThisFuncEnter(); - - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* Disabled USB controllers cannot actually work with USB devices */ - if (!m->bd->fEnabled) - return false; - - HRESULT rc = S_OK; - - /* query fields */ - USBFILTER dev; - USBFilterInit(&dev, USBFILTERTYPE_CAPTURE); - - USHORT vendorId = 0; - rc = aUSBDevice->COMGETTER(VendorId)(&vendorId); - ComAssertComRCRet(rc, false); - ComAssertRet(vendorId, false); - int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc); - - USHORT productId = 0; - rc = aUSBDevice->COMGETTER(ProductId)(&productId); - ComAssertComRCRet(rc, false); - vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc); - - USHORT revision; - rc = aUSBDevice->COMGETTER(Revision)(&revision); - ComAssertComRCRet(rc, false); - vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc); - - Bstr manufacturer; - rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam()); - ComAssertComRCRet(rc, false); - if (!manufacturer.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true); - - Bstr product; - rc = aUSBDevice->COMGETTER(Product)(product.asOutParam()); - ComAssertComRCRet(rc, false); - if (!product.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true); - - Bstr serialNumber; - rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam()); - ComAssertComRCRet(rc, false); - if (!serialNumber.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true); - - Bstr address; - rc = aUSBDevice->COMGETTER(Address)(address.asOutParam()); - ComAssertComRCRet(rc, false); - - USHORT port = 0; - rc = aUSBDevice->COMGETTER(Port)(&port); - ComAssertComRCRet(rc, false); - USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true); - - BOOL remote = FALSE; - rc = aUSBDevice->COMGETTER(Remote)(&remote); - ComAssertComRCRet(rc, false); - ComAssertRet(remote == TRUE, false); - - bool match = false; - - /* apply self filters */ - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - const USBDeviceFilter::Data &aData = (*it)->getData(); - - if (!aData.mActive) - continue; - if (!aData.mRemote.isMatch(remote)) - continue; - if (!USBFilterMatch(&aData.mUSBFilter, &dev)) - continue; - - match = true; - *aMaskedIfs = aData.mMaskedIfs; - break; - } - - LogFlowThisFunc(("returns: %d\n", match)); - LogFlowThisFuncLeave(); - - return match; + return m->bd->strName; } -/** - * Notifies the proxy service about all filters as requested by the - * @a aInsertFilters argument. - * - * @param aInsertFilters @c true to insert filters, @c false to remove. - * - * @note Locks this object for reading. - */ -HRESULT USBController::notifyProxy(bool aInsertFilters) +USBControllerType_T USBController::getControllerType() const { - LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters)); - - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - USBProxyService *service = m->pHost->usbProxyService(); - AssertReturn(service, E_FAIL); - - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */ - - /* notify the proxy (only if the filter is active) */ - if ( flt->getData().mActive - && flt->getData().mRemote.isMatch(false) /* and if the filter is NOT remote */ - ) - { - if (aInsertFilters) - { - AssertReturn(flt->getId() == NULL, E_FAIL); - flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); - } - else - { - /* It's possible that the given filter was not inserted the proxy - * when this method gets called (as a result of an early VM - * process crash for example. So, don't assert that ID != NULL. */ - if (flt->getId() != NULL) - { - service->removeFilter(flt->getId()); - flt->getId() = NULL; - } - } - } - ++it; - } - - return S_OK; + return m->bd->enmType; } -Machine* USBController::getMachine() +ComObjPtr USBController::getPeer() { - return m->pParent; + return m->pPeer; } -#endif /* VBOX_WITH_USB */ - // private methods ///////////////////////////////////////////////////////////////////////////// /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp b/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp index 0c8046e9..47857b4e 100644 --- a/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp +++ b/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -16,7 +16,7 @@ */ #include "USBDeviceFilterImpl.h" -#include "USBControllerImpl.h" +#include "USBDeviceFiltersImpl.h" #include "MachineImpl.h" #include "HostImpl.h" @@ -203,7 +203,7 @@ void USBDeviceFilter::FinalRelease() * * @param aParent Handle of the parent object. */ -HRESULT USBDeviceFilter::init(USBController *aParent, +HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, const settings::USBDeviceFilter &data) { LogFlowThisFunc(("aParent=%p\n", aParent)); @@ -277,7 +277,7 @@ HRESULT USBDeviceFilter::init(USBController *aParent, * * @param aParent Handle of the parent object. */ -HRESULT USBDeviceFilter::init(USBController *aParent, IN_BSTR aName) +HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, IN_BSTR aName) { LogFlowThisFunc(("aParent=%p\n", aParent)); @@ -326,7 +326,7 @@ HRESULT USBDeviceFilter::init(USBController *aParent, IN_BSTR aName) * @note Locks @a aThat object for writing if @a aReshare is @c true, or for * reading if @a aReshare is false. */ -HRESULT USBDeviceFilter::init (USBController *aParent, USBDeviceFilter *aThat, +HRESULT USBDeviceFilter::init (USBDeviceFilters *aParent, USBDeviceFilter *aThat, bool aReshare /* = false */) { LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n", @@ -379,7 +379,7 @@ HRESULT USBDeviceFilter::init (USBController *aParent, USBDeviceFilter *aThat, * * @note Locks @a aThat object for reading. */ -HRESULT USBDeviceFilter::initCopy (USBController *aParent, USBDeviceFilter *aThat) +HRESULT USBDeviceFilter::initCopy (USBDeviceFilters *aParent, USBDeviceFilter *aThat) { LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat)); diff --git a/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp b/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp new file mode 100644 index 00000000..09b42f5c --- /dev/null +++ b/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp @@ -0,0 +1,1089 @@ +/* $Id: USBDeviceFiltersImpl.cpp $ */ +/** @file + * Implementation of IUSBController. + */ + +/* + * Copyright (C) 2005-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "USBDeviceFiltersImpl.h" + +#include "Global.h" +#include "MachineImpl.h" +#include "VirtualBoxImpl.h" +#include "HostImpl.h" +#ifdef VBOX_WITH_USB +# include "USBDeviceImpl.h" +# include "HostUSBDeviceImpl.h" +# include "USBProxyService.h" +# include "USBDeviceFilterImpl.h" +#endif + +#include +#include + +#include +#include +#include + +#include + +#include "AutoStateDep.h" +#include "AutoCaller.h" +#include "Logging.h" + +// defines +///////////////////////////////////////////////////////////////////////////// + +typedef std::list< ComObjPtr > DeviceFilterList; + +struct USBDeviceFilters::Data +{ + Data(Machine *pMachine) + : pParent(pMachine), + pHost(pMachine->getVirtualBox()->host()) + { } + + ~Data() + {}; + + Machine * const pParent; + Host * const pHost; + + // peer machine's USB device filters list + const ComObjPtr pPeer; + +#ifdef VBOX_WITH_USB + // List of device filters. + Backupable llDeviceFilters; +#endif +}; + + + +// constructor / destructor +///////////////////////////////////////////////////////////////////////////// + +DEFINE_EMPTY_CTOR_DTOR(USBDeviceFilters) + +HRESULT USBDeviceFilters::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void USBDeviceFilters::FinalRelease() +{ + uninit(); + BaseFinalRelease(); +} + +// public initializer/uninitializer for internal purposes only +///////////////////////////////////////////////////////////////////////////// + +/** + * Initializes the USB controller object. + * + * @returns COM result indicator. + * @param aParent Pointer to our parent object. + */ +HRESULT USBDeviceFilters::init(Machine *aParent) +{ + LogFlowThisFunc(("aParent=%p\n", aParent)); + + ComAssertRet(aParent, E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m = new Data(aParent); + + /* mPeer is left null */ +#ifdef VBOX_WITH_USB + m->llDeviceFilters.allocate(); +#endif + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + +/** + * Initializes the USB devic filters object given another USB filters object + * (a kind of copy constructor). This object shares data with + * the object passed as an argument. + * + * @returns COM result indicator. + * @param aParent Pointer to our parent object. + * @param aPeer The object to share. + * + * @note This object must be destroyed before the original object + * it shares data with is destroyed. + */ +HRESULT USBDeviceFilters::init(Machine *aParent, USBDeviceFilters *aPeer) +{ + LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer)); + + ComAssertRet(aParent && aPeer, E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m = new Data(aParent); + + unconst(m->pPeer) = aPeer; + + AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + /* create copies of all filters */ + m->llDeviceFilters.allocate(); + DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); + while (it != aPeer->m->llDeviceFilters->end()) + { + ComObjPtr pFilter; + pFilter.createObject(); + pFilter->init(this, *it); + m->llDeviceFilters->push_back(pFilter); + ++it; + } +#endif /* VBOX_WITH_USB */ + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + + +/** + * Initializes the USB controller object given another guest object + * (a kind of copy constructor). This object makes a private copy of data + * of the original object passed as an argument. + */ +HRESULT USBDeviceFilters::initCopy(Machine *aParent, USBDeviceFilters *aPeer) +{ + LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer)); + + ComAssertRet(aParent && aPeer, E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m = new Data(aParent); + + /* mPeer is left null */ + + AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + /* create private copies of all filters */ + m->llDeviceFilters.allocate(); + DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); + while (it != aPeer->m->llDeviceFilters->end()) + { + ComObjPtr pFilter; + pFilter.createObject(); + pFilter->initCopy(this, *it); + m->llDeviceFilters->push_back(pFilter); + ++it; + } +#endif /* VBOX_WITH_USB */ + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return S_OK; +} + + +/** + * Uninitializes the instance and sets the ready flag to FALSE. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void USBDeviceFilters::uninit() +{ + LogFlowThisFunc(("\n")); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + +#ifdef VBOX_WITH_USB + // uninit all device filters on the list (it's a standard std::list not an ObjectsList + // so we must uninit() manually) + for (DeviceFilterList::iterator it = m->llDeviceFilters->begin(); + it != m->llDeviceFilters->end(); + ++it) + (*it)->uninit(); + + m->llDeviceFilters.free(); +#endif + + unconst(m->pPeer) = NULL; + unconst(m->pParent) = NULL; + + delete m; + m = NULL; +} + + +// IUSBDeviceFilters properties +///////////////////////////////////////////////////////////////////////////// + +#ifndef VBOX_WITH_USB +/** + * Fake class for build without USB. + * We need an empty collection & enum for deviceFilters, that's all. + */ +class ATL_NO_VTABLE USBDeviceFilter : + public VirtualBoxBase, + VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter) +{ +public: + DECLARE_NOT_AGGREGATABLE(USBDeviceFilter) + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(USBDeviceFilter) + VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilter) + END_COM_MAP() + + DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter) + + // IUSBDeviceFilter properties + STDMETHOD(COMGETTER(Name))(BSTR *aName); + STDMETHOD(COMSETTER(Name))(IN_BSTR aName); + STDMETHOD(COMGETTER(Active))(BOOL *aActive); + STDMETHOD(COMSETTER(Active))(BOOL aActive); + STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId); + STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId); + STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId); + STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId); + STDMETHOD(COMGETTER(Revision))(BSTR *aRevision); + STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision); + STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer); + STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer); + STDMETHOD(COMGETTER(Product))(BSTR *aProduct); + STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct); + STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber); + STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber); + STDMETHOD(COMGETTER(Port))(BSTR *aPort); + STDMETHOD(COMSETTER(Port))(IN_BSTR aPort); + STDMETHOD(COMGETTER(Remote))(BSTR *aRemote); + STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote); + STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs); + STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs); +}; +#endif /* !VBOX_WITH_USB */ + + +STDMETHODIMP USBDeviceFilters::COMGETTER(DeviceFilters)(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters)) +{ +#ifdef VBOX_WITH_USB + CheckComArgOutSafeArrayPointerValid(aDevicesFilters); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + SafeIfaceArray collection(*m->llDeviceFilters.data()); + collection.detachTo(ComSafeArrayOutArg(aDevicesFilters)); + + return S_OK; +#else + NOREF(aDevicesFilters); +# ifndef RT_OS_WINDOWS + NOREF(aDevicesFiltersSize); +# endif + ReturnComNotImplemented(); +#endif +} + +// IUSBDeviceFilters methods +///////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP USBDeviceFilters::CreateDeviceFilter(IN_BSTR aName, + IUSBDeviceFilter **aFilter) +{ +#ifdef VBOX_WITH_USB + CheckComArgOutPointerValid(aFilter); + + CheckComArgStrNotEmptyOrNull(aName); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent); + if (FAILED(adep.rc())) return adep.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + ComObjPtr pFilter; + pFilter.createObject(); + HRESULT rc = pFilter->init(this, aName); + ComAssertComRCRetRC(rc); + rc = pFilter.queryInterfaceTo(aFilter); + AssertComRCReturnRC(rc); + + return S_OK; +#else + NOREF(aName); + NOREF(aFilter); + ReturnComNotImplemented(); +#endif +} + +STDMETHODIMP USBDeviceFilters::InsertDeviceFilter(ULONG aPosition, + IUSBDeviceFilter *aFilter) +{ +#ifdef VBOX_WITH_USB + + CheckComArgNotNull(aFilter); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent); + if (FAILED(adep.rc())) return adep.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + ComObjPtr pFilter = static_cast(aFilter); + + if (pFilter->mInList) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("The given USB device pFilter is already in the list")); + + /* backup the list before modification */ + m->llDeviceFilters.backup(); + + /* iterate to the position... */ + DeviceFilterList::iterator it; + if (aPosition < m->llDeviceFilters->size()) + { + it = m->llDeviceFilters->begin(); + std::advance(it, aPosition); + } + else + it = m->llDeviceFilters->end(); + /* ...and insert */ + m->llDeviceFilters->insert(it, pFilter); + pFilter->mInList = true; + + /* notify the proxy (only when it makes sense) */ + if (pFilter->getData().mActive && Global::IsOnline(adep.machineState()) + && pFilter->getData().mRemote.isMatch(false)) + { + USBProxyService *pProxySvc = m->pHost->usbProxyService(); + ComAssertRet(pProxySvc, E_FAIL); + + ComAssertRet(pFilter->getId() == NULL, E_FAIL); + pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter); + } + + alock.release(); + AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); + m->pParent->setModified(Machine::IsModified_USB); + mlock.release(); + + return S_OK; + +#else /* VBOX_WITH_USB */ + + NOREF(aPosition); + NOREF(aFilter); + ReturnComNotImplemented(); + +#endif /* VBOX_WITH_USB */ +} + +STDMETHODIMP USBDeviceFilters::RemoveDeviceFilter(ULONG aPosition, + IUSBDeviceFilter **aFilter) +{ +#ifdef VBOX_WITH_USB + + CheckComArgOutPointerValid(aFilter); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + /* the machine needs to be mutable */ + AutoMutableStateDependency adep(m->pParent); + if (FAILED(adep.rc())) return adep.rc(); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (!m->llDeviceFilters->size()) + return setError(E_INVALIDARG, + tr("The USB device pFilter list is empty")); + + if (aPosition >= m->llDeviceFilters->size()) + return setError(E_INVALIDARG, + tr("Invalid position: %lu (must be in range [0, %lu])"), + aPosition, m->llDeviceFilters->size() - 1); + + /* backup the list before modification */ + m->llDeviceFilters.backup(); + + ComObjPtr pFilter; + { + /* iterate to the position... */ + DeviceFilterList::iterator it = m->llDeviceFilters->begin(); + std::advance(it, aPosition); + /* ...get an element from there... */ + pFilter = *it; + /* ...and remove */ + pFilter->mInList = false; + m->llDeviceFilters->erase(it); + } + + /* cancel sharing (make an independent copy of data) */ + pFilter->unshare(); + + pFilter.queryInterfaceTo(aFilter); + + /* notify the proxy (only when it makes sense) */ + if (pFilter->getData().mActive && Global::IsOnline(adep.machineState()) + && pFilter->getData().mRemote.isMatch(false)) + { + USBProxyService *pProxySvc = m->pHost->usbProxyService(); + ComAssertRet(pProxySvc, E_FAIL); + + ComAssertRet(pFilter->getId() != NULL, E_FAIL); + pProxySvc->removeFilter(pFilter->getId()); + pFilter->getId() = NULL; + } + + alock.release(); + AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); + m->pParent->setModified(Machine::IsModified_USB); + mlock.release(); + + return S_OK; + +#else /* VBOX_WITH_USB */ + + NOREF(aPosition); + NOREF(aFilter); + ReturnComNotImplemented(); + +#endif /* VBOX_WITH_USB */ +} + +// public methods only for internal purposes +///////////////////////////////////////////////////////////////////////////// + +/** + * Loads settings from the given machine node. + * May be called once right after this object creation. + * + * @param aMachineNode node. + * + * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either. + */ +HRESULT USBDeviceFilters::loadSettings(const settings::USB &data) +{ + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + /* Note: we assume that the default values for attributes of optional + * nodes are assigned in the Data::Data() constructor and don't do it + * here. It implies that this method may only be called after constructing + * a new USBDeviceFilters object while all its data fields are in the default + * values. Exceptions are fields whose creation time defaults don't match + * values that should be applied when these fields are not explicitly set + * in the settings file (for backwards compatibility reasons). This takes + * place when a setting of a newly created object must default to A while + * the same setting of an object loaded from the old settings file must + * default to B. */ + +#ifdef VBOX_WITH_USB + for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin(); + it != data.llDeviceFilters.end(); + ++it) + { + const settings::USBDeviceFilter &f = *it; + ComObjPtr pFilter; + pFilter.createObject(); + HRESULT rc = pFilter->init(this, // parent + f); + if (FAILED(rc)) return rc; + + m->llDeviceFilters->push_back(pFilter); + pFilter->mInList = true; + } +#endif /* VBOX_WITH_USB */ + + return S_OK; +} + +/** + * Saves settings to the given machine node. + * + * @param aMachineNode node. + * + * @note Locks this object for reading. + */ +HRESULT USBDeviceFilters::saveSettings(settings::USB &data) +{ + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + data.llDeviceFilters.clear(); + + for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + it != m->llDeviceFilters->end(); + ++it) + { + AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); + const USBDeviceFilter::Data &filterData = (*it)->getData(); + + Bstr str; + + settings::USBDeviceFilter f; + f.strName = filterData.mName; + f.fActive = !!filterData.mActive; + (*it)->COMGETTER(VendorId)(str.asOutParam()); + f.strVendorId = str; + (*it)->COMGETTER(ProductId)(str.asOutParam()); + f.strProductId = str; + (*it)->COMGETTER(Revision)(str.asOutParam()); + f.strRevision = str; + (*it)->COMGETTER(Manufacturer)(str.asOutParam()); + f.strManufacturer = str; + (*it)->COMGETTER(Product)(str.asOutParam()); + f.strProduct = str; + (*it)->COMGETTER(SerialNumber)(str.asOutParam()); + f.strSerialNumber = str; + (*it)->COMGETTER(Port)(str.asOutParam()); + f.strPort = str; + f.strRemote = filterData.mRemote.string(); + f.ulMaskedInterfaces = filterData.mMaskedIfs; + + data.llDeviceFilters.push_back(f); + } +#endif /* VBOX_WITH_USB */ + + return S_OK; +} + +/** @note Locks objects for writing! */ +void USBDeviceFilters::rollback() +{ + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); + + /* we need the machine state */ + AutoAnyStateDependency adep(m->pParent); + AssertComRCReturnVoid(adep.rc()); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + + if (m->llDeviceFilters.isBackedUp()) + { + USBProxyService *pProxySvc = m->pHost->usbProxyService(); + Assert(pProxySvc); + + /* uninitialize all new filters (absent in the backed up list) */ + DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + DeviceFilterList *backedList = m->llDeviceFilters.backedUpData(); + while (it != m->llDeviceFilters->end()) + { + if (std::find(backedList->begin(), backedList->end(), *it) == + backedList->end()) + { + /* notify the proxy (only when it makes sense) */ + if ((*it)->getData().mActive && + Global::IsOnline(adep.machineState()) + && (*it)->getData().mRemote.isMatch(false)) + { + USBDeviceFilter *pFilter = *it; + Assert(pFilter->getId() != NULL); + pProxySvc->removeFilter(pFilter->getId()); + pFilter->getId() = NULL; + } + + (*it)->uninit(); + } + ++it; + } + + if (Global::IsOnline(adep.machineState())) + { + /* find all removed old filters (absent in the new list) + * and insert them back to the USB proxy */ + it = backedList->begin(); + while (it != backedList->end()) + { + if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) == + m->llDeviceFilters->end()) + { + /* notify the proxy (only when necessary) */ + if ((*it)->getData().mActive + && (*it)->getData().mRemote.isMatch(false)) + { + USBDeviceFilter *pFilter = *it; /* resolve ambiguity */ + Assert(pFilter->getId() == NULL); + pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter); + } + } + ++it; + } + } + + /* restore the list */ + m->llDeviceFilters.rollback(); + } + + /* here we don't depend on the machine state any more */ + adep.release(); + + /* rollback any changes to filters after restoring the list */ + DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + while (it != m->llDeviceFilters->end()) + { + if ((*it)->isModified()) + { + (*it)->rollback(); + /* call this to notify the USB proxy about changes */ + onDeviceFilterChange(*it); + } + ++it; + } + +#endif /* VBOX_WITH_USB */ +} + +/** + * @note Locks this object for writing, together with the peer object (also + * for writing) if there is one. + */ +void USBDeviceFilters::commit() +{ + /* sanity */ + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); + + /* sanity too */ + AutoCaller peerCaller(m->pPeer); + AssertComRCReturnVoid(peerCaller.rc()); + + /* lock both for writing since we modify both (mPeer is "master" so locked + * first) */ + AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + bool commitFilters = false; + + if (m->llDeviceFilters.isBackedUp()) + { + m->llDeviceFilters.commit(); + + /* apply changes to peer */ + if (m->pPeer) + { + AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS); + + /* commit all changes to new filters (this will reshare data with + * peers for those who have peers) */ + DeviceFilterList *newList = new DeviceFilterList(); + DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + while (it != m->llDeviceFilters->end()) + { + (*it)->commit(); + + /* look if this filter has a peer filter */ + ComObjPtr peer = (*it)->peer(); + if (!peer) + { + /* no peer means the filter is a newly created one; + * create a peer owning data this filter share it with */ + peer.createObject(); + peer->init(m->pPeer, *it, true /* aReshare */); + } + else + { + /* remove peer from the old list */ + m->pPeer->m->llDeviceFilters->remove(peer); + } + /* and add it to the new list */ + newList->push_back(peer); + + ++it; + } + + /* uninit old peer's filters that are left */ + it = m->pPeer->m->llDeviceFilters->begin(); + while (it != m->pPeer->m->llDeviceFilters->end()) + { + (*it)->uninit(); + ++it; + } + + /* attach new list of filters to our peer */ + m->pPeer->m->llDeviceFilters.attach(newList); + } + else + { + /* we have no peer (our parent is the newly created machine); + * just commit changes to filters */ + commitFilters = true; + } + } + else + { + /* the list of filters itself is not changed, + * just commit changes to filters themselves */ + commitFilters = true; + } + + if (commitFilters) + { + DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + while (it != m->llDeviceFilters->end()) + { + (*it)->commit(); + ++it; + } + } +#endif /* VBOX_WITH_USB */ +} + +/** + * @note Locks this object for writing, together with the peer object + * represented by @a aThat (locked for reading). + */ +void USBDeviceFilters::copyFrom(USBDeviceFilters *aThat) +{ + AssertReturnVoid(aThat != NULL); + + /* sanity */ + AutoCaller autoCaller(this); + AssertComRCReturnVoid(autoCaller.rc()); + + /* sanity too */ + AutoCaller thatCaller(aThat); + AssertComRCReturnVoid(thatCaller.rc()); + + /* even more sanity */ + AutoAnyStateDependency adep(m->pParent); + AssertComRCReturnVoid(adep.rc()); + /* Machine::copyFrom() may not be called when the VM is running */ + AssertReturnVoid(!Global::IsOnline(adep.machineState())); + + /* peer is not modified, lock it for reading (aThat is "master" so locked + * first) */ + AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS); + AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS); + +#ifdef VBOX_WITH_USB + + /* Note that we won't inform the USB proxy about new filters since the VM is + * not running when we are here and therefore no need to do so */ + + /* create private copies of all filters */ + m->llDeviceFilters.backup(); + m->llDeviceFilters->clear(); + for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin(); + it != aThat->m->llDeviceFilters->end(); + ++it) + { + ComObjPtr pFilter; + pFilter.createObject(); + pFilter->initCopy(this, *it); + m->llDeviceFilters->push_back(pFilter); + } + +#endif /* VBOX_WITH_USB */ +} + +#ifdef VBOX_WITH_USB + +/** + * Called by setter methods of all USB device filters. + * + * @note Locks nothing. + */ +HRESULT USBDeviceFilters::onDeviceFilterChange(USBDeviceFilter *aFilter, + BOOL aActiveChanged /* = FALSE */) +{ + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + /* we need the machine state */ + AutoAnyStateDependency adep(m->pParent); + AssertComRCReturnRC(adep.rc()); + + /* nothing to do if the machine isn't running */ + if (!Global::IsOnline(adep.machineState())) + return S_OK; + + /* we don't modify our data fields -- no need to lock */ + + if ( aFilter->mInList + && m->pParent->isRegistered()) + { + USBProxyService *pProxySvc = m->pHost->usbProxyService(); + ComAssertRet(pProxySvc, E_FAIL); + + if (aActiveChanged) + { + if (aFilter->getData().mRemote.isMatch(false)) + { + /* insert/remove the filter from the proxy */ + if (aFilter->getData().mActive) + { + ComAssertRet(aFilter->getId() == NULL, E_FAIL); + aFilter->getId() = pProxySvc->insertFilter(&aFilter->getData().mUSBFilter); + } + else + { + ComAssertRet(aFilter->getId() != NULL, E_FAIL); + pProxySvc->removeFilter(aFilter->getId()); + aFilter->getId() = NULL; + } + } + } + else + { + if (aFilter->getData().mActive) + { + /* update the filter in the proxy */ + ComAssertRet(aFilter->getId() != NULL, E_FAIL); + pProxySvc->removeFilter(aFilter->getId()); + if (aFilter->getData().mRemote.isMatch(false)) + { + aFilter->getId() = pProxySvc->insertFilter(&aFilter->getData().mUSBFilter); + } + } + } + } + + return S_OK; +} + +/** + * Returns true if the given USB device matches to at least one of + * this controller's USB device filters. + * + * A HostUSBDevice specific version. + * + * @note Locks this object for reading. + */ +bool USBDeviceFilters::hasMatchingFilter(const ComObjPtr &aDevice, ULONG *aMaskedIfs) +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), false); + + /* It is not possible to work with USB device if there is no USB controller present. */ + if (!m->pParent->isUSBControllerPresent()) + return false; + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* apply self filters */ + for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + it != m->llDeviceFilters->end(); + ++it) + { + AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); + if (aDevice->isMatch((*it)->getData())) + { + *aMaskedIfs = (*it)->getData().mMaskedIfs; + return true; + } + } + + return false; +} + +/** + * Returns true if the given USB device matches to at least one of + * this controller's USB device filters. + * + * A generic version that accepts any IUSBDevice on input. + * + * @note + * This method MUST correlate with HostUSBDevice::isMatch() + * in the sense of the device matching logic. + * + * @note Locks this object for reading. + */ +bool USBDeviceFilters::hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs) +{ + LogFlowThisFuncEnter(); + + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), false); + + /* It is not possible to work with USB device if there is no USB controller present. */ + if (!m->pParent->isUSBControllerPresent()) + return false; + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = S_OK; + + /* query fields */ + USBFILTER dev; + USBFilterInit(&dev, USBFILTERTYPE_CAPTURE); + + USHORT vendorId = 0; + rc = aUSBDevice->COMGETTER(VendorId)(&vendorId); + ComAssertComRCRet(rc, false); + ComAssertRet(vendorId, false); + int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc); + + USHORT productId = 0; + rc = aUSBDevice->COMGETTER(ProductId)(&productId); + ComAssertComRCRet(rc, false); + vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc); + + USHORT revision; + rc = aUSBDevice->COMGETTER(Revision)(&revision); + ComAssertComRCRet(rc, false); + vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc); + + Bstr manufacturer; + rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam()); + ComAssertComRCRet(rc, false); + if (!manufacturer.isEmpty()) + USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true); + + Bstr product; + rc = aUSBDevice->COMGETTER(Product)(product.asOutParam()); + ComAssertComRCRet(rc, false); + if (!product.isEmpty()) + USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true); + + Bstr serialNumber; + rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam()); + ComAssertComRCRet(rc, false); + if (!serialNumber.isEmpty()) + USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true); + + Bstr address; + rc = aUSBDevice->COMGETTER(Address)(address.asOutParam()); + ComAssertComRCRet(rc, false); + + USHORT port = 0; + rc = aUSBDevice->COMGETTER(Port)(&port); + ComAssertComRCRet(rc, false); + USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true); + + BOOL remote = FALSE; + rc = aUSBDevice->COMGETTER(Remote)(&remote); + ComAssertComRCRet(rc, false); + ComAssertRet(remote == TRUE, false); + + bool match = false; + + /* apply self filters */ + for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + it != m->llDeviceFilters->end(); + ++it) + { + AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); + const USBDeviceFilter::Data &aData = (*it)->getData(); + + if (!aData.mActive) + continue; + if (!aData.mRemote.isMatch(remote)) + continue; + if (!USBFilterMatch(&aData.mUSBFilter, &dev)) + continue; + + match = true; + *aMaskedIfs = aData.mMaskedIfs; + break; + } + + LogFlowThisFunc(("returns: %d\n", match)); + LogFlowThisFuncLeave(); + + return match; +} + +/** + * Notifies the proxy pProxySvc about all filters as requested by the + * @a aInsertFilters argument. + * + * @param aInsertFilters @c true to insert filters, @c false to remove. + * + * @note Locks this object for reading. + */ +HRESULT USBDeviceFilters::notifyProxy(bool aInsertFilters) +{ + LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters)); + + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), false); + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + USBProxyService *pProxySvc = m->pHost->usbProxyService(); + AssertReturn(pProxySvc, E_FAIL); + + DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); + while (it != m->llDeviceFilters->end()) + { + USBDeviceFilter *pFilter = *it; /* resolve ambiguity (for ComPtr below) */ + + /* notify the proxy (only if the filter is active) */ + if ( pFilter->getData().mActive + && pFilter->getData().mRemote.isMatch(false) /* and if the filter is NOT remote */ + ) + { + if (aInsertFilters) + { + AssertReturn(pFilter->getId() == NULL, E_FAIL); + pFilter->getId() = pProxySvc->insertFilter(&pFilter->getData().mUSBFilter); + } + else + { + /* It's possible that the given filter was not inserted the proxy + * when this method gets called (as a result of an early VM + * process crash for example. So, don't assert that ID != NULL. */ + if (pFilter->getId() != NULL) + { + pProxySvc->removeFilter(pFilter->getId()); + pFilter->getId() = NULL; + } + } + } + ++it; + } + + return S_OK; +} + +Machine* USBDeviceFilters::getMachine() +{ + return m->pParent; +} + +#endif /* VBOX_WITH_USB */ + +// private methods +///////////////////////////////////////////////////////////////////////////// +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/VFSExplorerImpl.cpp b/src/VBox/Main/src-server/VFSExplorerImpl.cpp index e94b7225..9f50b667 100644 --- a/src/VBox/Main/src-server/VFSExplorerImpl.cpp +++ b/src/VBox/Main/src-server/VFSExplorerImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -622,7 +622,7 @@ STDMETHODIMP VFSExplorer::CdUp(IProgress **aProgress) return Cd(Bstr(strUpPath).raw(), aProgress); } -STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(ULONG, aSizes), ComSafeArrayOut(ULONG, aModes)) +STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes), ComSafeArrayOut(LONG64, aSizes), ComSafeArrayOut(ULONG, aModes)) { if (ComSafeArrayOutIsNull(aNames) || ComSafeArrayOutIsNull(aTypes)) @@ -635,7 +635,7 @@ STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayO com::SafeArray sfaNames(m->entryList.size()); com::SafeArray sfaTypes(m->entryList.size()); - com::SafeArray sfaSizes(m->entryList.size()); + com::SafeArray sfaSizes(m->entryList.size()); com::SafeArray sfaModes(m->entryList.size()); std::list::const_iterator it; diff --git a/src/VBox/Main/src-server/VRDEServerImpl.cpp b/src/VBox/Main/src-server/VRDEServerImpl.cpp index 5862545a..a717affe 100644 --- a/src/VBox/Main/src-server/VRDEServerImpl.cpp +++ b/src/VBox/Main/src-server/VRDEServerImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,6 +29,7 @@ #include #include +#include #include @@ -72,7 +73,7 @@ void VRDEServer::FinalRelease() * * @param aParent Handle of the parent object. */ -HRESULT VRDEServer::init (Machine *aParent) +HRESULT VRDEServer::init(Machine *aParent) { LogFlowThisFunc(("aParent=%p\n", aParent)); @@ -111,7 +112,7 @@ HRESULT VRDEServer::init (Machine *aParent) * * @note Locks @a aThat object for reading. */ -HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat) +HRESULT VRDEServer::init(Machine *aParent, VRDEServer *aThat) { LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat)); @@ -124,11 +125,11 @@ HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat) unconst(mParent) = aParent; unconst(mPeer) = aThat; - AutoCaller thatCaller (aThat); + AutoCaller thatCaller(aThat); AssertComRCReturnRC(thatCaller.rc()); AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS); - mData.share (aThat->mData); + mData.share(aThat->mData); /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -143,7 +144,7 @@ HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat) * * @note Locks @a aThat object for reading. */ -HRESULT VRDEServer::initCopy (Machine *aParent, VRDEServer *aThat) +HRESULT VRDEServer::initCopy(Machine *aParent, VRDEServer *aThat) { LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat)); @@ -156,11 +157,11 @@ HRESULT VRDEServer::initCopy (Machine *aParent, VRDEServer *aThat) unconst(mParent) = aParent; /* mPeer is left null */ - AutoCaller thatCaller (aThat); + AutoCaller thatCaller(aThat); AssertComRCReturnRC(thatCaller.rc()); AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS); - mData.attachCopy (aThat->mData); + mData.attachCopy(aThat->mData); /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -245,7 +246,7 @@ HRESULT VRDEServer::saveSettings(settings::VRDESettings &data) // IVRDEServer properties ///////////////////////////////////////////////////////////////////////////// -STDMETHODIMP VRDEServer::COMGETTER(Enabled) (BOOL *aEnabled) +STDMETHODIMP VRDEServer::COMGETTER(Enabled)(BOOL *aEnabled) { CheckComArgOutPointerValid(aEnabled); @@ -257,17 +258,19 @@ STDMETHODIMP VRDEServer::COMGETTER(Enabled) (BOOL *aEnabled) return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(Enabled) (BOOL aEnabled) +STDMETHODIMP VRDEServer::COMSETTER(Enabled)(BOOL aEnabled) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* the machine can also be in saved state for this property to change */ - AutoMutableOrSavedStateDependency adep (mParent); + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + HRESULT rc = S_OK; + if (mData->mEnabled != aEnabled) { mData.backup(); @@ -283,10 +286,10 @@ STDMETHODIMP VRDEServer::COMSETTER(Enabled) (BOOL aEnabled) /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */ adep.release(); - mParent->onVRDEServerChange(/* aRestart */ TRUE); + rc = mParent->onVRDEServerChange(/* aRestart */ TRUE); } - return S_OK; + return rc; } static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd) @@ -373,15 +376,15 @@ static int vrdpServerVerifyPortsString(Bstr ports) return VINF_SUCCESS; } -STDMETHODIMP VRDEServer::SetVRDEProperty (IN_BSTR aKey, IN_BSTR aValue) +STDMETHODIMP VRDEServer::SetVRDEProperty(IN_BSTR aKey, IN_BSTR aValue) { LogFlowThisFunc(("\n")); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* The machine needs to be mutable. */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); Bstr key = aKey; @@ -460,7 +463,7 @@ STDMETHODIMP VRDEServer::SetVRDEProperty (IN_BSTR aKey, IN_BSTR aValue) return S_OK; } -STDMETHODIMP VRDEServer::GetVRDEProperty (IN_BSTR aKey, BSTR *aValue) +STDMETHODIMP VRDEServer::GetVRDEProperty(IN_BSTR aKey, BSTR *aValue) { CheckComArgOutPointerValid(aValue); @@ -627,7 +630,7 @@ STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProper return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(AuthType) (AuthType_T *aType) +STDMETHODIMP VRDEServer::COMGETTER(AuthType)(AuthType_T *aType) { CheckComArgOutPointerValid(aType); @@ -641,13 +644,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthType) (AuthType_T *aType) return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(AuthType) (AuthType_T aType) +STDMETHODIMP VRDEServer::COMSETTER(AuthType)(AuthType_T aType) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -670,7 +673,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthType) (AuthType_T aType) return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout) (ULONG *aTimeout) +STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout)(ULONG *aTimeout) { CheckComArgOutPointerValid(aTimeout); @@ -684,13 +687,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout) (ULONG *aTimeout) return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout) (ULONG aTimeout) +STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout)(ULONG aTimeout) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -717,7 +720,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout) (ULONG aTimeout) return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary) +STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary)(BSTR *aLibrary) { CheckComArgOutPointerValid(aLibrary); @@ -748,13 +751,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary) return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary) (IN_BSTR aLibrary) +STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary)(IN_BSTR aLibrary) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); Bstr bstrLibrary(aLibrary); @@ -779,8 +782,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary) (IN_BSTR aLibrary) return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection) ( - BOOL *aAllowMultiConnection) +STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection)(BOOL *aAllowMultiConnection) { CheckComArgOutPointerValid(aAllowMultiConnection); @@ -794,14 +796,13 @@ STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection) ( return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection) ( - BOOL aAllowMultiConnection) +STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection)(BOOL aAllowMultiConnection) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -824,8 +825,7 @@ STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection) ( return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection) ( - BOOL *aReuseSingleConnection) +STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection)(BOOL *aReuseSingleConnection) { CheckComArgOutPointerValid(aReuseSingleConnection); @@ -839,14 +839,13 @@ STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection) ( return S_OK; } -STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection) ( - BOOL aReuseSingleConnection) +STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection)(BOOL aReuseSingleConnection) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -869,7 +868,7 @@ STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection) ( return S_OK; } -STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack) (BSTR *aExtPack) +STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack)(BSTR *aExtPack) { CheckComArgOutPointerValid(aExtPack); @@ -919,8 +918,8 @@ STDMETHODIMP VRDEServer::COMSETTER(VRDEExtPack)(IN_BSTR aExtPack) HRESULT hrc = autoCaller.rc(); if (SUCCEEDED(hrc)) { - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(mParent); + /* the machine can also be in saved state for this property to change */ + AutoMutableOrSavedStateDependency adep(mParent); hrc = adep.rc(); if (SUCCEEDED(hrc)) { @@ -994,11 +993,11 @@ void VRDEServer::commit() { /* sanity */ AutoCaller autoCaller(this); - AssertComRCReturnVoid (autoCaller.rc()); + AssertComRCReturnVoid(autoCaller.rc()); /* sanity too */ - AutoCaller peerCaller (mPeer); - AssertComRCReturnVoid (peerCaller.rc()); + AutoCaller peerCaller(mPeer); + AssertComRCReturnVoid(peerCaller.rc()); /* lock both for writing since we modify both (mPeer is "master" so locked * first) */ @@ -1010,7 +1009,7 @@ void VRDEServer::commit() if (mPeer) { /* attach new data to the peer and reshare it */ - mPeer->mData.attach (mData); + mPeer->mData.attach(mData); } } } @@ -1019,17 +1018,17 @@ void VRDEServer::commit() * @note Locks this object for writing, together with the peer object * represented by @a aThat (locked for reading). */ -void VRDEServer::copyFrom (VRDEServer *aThat) +void VRDEServer::copyFrom(VRDEServer *aThat) { - AssertReturnVoid (aThat != NULL); + AssertReturnVoid(aThat != NULL); /* sanity */ AutoCaller autoCaller(this); - AssertComRCReturnVoid (autoCaller.rc()); + AssertComRCReturnVoid(autoCaller.rc()); /* sanity too */ - AutoCaller thatCaller (aThat); - AssertComRCReturnVoid (thatCaller.rc()); + AutoCaller thatCaller(aThat); + AssertComRCReturnVoid(thatCaller.rc()); /* peer is not modified, lock it for reading (aThat is "master" so locked * first) */ @@ -1037,6 +1036,6 @@ void VRDEServer::copyFrom (VRDEServer *aThat) AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS); /* this will back up current data */ - mData.assignCopy (aThat->mData); + mData.assignCopy(aThat->mData); } /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/VirtualBoxImpl.cpp b/src/VBox/Main/src-server/VirtualBoxImpl.cpp index 64135154..7c319236 100644 --- a/src/VBox/Main/src-server/VirtualBoxImpl.cpp +++ b/src/VBox/Main/src-server/VirtualBoxImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -35,6 +35,7 @@ #include #include #include "VBox/com/EventQueue.h" +#include "VBox/com/MultiResult.h" #include #include @@ -60,8 +61,9 @@ #include "USBControllerImpl.h" #include "SystemPropertiesImpl.h" #include "GuestOSTypeImpl.h" -#include "DHCPServerRunner.h" +#include "NetworkServiceRunner.h" #include "DHCPServerImpl.h" +#include "NATNetworkImpl.h" #ifdef VBOX_WITH_RESOURCE_USAGE_API # include "PerformanceImpl.h" #endif /* VBOX_WITH_RESOURCE_USAGE_API */ @@ -71,10 +73,10 @@ # include "ExtPackManagerImpl.h" #endif #include "AutostartDb.h" +#include "ClientWatcher.h" #include "AutoCaller.h" #include "Logging.h" -#include "objectslist.h" #ifdef RT_OS_WINDOWS # include "win/svchlp.h" @@ -110,12 +112,11 @@ Bstr VirtualBox::sPackageType; // static Bstr VirtualBox::sAPIVersion; -#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER -/** Table for adaptive timeouts in the client watcher. The counter starts at - * the maximum value and decreases to 0. */ -static const RTMSINTERVAL s_updateAdaptTimeouts[] = { 500, 200, 100, 50, 20, 10, 5 }; -#endif +// static +std::map VirtualBox::sNatNetworkNameToRefCount; +// static leaked (todo: find better place to free it.) +RWLockHandle *VirtualBox::spMtxNatNetworkNameToRefCountLock; //////////////////////////////////////////////////////////////////////////////// // // CallbackEvent class @@ -163,24 +164,11 @@ protected: // //////////////////////////////////////////////////////////////////////////////// -#if defined(RT_OS_WINDOWS) - #define UPDATEREQARG NULL - #define UPDATEREQTYPE HANDLE -#elif defined(RT_OS_OS2) - #define UPDATEREQARG NIL_RTSEMEVENT - #define UPDATEREQTYPE RTSEMEVENT -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - #define UPDATEREQARG - #define UPDATEREQTYPE RTSEMEVENT -#else -# error "Port me!" -#endif - -typedef ObjectsList MachinesOList; typedef ObjectsList MediaOList; typedef ObjectsList GuestOSTypesOList; typedef ObjectsList SharedFoldersOList; typedef ObjectsList DHCPServersOList; +typedef ObjectsList NATNetworksOList; typedef std::map > ProgressMap; typedef std::map > HardDiskMap; @@ -208,9 +196,10 @@ struct VirtualBox::Data allSharedFolders(lockSharedFolders), lockDHCPServers(LOCKCLASS_LISTOFOTHEROBJECTS), allDHCPServers(lockDHCPServers), + lockNATNetworks(LOCKCLASS_LISTOFOTHEROBJECTS), + allNATNetworks(lockNATNetworks), mtxProgressOperations(LOCKCLASS_PROGRESSLIST), - updateReq(UPDATEREQARG), - threadClientWatcher(NIL_RTTHREAD), + pClientWatcher(NULL), threadAsyncEvent(NIL_RTTHREAD), pAsyncEventQ(NULL), pAutostartDb(NULL), @@ -286,17 +275,13 @@ struct VirtualBox::Data RWLockHandle lockDHCPServers; DHCPServersOList allDHCPServers; + RWLockHandle lockNATNetworks; + NATNetworksOList allNATNetworks; + RWLockHandle mtxProgressOperations; ProgressMap mapProgressOperations; - // the following are data for the client watcher thread - const UPDATEREQTYPE updateReq; -#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER - uint8_t updateAdaptCtr; -#endif - const RTTHREAD threadClientWatcher; - typedef std::list ProcessList; - ProcessList llProcesses; + ClientWatcher * const pClientWatcher; // the following are data for the async event thread const RTTHREAD threadAsyncEvent; @@ -385,6 +370,9 @@ HRESULT VirtualBox::init() sPackageType = VBOX_PACKAGE_STRING; if (sAPIVersion.isEmpty()) sAPIVersion = VBOX_API_VERSION_STRING; + if (!spMtxNatNetworkNameToRefCountLock) + spMtxNatNetworkNameToRefCountLock = new RWLockHandle(LOCKCLASS_VIRTUALBOXOBJECT); + LogFlowThisFunc(("Version: %ls, Package: %ls, API Version: %ls\n", sVersion.raw(), sPackageType.raw(), sAPIVersion.raw())); /* Get the VirtualBox home directory. */ @@ -485,7 +473,7 @@ HRESULT VirtualBox::init() dumpAllBackRefs(); #endif - /* net services */ + /* net services - dhcp services */ for (settings::DHCPServersList::const_iterator it = m->pMainConfigFile->llDhcpServers.begin(); it != m->pMainConfigFile->llDhcpServers.end(); ++it) @@ -501,9 +489,27 @@ HRESULT VirtualBox::init() if (FAILED(rc)) throw rc; } + /* net services - nat networks */ + for (settings::NATNetworksList::const_iterator it = m->pMainConfigFile->llNATNetworks.begin(); + it != m->pMainConfigFile->llNATNetworks.end(); + ++it) + { + const settings::NATNetwork &net = *it; + + ComObjPtr pNATNetwork; + if (SUCCEEDED(rc = pNATNetwork.createObject())) + { + rc = pNATNetwork->init(this, net); + AssertComRCReturnRC(rc); + } + + rc = registerNATNetwork(pNATNetwork, false /* aSaveRegistry */); + AssertComRCReturnRC(rc); + } + /* events */ if (SUCCEEDED(rc = unconst(m->pEventSource).createObject())) - rc = m->pEventSource->init(static_cast(this)); + rc = m->pEventSource->init(); if (FAILED(rc)) throw rc; #ifdef VBOX_WITH_EXTPACK @@ -527,27 +533,21 @@ HRESULT VirtualBox::init() if (SUCCEEDED(rc)) { - /* start the client watcher thread */ -#if defined(RT_OS_WINDOWS) - unconst(m->updateReq) = ::CreateEvent(NULL, FALSE, FALSE, NULL); -#elif defined(RT_OS_OS2) - RTSemEventCreate(&unconst(m->updateReq)); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - RTSemEventCreate(&unconst(m->updateReq)); - ASMAtomicUoWriteU8(&m->updateAdaptCtr, 0); -#else -# error "Port me!" -#endif - int vrc = RTThreadCreate(&unconst(m->threadClientWatcher), - ClientWatcher, - (void *)this, - 0, - RTTHREADTYPE_MAIN_WORKER, - RTTHREADFLAGS_WAITABLE, - "Watcher"); - ComAssertRC(vrc); - if (RT_FAILURE(vrc)) - rc = E_FAIL; + /* set up client monitoring */ + try + { + unconst(m->pClientWatcher) = new ClientWatcher(this); + if (!m->pClientWatcher->isReady()) + { + delete m->pClientWatcher; + unconst(m->pClientWatcher) = NULL; + rc = E_FAIL; + } + } + catch (std::bad_alloc &) + { + rc = E_OUTOFMEMORY; + } } if (SUCCEEDED(rc)) @@ -807,41 +807,20 @@ void VirtualBox::uninit() LogFlowThisFunc(("Releasing event source...\n")); if (m->pEventSource) { - // we don't perform uninit() as it's possible that some pending event refers to this source + // Must uninit the event source here, because it makes no sense that + // it survives longer than the base object. If someone gets an event + // with such an event source then that's life and it has to be dealt + // with appropriately on the API client side. + m->pEventSource->uninit(); unconst(m->pEventSource).setNull(); } LogFlowThisFunc(("Terminating the client watcher...\n")); - if (m->threadClientWatcher != NIL_RTTHREAD) - { - /* signal the client watcher thread */ - updateClientWatcher(); - /* wait for the termination */ - RTThreadWait(m->threadClientWatcher, RT_INDEFINITE_WAIT, NULL); - unconst(m->threadClientWatcher) = NIL_RTTHREAD; - } - m->llProcesses.clear(); -#if defined(RT_OS_WINDOWS) - if (m->updateReq != NULL) - { - ::CloseHandle(m->updateReq); - unconst(m->updateReq) = NULL; - } -#elif defined(RT_OS_OS2) - if (m->updateReq != NIL_RTSEMEVENT) + if (m->pClientWatcher) { - RTSemEventDestroy(m->updateReq); - unconst(m->updateReq) = NIL_RTSEMEVENT; + delete m->pClientWatcher; + unconst(m->pClientWatcher) = NULL; } -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - if (m->updateReq != NIL_RTSEMEVENT) - { - RTSemEventDestroy(m->updateReq); - unconst(m->updateReq) = NIL_RTSEMEVENT; - } -#else -# error "Port me!" -#endif delete m->pAutostartDb; @@ -1129,6 +1108,7 @@ VirtualBox::COMGETTER(PerformanceCollector)(IPerformanceCollector **aPerformance return S_OK; #else /* !VBOX_WITH_RESOURCE_USAGE_API */ + NOREF(aPerformanceCollector); ReturnComNotImplemented(); #endif /* !VBOX_WITH_RESOURCE_USAGE_API */ } @@ -1148,6 +1128,31 @@ VirtualBox::COMGETTER(DHCPServers)(ComSafeArrayOut(IDHCPServer *, aDHCPServers)) return S_OK; } + +STDMETHODIMP +VirtualBox::COMGETTER(NATNetworks)(ComSafeArrayOut(INATNetwork *, aNATNetworks)) +{ +#ifdef VBOX_WITH_NAT_SERVICE + CheckComArgOutSafeArrayPointerValid(aNATNetworks); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + AutoReadLock al(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS); + SafeIfaceArray nets(m->allNATNetworks.getList()); + nets.detachTo(ComSafeArrayOutArg(aNATNetworks)); + + return S_OK; +#else + NOREF(aNATNetworks); +# ifndef RT_OS_WINDOWS + NOREF(aNATNetworksSize); +# endif + return E_NOTIMPL; +#endif +} + + STDMETHODIMP VirtualBox::COMGETTER(EventSource)(IEventSource ** aEventSource) { @@ -1452,8 +1457,16 @@ STDMETHODIMP VirtualBox::ComposeMachineFilename(IN_BSTR aName, pcszNext += strFlag.length() + 1; } } - if (id.isEmpty()) + + if (id.isZero()) fDirectoryIncludesUUID = false; + else if (!id.isValid()) + { + /* do something else */ + return setError(E_INVALIDARG, + tr("'%ls' is not a valid Guid"), + id.toStringCurly().c_str()); + } Utf8Str strGroup(aGroup); if (strGroup.isEmpty()) @@ -1514,13 +1527,13 @@ void sanitiseMachineFilename(Utf8Str &strName) * *nix, or be otherwise difficult for shells to handle (I would have * preferred to remove the space and brackets too). We also remove all * characters which need UTF-16 surrogate pairs for Windows's benefit. */ -#ifdef RT_STRICT RTUNICP aCpSet[] = { ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_', 0xa0, 0xd7af, '\0' }; -#endif char *pszName = strName.mutableRaw(); - Assert(RTStrPurgeComplementSet(pszName, aCpSet, '_') >= 0); + int cReplacements = RTStrPurgeComplementSet(pszName, aCpSet, '_'); + Assert(cReplacements >= 0); + NOREF(cReplacements); /* No leading dot or dash. */ if (pszName[0] == '.' || pszName[0] == '-') pszName[0] = '_'; @@ -1648,8 +1661,15 @@ STDMETHODIMP VirtualBox::CreateMachine(IN_BSTR aSettingsFile, } } /* Create UUID if none was specified. */ - if (id.isEmpty()) + if (id.isZero()) id.create(); + else if (!id.isValid()) + { + /* do something else */ + return setError(E_INVALIDARG, + tr("'%ls' is not a valid Guid"), + id.toStringCurly().c_str()); + } /* NULL settings file means compose automatically */ Bstr bstrSettingsFile(aSettingsFile); @@ -1779,7 +1799,8 @@ STDMETHODIMP VirtualBox::FindMachine(IN_BSTR aNameOrId, IMachine **aMachine) ComObjPtr pMachineFound; Guid id(aNameOrId); - if (!id.isEmpty()) + if (id.isValid() && !id.isZero()) + rc = findMachine(id, true /* fPermitInaccessible */, true /* setError */, @@ -1939,6 +1960,7 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation, AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); + Guid id(aLocation); ComObjPtr pMedium; // have to get write lock as the whole find/update sequence must be done @@ -1951,18 +1973,22 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation, switch (deviceType) { case DeviceType_HardDisk: - rc = findHardDiskByLocation(aLocation, - false, /* aSetError */ - &pMedium); + if (id.isValid() && !id.isZero()) + rc = findHardDiskById(id, false /* setError */, &pMedium); + else + rc = findHardDiskByLocation(aLocation, + false, /* aSetError */ + &pMedium); break; case DeviceType_Floppy: case DeviceType_DVD: - rc = findDVDOrFloppyImage(deviceType, - NULL, /* guid */ - aLocation, - false, /* aSetError */ - &pMedium); + if (id.isValid() && !id.isZero()) + rc = findDVDOrFloppyImage(deviceType, &id, Utf8Str::Empty, + false /* setError */, &pMedium); + else + rc = findDVDOrFloppyImage(deviceType, NULL, aLocation, + false /* setError */, &pMedium); // enforce read-only for DVDs even if caller specified ReadWrite if (deviceType == DeviceType_DVD) @@ -1973,7 +1999,6 @@ STDMETHODIMP VirtualBox::OpenMedium(IN_BSTR aLocation, return setError(E_INVALIDARG, "Device type must be HardDisk, DVD or Floppy %d", deviceType); } - if (pMedium.isNull()) { pMedium.createObject(); @@ -2768,7 +2793,7 @@ VirtualBox::SVCHelperClientThread(RTTHREAD aThread, void *aUser) #endif /* RT_OS_WINDOWS */ /** - * Sends a signal to the client watcher thread to rescan the set of machines + * Sends a signal to the client watcher to rescan the set of machines * that have open sessions. * * @note Doesn't lock anything. @@ -2778,35 +2803,23 @@ void VirtualBox::updateClientWatcher() AutoCaller autoCaller(this); AssertComRCReturnVoid(autoCaller.rc()); - AssertReturnVoid(m->threadClientWatcher != NIL_RTTHREAD); - - /* sent an update request */ -#if defined(RT_OS_WINDOWS) - ::SetEvent(m->updateReq); -#elif defined(RT_OS_OS2) - RTSemEventSignal(m->updateReq); -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - ASMAtomicUoWriteU8(&m->updateAdaptCtr, RT_ELEMENTS(s_updateAdaptTimeouts) - 1); - RTSemEventSignal(m->updateReq); -#else -# error "Port me!" -#endif + AssertPtrReturnVoid(m->pClientWatcher); + m->pClientWatcher->update(); } /** * Adds the given child process ID to the list of processes to be reaped. * This call should be followed by #updateClientWatcher() to take the effect. + * + * @note Doesn't lock anything. */ void VirtualBox::addProcessToReap(RTPROCESS pid) { AutoCaller autoCaller(this); AssertComRCReturnVoid(autoCaller.rc()); - /// @todo (dmik) Win32? -#ifndef RT_OS_WINDOWS - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - m->llProcesses.push_back(pid); -#endif + AssertPtrReturnVoid(m->pClientWatcher); + m->pClientWatcher->addProcess(pid); } /** Event for onMachineStateChange(), onMachineDataChange(), onMachineRegistered() */ @@ -2977,8 +2990,8 @@ struct SnapshotEvent : public VirtualBox::CallbackEvent virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc) { - return aEvDesc.init(aSource, VBoxEventType_OnSnapshotTaken, - machineId.toUtf16().raw(), snapshotId.toUtf16().raw()); + return aEvDesc.init(aSource, mWhat, machineId.toUtf16().raw(), + snapshotId.toUtf16().raw()); } Guid machineId; @@ -3043,65 +3056,108 @@ void VirtualBox::onGuestPropertyChange(const Guid &aMachineId, IN_BSTR aName, postEvent(new GuestPropertyEvent(this, aMachineId, aName, aValue, aFlags)); } -/** Event for onMachineUninit(), this is not a CallbackEvent */ -class MachineUninitEvent : public Event +/** + * @note Doesn't lock any object. + */ +void VirtualBox::onNatRedirectChange(const Guid &aMachineId, ULONG ulSlot, bool fRemove, IN_BSTR aName, + NATProtocol_T aProto, IN_BSTR aHostIp, uint16_t aHostPort, + IN_BSTR aGuestIp, uint16_t aGuestPort) { -public: + fireNATRedirectEvent(m->pEventSource, aMachineId.toUtf16().raw(), ulSlot, fRemove, aName, aProto, aHostIp, + aHostPort, aGuestIp, aGuestPort); +} - MachineUninitEvent(VirtualBox *aVirtualBox, Machine *aMachine) - : mVirtualBox(aVirtualBox), mMachine(aMachine) - { - Assert(aVirtualBox); - Assert(aMachine); - } +void VirtualBox::onNATNetworkChange(IN_BSTR aName) +{ + fireNATNetworkChangedEvent(m->pEventSource, aName); +} - void *handler() - { -#ifdef VBOX_WITH_RESOURCE_USAGE_API - /* Handle unregistering metrics here, as it is not vital to get - * it done immediately. It reduces the number of locks needed and - * the lock contention in SessionMachine::uninit. */ - { - AutoWriteLock mLock(mMachine COMMA_LOCKVAL_SRC_POS); - mMachine->unregisterMetrics(mVirtualBox->performanceCollector(), mMachine); - } -#endif /* VBOX_WITH_RESOURCE_USAGE_API */ +void VirtualBox::onNATNetworkStartStop(IN_BSTR aName, BOOL fStart) +{ + fireNATNetworkStartStopEvent(m->pEventSource, aName, fStart); +} +void VirtualBox::onNATNetworkSetting(IN_BSTR aNetworkName, BOOL aEnabled, + IN_BSTR aNetwork, IN_BSTR aGateway, + BOOL aAdvertiseDefaultIpv6RouteEnabled, + BOOL fNeedDhcpServer) +{ + fireNATNetworkSettingEvent(m->pEventSource, aNetworkName, aEnabled, + aNetwork, aGateway, + aAdvertiseDefaultIpv6RouteEnabled, fNeedDhcpServer); +} - return NULL; - } +void VirtualBox::onNATNetworkPortForward(IN_BSTR aNetworkName, BOOL create, BOOL fIpv6, + IN_BSTR aRuleName, NATProtocol_T proto, + IN_BSTR aHostIp, LONG aHostPort, + IN_BSTR aGuestIp, LONG aGuestPort) +{ + fireNATNetworkPortForwardEvent(m->pEventSource, aNetworkName, create, + fIpv6, aRuleName, proto, + aHostIp, aHostPort, + aGuestIp, aGuestPort); +} -private: - /** - * Note that this is a weak ref -- the CallbackEvent handler thread - * is bound to the lifetime of the VirtualBox instance, so it's safe. - */ - VirtualBox *mVirtualBox; +void VirtualBox::onHostNameResolutionConfigurationChange() +{ + if (m->pEventSource) + fireHostNameResolutionConfigurationChangeEvent(m->pEventSource); +} - /** Reference to the machine object. */ - ComObjPtr mMachine; -}; -/** - * Trigger internal event. This isn't meant to be signalled to clients. - * @note Doesn't lock any object. - */ -void VirtualBox::onMachineUninit(Machine *aMachine) +int VirtualBox::natNetworkRefInc(IN_BSTR aNetworkName) { - postEvent(new MachineUninitEvent(this, aMachine)); + AutoWriteLock safeLock(*spMtxNatNetworkNameToRefCountLock COMMA_LOCKVAL_SRC_POS); + Bstr name(aNetworkName); + + if (!sNatNetworkNameToRefCount[name]) + { + ComPtr nat; + HRESULT rc = FindNATNetworkByName(aNetworkName, nat.asOutParam()); + if (FAILED(rc)) return -1; + + rc = nat->Start(Bstr("whatever").raw()); + if (SUCCEEDED(rc)) + LogRel(("Started NAT network '%ls'\n", aNetworkName)); + else + LogRel(("Error %Rhrc starting NAT network '%ls'\n", rc, aNetworkName)); + AssertComRCReturn(rc, -1); + } + + sNatNetworkNameToRefCount[name]++; + + return sNatNetworkNameToRefCount[name]; } -/** - * @note Doesn't lock any object. - */ -void VirtualBox::onNatRedirectChange(const Guid &aMachineId, ULONG ulSlot, bool fRemove, IN_BSTR aName, - NATProtocol_T aProto, IN_BSTR aHostIp, uint16_t aHostPort, - IN_BSTR aGuestIp, uint16_t aGuestPort) + +int VirtualBox::natNetworkRefDec(IN_BSTR aNetworkName) { - fireNATRedirectEvent(m->pEventSource, aMachineId.toUtf16().raw(), ulSlot, fRemove, aName, aProto, aHostIp, - aHostPort, aGuestIp, aGuestPort); + AutoWriteLock safeLock(*spMtxNatNetworkNameToRefCountLock COMMA_LOCKVAL_SRC_POS); + Bstr name(aNetworkName); + + if (!sNatNetworkNameToRefCount[name]) + return 0; + + sNatNetworkNameToRefCount[name]--; + + if (!sNatNetworkNameToRefCount[name]) + { + ComPtr nat; + HRESULT rc = FindNATNetworkByName(aNetworkName, nat.asOutParam()); + if (FAILED(rc)) return -1; + + rc = nat->Stop(); + if (SUCCEEDED(rc)) + LogRel(("Stopped NAT network '%ls'\n", aNetworkName)); + else + LogRel(("Error %Rhrc stopping NAT network '%ls'\n", rc, aNetworkName)); + AssertComRCReturn(rc, -1); + } + + return sNatNetworkNameToRefCount[name]; } + /** * @note Locks this object for reading. */ @@ -3160,6 +3216,19 @@ void VirtualBox::getOpenedMachines(SessionMachinesList &aMachines, } } +/** + * Gets a reference to the machine list. This is the real thing, not a copy, + * so bad things will happen if the caller doesn't hold the necessary lock. + * + * @returns reference to machine list + * + * @note Caller must hold the VirtualBox object lock at least for reading. + */ +VirtualBox::MachinesOList &VirtualBox::getMachinesList(void) +{ + return m->allMachines; +} + /** * Searches for a machine object with the given ID in the collection * of registered machines. @@ -3402,7 +3471,7 @@ HRESULT VirtualBox::findHardDiskById(const Guid &id, bool aSetError, ComObjPtr *aHardDisk /*= NULL*/) { - AssertReturn(!id.isEmpty(), E_INVALIDARG); + AssertReturn(!id.isZero(), E_INVALIDARG); // we use the hard disks map, but it is protected by the // hard disk _list_ lock handle @@ -3609,12 +3678,19 @@ HRESULT VirtualBox::findRemoveableMedium(DeviceType_T mediumType, bool aSetError, ComObjPtr &pMedium) { - if (uuid.isEmpty()) + if (uuid.isZero()) { // that's easy pMedium.setNull(); return S_OK; } + else if (!uuid.isValid()) + { + /* handling of case invalid GUID */ + return setError(VBOX_E_OBJECT_NOT_FOUND, + tr("Guid '%ls' is invalid"), + uuid.toString().c_str()); + } // first search for host drive with that UUID HRESULT rc = m->pHost->findHostDriveById(mediumType, @@ -3816,7 +3892,7 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId, Utf8Str &aConflict, ComObjPtr *ppMedium) { - AssertReturn(!aId.isEmpty() && !aLocation.isEmpty(), E_FAIL); + AssertReturn(!aId.isZero() && !aLocation.isEmpty(), E_FAIL); AssertReturn(ppMedium, E_INVALIDARG); aConflict.setNull(); @@ -3829,7 +3905,7 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId, ComObjPtr pMediumFound; const char *pcszType = NULL; - if (!aId.isEmpty()) + if (aId.isValid() && !aId.isZero()) rc = findHardDiskById(aId, false /* aSetError */, &pMediumFound); if (FAILED(rc) && !aLocation.isEmpty()) rc = findHardDiskByLocation(aLocation, false /* aSetError */, &pMediumFound); @@ -3872,6 +3948,49 @@ HRESULT VirtualBox::checkMediaForConflicts(const Guid &aId, return S_OK; } +/** + * Checks whether the given UUID is already in use by one medium for the + * given device type. + * + * @returns true if the UUID is already in use + * fale otherwise + * @param aId The UUID to check. + * @param deviceType The device type the UUID is going to be checked for + * conflicts. + */ +bool VirtualBox::isMediaUuidInUse(const Guid &aId, DeviceType_T deviceType) +{ + /* A zero UUID is invalid here, always claim that it is already used. */ + AssertReturn(!aId.isZero(), true); + + AutoReadLock alock(getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = S_OK; + bool fInUse = false; + + ComObjPtr pMediumFound; + + switch (deviceType) + { + case DeviceType_HardDisk: + rc = findHardDiskById(aId, false /* aSetError */, &pMediumFound); + break; + case DeviceType_DVD: + rc = findDVDOrFloppyImage(DeviceType_DVD, &aId, Utf8Str::Empty, false /* aSetError */, &pMediumFound); + break; + case DeviceType_Floppy: + rc = findDVDOrFloppyImage(DeviceType_Floppy, &aId, Utf8Str::Empty, false /* aSetError */, &pMediumFound); + break; + default: + AssertMsgFailed(("Invalid device type %d\n", deviceType)); + } + + if (SUCCEEDED(rc) && pMediumFound) + fInUse = true; + + return fInUse; +} + /** * Called from Machine::prepareSaveSettings() when it has detected * that a machine has been renamed. Such renames will require @@ -4129,6 +4248,23 @@ HRESULT VirtualBox::saveSettings() } } +#ifdef VBOX_WITH_NAT_SERVICE + /* Saving NAT Network configuration */ + m->pMainConfigFile->llNATNetworks.clear(); + { + AutoReadLock natNetworkLock(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS); + for (NATNetworksOList::const_iterator it = m->allNATNetworks.begin(); + it != m->allNATNetworks.end(); + ++it) + { + settings::NATNetwork n; + rc = (*it)->saveSettings(n); + if (FAILED(rc)) throw rc; + m->pMainConfigFile->llNATNetworks.push_back(n); + } + } +#endif + // leave extra data alone, it's still in the config file // host data (USB filters) @@ -4418,7 +4554,7 @@ void VirtualBox::pushMediumToListWithChildren(MediaList &llMedia, Medium *pMediu */ HRESULT VirtualBox::unregisterMachineMedia(const Guid &uuidMachine) { - Assert(!uuidMachine.isEmpty()); + Assert(!uuidMachine.isZero() && uuidMachine.isValid()); LogFlowFuncEnter(); @@ -4669,6 +4805,18 @@ const Utf8Str& VirtualBox::settingsFilePath() return m->strSettingsFilePath; } +/** + * Returns the lock handle which protects the machines list. As opposed + * to version 3.1 and earlier, these lists are no longer protected by the + * VirtualBox lock, but by this more specialized lock. Mind the locking + * order: always request this lock after the VirtualBox object lock but + * before the locks of any machine object. See AutoLock.h. + */ +RWLockHandle& VirtualBox::getMachinesListLockHandle() +{ + return m->lockMachines; +} + /** * Returns the lock handle which protects the media trees (hard disks, * DVDs, floppies). As opposed to version 3.1 and earlier, these lists @@ -4683,541 +4831,62 @@ RWLockHandle& VirtualBox::getMediaTreeLockHandle() } /** - * Thread function that watches the termination of all client processes - * that have opened sessions using IMachine::LockMachine() + * Thread function that handles custom events posted using #postEvent(). */ // static -DECLCALLBACK(int) VirtualBox::ClientWatcher(RTTHREAD /* thread */, void *pvUser) +DECLCALLBACK(int) VirtualBox::AsyncEventHandler(RTTHREAD thread, void *pvUser) { LogFlowFuncEnter(); - VirtualBox *that = (VirtualBox*)pvUser; - Assert(that); - - typedef std::vector< ComObjPtr > MachineVector; - typedef std::vector< ComObjPtr > SessionMachineVector; - - SessionMachineVector machines; - MachineVector spawnedMachines; - - size_t cnt = 0; - size_t cntSpawned = 0; - - VirtualBoxBase::initializeComForThread(); - -#if defined(RT_OS_WINDOWS) + AssertReturn(pvUser, VERR_INVALID_POINTER); - /// @todo (dmik) processes reaping! + HRESULT hr = com::Initialize(); + if (FAILED(hr)) + return VERR_COM_UNEXPECTED; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - handles[0] = that->m->updateReq; + int rc = VINF_SUCCESS; - do + try { - AutoCaller autoCaller(that); - /* VirtualBox has been early uninitialized, terminate */ - if (!autoCaller.isOk()) - break; - - do - { - /* release the caller to let uninit() ever proceed */ - autoCaller.release(); - - DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned), - handles, - FALSE, - INFINITE); - - /* Restore the caller before using VirtualBox. If it fails, this - * means VirtualBox is being uninitialized and we must terminate. */ - autoCaller.add(); - if (!autoCaller.isOk()) - break; - - bool update = false; - - if (rc == WAIT_OBJECT_0) - { - /* update event is signaled */ - update = true; - } - else if (rc > WAIT_OBJECT_0 && rc <= (WAIT_OBJECT_0 + cnt)) - { - /* machine mutex is released */ - (machines[rc - WAIT_OBJECT_0 - 1])->checkForDeath(); - update = true; - } - else if (rc > WAIT_ABANDONED_0 && rc <= (WAIT_ABANDONED_0 + cnt)) - { - /* machine mutex is abandoned due to client process termination */ - (machines[rc - WAIT_ABANDONED_0 - 1])->checkForDeath(); - update = true; - } - else if (rc > WAIT_OBJECT_0 + cnt && rc <= (WAIT_OBJECT_0 + cntSpawned)) - { - /* spawned VM process has terminated (normally or abnormally) */ - (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])-> - checkForSpawnFailure(); - update = true; - } - - if (update) - { - /* close old process handles */ - for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i) - CloseHandle(handles[i]); - - // lock the machines list for reading - AutoReadLock thatLock(that->m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); - - /* obtain a new set of opened machines */ - cnt = 0; - machines.clear(); - - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); - ++it) - { - /// @todo handle situations with more than 64 objects - AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS, - ("MAXIMUM_WAIT_OBJECTS reached")); - - ComObjPtr sm; - HANDLE ipcSem; - if ((*it)->isSessionOpenOrClosing(sm, NULL, &ipcSem)) - { - machines.push_back(sm); - handles[1 + cnt] = ipcSem; - ++cnt; - } - } - - LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); - - /* obtain a new set of spawned machines */ - cntSpawned = 0; - spawnedMachines.clear(); + /* Create an event queue for the current thread. */ + EventQueue *pEventQueue = new EventQueue(); + AssertPtr(pEventQueue); - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); - ++it) - { - /// @todo handle situations with more than 64 objects - AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS, - ("MAXIMUM_WAIT_OBJECTS reached")); - - RTPROCESS pid; - if ((*it)->isSessionSpawning(&pid)) - { - HANDLE ph = OpenProcess(SYNCHRONIZE, FALSE, pid); - AssertMsg(ph != NULL, ("OpenProcess (pid=%d) failed with %d\n", - pid, GetLastError())); - if (rc == 0) - { - spawnedMachines.push_back(*it); - handles[1 + cnt + cntSpawned] = ph; - ++cntSpawned; - } - } - } - - LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); - - // machines lock unwinds here - } - } - while (true); - } - while (0); - - /* close old process handles */ - for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++ i) - CloseHandle(handles[i]); - - /* release sets of machines if any */ - machines.clear(); - spawnedMachines.clear(); - - ::CoUninitialize(); - -#elif defined(RT_OS_OS2) - - /// @todo (dmik) processes reaping! + /* Return the queue to the one who created this thread. */ + *(static_cast (pvUser)) = pEventQueue; - /* according to PMREF, 64 is the maximum for the muxwait list */ - SEMRECORD handles[64]; + /* signal that we're ready. */ + RTThreadUserSignal(thread); - HMUX muxSem = NULLHANDLE; - - do - { - AutoCaller autoCaller(that); - /* VirtualBox has been early uninitialized, terminate */ - if (!autoCaller.isOk()) - break; - - do + /* + * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes + * we must not stop processing events and delete the pEventQueue object. This must + * be done ONLY when we stop this loop via interruptEventQueueProcessing(). + * See @bugref{5724}. + */ + for (;;) { - /* release the caller to let uninit() ever proceed */ - autoCaller.release(); - - int vrc = RTSemEventWait(that->m->updateReq, 500); - - /* Restore the caller before using VirtualBox. If it fails, this - * means VirtualBox is being uninitialized and we must terminate. */ - autoCaller.add(); - if (!autoCaller.isOk()) - break; - - bool update = false; - bool updateSpawned = false; - - if (RT_SUCCESS(vrc)) - { - /* update event is signaled */ - update = true; - updateSpawned = true; - } - else - { - AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED, - ("RTSemEventWait returned %Rrc\n", vrc)); - - /* are there any mutexes? */ - if (cnt > 0) - { - /* figure out what's going on with machines */ - - unsigned long semId = 0; - APIRET arc = ::DosWaitMuxWaitSem(muxSem, - SEM_IMMEDIATE_RETURN, &semId); - - if (arc == NO_ERROR) - { - /* machine mutex is normally released */ - Assert(semId >= 0 && semId < cnt); - if (semId >= 0 && semId < cnt) - { -#if 0//def DEBUG - { - AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); - LogFlowFunc(("released mutex: machine='%ls'\n", - machines[semId]->name().raw())); - } -#endif - machines[semId]->checkForDeath(); - } - update = true; - } - else if (arc == ERROR_SEM_OWNER_DIED) - { - /* machine mutex is abandoned due to client process - * termination; find which mutex is in the Owner Died - * state */ - for (size_t i = 0; i < cnt; ++ i) - { - PID pid; TID tid; - unsigned long reqCnt; - arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt); - if (arc == ERROR_SEM_OWNER_DIED) - { - /* close the dead mutex as asked by PMREF */ - ::DosCloseMutexSem((HMTX)handles[i].hsemCur); - - Assert(i >= 0 && i < cnt); - if (i >= 0 && i < cnt) - { -#if 0//def DEBUG - { - AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); - LogFlowFunc(("mutex owner dead: machine='%ls'\n", - machines[i]->name().raw())); - } -#endif - machines[i]->checkForDeath(); - } - } - } - update = true; - } - else - AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT, - ("DosWaitMuxWaitSem returned %d\n", arc)); - } - - /* are there any spawning sessions? */ - if (cntSpawned > 0) - { - for (size_t i = 0; i < cntSpawned; ++ i) - updateSpawned |= (spawnedMachines[i])-> - checkForSpawnFailure(); - } - } - - if (update || updateSpawned) + rc = pEventQueue->processEventQueue(RT_INDEFINITE_WAIT); + if (rc == VERR_INTERRUPTED) { - AutoReadLock thatLock(that COMMA_LOCKVAL_SRC_POS); - - if (update) - { - /* close the old muxsem */ - if (muxSem != NULLHANDLE) - ::DosCloseMuxWaitSem(muxSem); - - /* obtain a new set of opened machines */ - cnt = 0; - machines.clear(); - - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); ++ it) - { - /// @todo handle situations with more than 64 objects - AssertMsg(cnt <= 64 /* according to PMREF */, - ("maximum of 64 mutex semaphores reached (%d)", - cnt)); - - ComObjPtr sm; - HMTX ipcSem; - if ((*it)->isSessionOpenOrClosing(sm, NULL, &ipcSem)) - { - machines.push_back(sm); - handles[cnt].hsemCur = (HSEM)ipcSem; - handles[cnt].ulUser = cnt; - ++ cnt; - } - } - - LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); - - if (cnt > 0) - { - /* create a new muxsem */ - APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt, - handles, - DCMW_WAIT_ANY); - AssertMsg(arc == NO_ERROR, - ("DosCreateMuxWaitSem returned %d\n", arc)); - NOREF(arc); - } - } - - if (updateSpawned) - { - /* obtain a new set of spawned machines */ - spawnedMachines.clear(); - - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); ++ it) - { - if ((*it)->isSessionSpawning()) - spawnedMachines.push_back(*it); - } - - cntSpawned = spawnedMachines.size(); - LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); - } + LogFlow(("Event queue processing ended with rc=%Rrc\n", rc)); + rc = VINF_SUCCESS; /* Set success when exiting. */ + break; } } - while (true); - } - while (0); - - /* close the muxsem */ - if (muxSem != NULLHANDLE) - ::DosCloseMuxWaitSem(muxSem); - - /* release sets of machines if any */ - machines.clear(); - spawnedMachines.clear(); - -#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) - bool update = false; - bool updateSpawned = false; - - do + delete pEventQueue; + } + catch (std::bad_alloc &ba) { - AutoCaller autoCaller(that); - if (!autoCaller.isOk()) - break; - - do - { - /* release the caller to let uninit() ever proceed */ - autoCaller.release(); - - /* determine wait timeout adaptively: after updating information - * relevant to the client watcher, check a few times more - * frequently. This ensures good reaction time when the signalling - * has to be done a bit before the actual change for technical - * reasons, and saves CPU cycles when no activities are expected. */ - RTMSINTERVAL cMillies; - { - uint8_t uOld, uNew; - do - { - uOld = ASMAtomicUoReadU8(&that->m->updateAdaptCtr); - uNew = uOld ? uOld - 1 : uOld; - } while (!ASMAtomicCmpXchgU8(&that->m->updateAdaptCtr, uNew, uOld)); - Assert(uOld <= RT_ELEMENTS(s_updateAdaptTimeouts) - 1); - cMillies = s_updateAdaptTimeouts[uOld]; - } - - int rc = RTSemEventWait(that->m->updateReq, cMillies); - - /* - * Restore the caller before using VirtualBox. If it fails, this - * means VirtualBox is being uninitialized and we must terminate. - */ - autoCaller.add(); - if (!autoCaller.isOk()) - break; - - if (RT_SUCCESS(rc) || update || updateSpawned) - { - /* RT_SUCCESS(rc) means an update event is signaled */ - - // lock the machines list for reading - AutoReadLock thatLock(that->m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); - - if (RT_SUCCESS(rc) || update) - { - /* obtain a new set of opened machines */ - machines.clear(); - - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); - ++it) - { - ComObjPtr sm; - if ((*it)->isSessionOpenOrClosing(sm)) - machines.push_back(sm); - } - - cnt = machines.size(); - LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); - } - - if (RT_SUCCESS(rc) || updateSpawned) - { - /* obtain a new set of spawned machines */ - spawnedMachines.clear(); - - for (MachinesOList::iterator it = that->m->allMachines.begin(); - it != that->m->allMachines.end(); - ++it) - { - if ((*it)->isSessionSpawning()) - spawnedMachines.push_back(*it); - } - - cntSpawned = spawnedMachines.size(); - LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); - } - - // machines lock unwinds here - } - - update = false; - for (size_t i = 0; i < cnt; ++ i) - update |= (machines[i])->checkForDeath(); - - updateSpawned = false; - for (size_t i = 0; i < cntSpawned; ++ i) - updateSpawned |= (spawnedMachines[i])->checkForSpawnFailure(); - - /* reap child processes */ - { - AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS); - if (that->m->llProcesses.size()) - { - LogFlowFunc(("UPDATE: child process count = %d\n", - that->m->llProcesses.size())); - VirtualBox::Data::ProcessList::iterator it = that->m->llProcesses.begin(); - while (it != that->m->llProcesses.end()) - { - RTPROCESS pid = *it; - RTPROCSTATUS status; - int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status); - if (vrc == VINF_SUCCESS) - { - LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n", - pid, pid, status.iStatus, - status.enmReason)); - it = that->m->llProcesses.erase(it); - } - else - { - LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n", - pid, pid, vrc)); - if (vrc != VERR_PROCESS_RUNNING) - { - /* remove the process if it is not already running */ - it = that->m->llProcesses.erase(it); - } - else - ++ it; - } - } - } - } - } - while (true); + rc = VERR_NO_MEMORY; + NOREF(ba); } - while (0); - - /* release sets of machines if any */ - machines.clear(); - spawnedMachines.clear(); - -#else -# error "Port me!" -#endif - - VirtualBoxBase::uninitializeComForThread(); - LogFlowFuncLeave(); - return 0; -} - -/** - * Thread function that handles custom events posted using #postEvent(). - */ -// static -DECLCALLBACK(int) VirtualBox::AsyncEventHandler(RTTHREAD thread, void *pvUser) -{ - LogFlowFuncEnter(); - - AssertReturn(pvUser, VERR_INVALID_POINTER); - - com::Initialize(); - - // create an event queue for the current thread - EventQueue *eventQ = new EventQueue(); - AssertReturn(eventQ, VERR_NO_MEMORY); - - // return the queue to the one who created this thread - *(static_cast (pvUser)) = eventQ; - // signal that we're ready - RTThreadUserSignal(thread); - - /* - * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes - * we must not stop processing events and delete the "eventQ" object. This must - * be done ONLY when we stop this loop via interruptEventQueueProcessing(). - * See @bugref{5724}. - */ - while (eventQ->processEventQueue(RT_INDEFINITE_WAIT) != VERR_INTERRUPTED) - /* nothing */ ; - - delete eventQ; com::Shutdown(); - - LogFlowFuncLeave(); - - return 0; + LogFlowFuncLeaveRC(rc); + return rc; } @@ -5422,4 +5091,204 @@ HRESULT VirtualBox::unregisterDHCPServer(DHCPServer *aDHCPServer, return rc; } + +/** + * NAT Network + */ + +STDMETHODIMP VirtualBox::CreateNATNetwork(IN_BSTR aName, INATNetwork ** aNatNetwork) +{ +#ifdef VBOX_WITH_NAT_SERVICE + CheckComArgStrNotEmptyOrNull(aName); + CheckComArgNotNull(aNatNetwork); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + ComObjPtr natNetwork; + natNetwork.createObject(); + HRESULT rc = natNetwork->init(this, aName); + if (FAILED(rc)) return rc; + + rc = registerNATNetwork(natNetwork, true); + if (FAILED(rc)) return rc; + + natNetwork.queryInterfaceTo(aNatNetwork); + + fireNATNetworkCreationDeletionEvent(m->pEventSource, aName, TRUE); + return rc; +#else + NOREF(aName); + NOREF(aNatNetwork); + return E_NOTIMPL; +#endif +} + +STDMETHODIMP VirtualBox::FindNATNetworkByName(IN_BSTR aName, INATNetwork ** aNetwork) +{ +#ifdef VBOX_WITH_NAT_SERVICE + CheckComArgStrNotEmptyOrNull(aName); + CheckComArgNotNull(aNetwork); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + HRESULT rc; + Bstr bstr; + ComPtr found; + + AutoReadLock alock(m->allNATNetworks.getLockHandle() COMMA_LOCKVAL_SRC_POS); + + for (NATNetworksOList::const_iterator it = m->allNATNetworks.begin(); + it != m->allNATNetworks.end(); + ++it) + { + rc = (*it)->COMGETTER(NetworkName)(bstr.asOutParam()); + if (FAILED(rc)) return rc; + + if (bstr == aName) + { + found = *it; + break; + } + } + + if (!found) + return E_INVALIDARG; + + return found.queryInterfaceTo(aNetwork); +#else + NOREF(aName); + NOREF(aNetwork); + return E_NOTIMPL; +#endif +} + +STDMETHODIMP VirtualBox::RemoveNATNetwork(INATNetwork * aNetwork) +{ +#ifdef VBOX_WITH_NAT_SERVICE + CheckComArgNotNull(aNetwork); + + AutoCaller autoCaller(this); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + Bstr name; + HRESULT rc; + NATNetwork *network = static_cast(aNetwork); + rc = network->COMGETTER(NetworkName)(name.asOutParam()); + rc = unregisterNATNetwork(network, true); + fireNATNetworkCreationDeletionEvent(m->pEventSource, name.raw(), FALSE); + return rc; +#else + NOREF(aNetwork); + return E_NOTIMPL; +#endif + +} +/** + * Remembers the given NAT network in the settings. + * + * @param aNATNetwork NAT Network object to remember. + * @param aSaveSettings @c true to save settings to disk (default). + * + * + * @note Locks this object for writing and @a aNATNetwork for reading. + */ +HRESULT VirtualBox::registerNATNetwork(NATNetwork *aNATNetwork, + bool aSaveSettings /*= true*/) +{ +#ifdef VBOX_WITH_NAT_SERVICE + AssertReturn(aNATNetwork != NULL, E_INVALIDARG); + + AutoCaller autoCaller(this); + AssertComRCReturnRC(autoCaller.rc()); + + AutoCaller natNetworkCaller(aNATNetwork); + AssertComRCReturnRC(natNetworkCaller.rc()); + + Bstr name; + HRESULT rc; + rc = aNATNetwork->COMGETTER(NetworkName)(name.asOutParam()); + AssertComRCReturnRC(rc); + + /* returned value isn't 0 and aSaveSettings is true + * means that we create duplicate, otherwise we just load settings. + */ + if ( sNatNetworkNameToRefCount[name] + && aSaveSettings) + AssertComRCReturnRC(E_INVALIDARG); + + rc = S_OK; + + sNatNetworkNameToRefCount[name] = 0; + + m->allNATNetworks.addChild(aNATNetwork); + + if (aSaveSettings) + { + AutoWriteLock vboxLock(this COMMA_LOCKVAL_SRC_POS); + rc = saveSettings(); + vboxLock.release(); + + if (FAILED(rc)) + unregisterNATNetwork(aNATNetwork, false /* aSaveSettings */); + } + + return rc; +#else + NOREF(aNATNetwork); + NOREF(aSaveSettings); + /* No panic please (silently ignore) */ + return S_OK; +#endif +} + +/** + * Removes the given NAT network from the settings. + * + * @param aNATNetwork NAT network object to remove. + * @param aSaveSettings @c true to save settings to disk (default). + * + * When @a aSaveSettings is @c true, this operation may fail because of the + * failed #saveSettings() method it calls. In this case, the DHCP server + * will NOT be removed from the settingsi when this method returns. + * + * @note Locks this object for writing. + */ +HRESULT VirtualBox::unregisterNATNetwork(NATNetwork *aNATNetwork, + bool aSaveSettings /*= true*/) +{ +#ifdef VBOX_WITH_NAT_SERVICE + AssertReturn(aNATNetwork != NULL, E_INVALIDARG); + + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoCaller natNetworkCaller(aNATNetwork); + AssertComRCReturn(natNetworkCaller.rc(), natNetworkCaller.rc()); + + Bstr name; + HRESULT rc = aNATNetwork->COMGETTER(NetworkName)(name.asOutParam()); + /* Hm, there're still running clients. */ + if (FAILED(rc) || sNatNetworkNameToRefCount[name]) + AssertComRCReturnRC(E_INVALIDARG); + + m->allNATNetworks.removeChild(aNATNetwork); + + if (aSaveSettings) + { + AutoWriteLock vboxLock(this COMMA_LOCKVAL_SRC_POS); + rc = saveSettings(); + vboxLock.release(); + + if (FAILED(rc)) + registerNATNetwork(aNATNetwork, false /* aSaveSettings */); + } + + return rc; +#else + NOREF(aNATNetwork); + NOREF(aSaveSettings); + return E_NOTIMPL; +#endif +} /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp b/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp new file mode 100644 index 00000000..6e91e7e6 --- /dev/null +++ b/src/VBox/Main/src-server/darwin/HostDnsServiceDarwin.cpp @@ -0,0 +1,256 @@ +/* $Id: HostDnsServiceDarwin.cpp $ */ +/** @file + * Darwin specific DNS information fetching. + */ + +/* + * Copyright (C) 2004-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include + + +#include +#include +#include + +#include +#include + +#include +#include +#include "../HostDnsService.h" + + +struct HostDnsServiceDarwin::Data +{ + SCDynamicStoreRef m_store; + CFRunLoopSourceRef m_DnsWatcher; + CFRunLoopRef m_RunLoopRef; + CFRunLoopSourceRef m_Stopper; + bool m_fStop; + RTSEMEVENT m_evtStop; + static void performShutdownCallback(void *); +}; + + +static const CFStringRef kStateNetworkGlobalDNSKey = CFSTR("State:/Network/Global/DNS"); + + +HostDnsServiceDarwin::HostDnsServiceDarwin():HostDnsMonitor(true),m(NULL) +{ + m = new HostDnsServiceDarwin::Data(); +} + + +HostDnsServiceDarwin::~HostDnsServiceDarwin() +{ + if (!m) + return; + + monitorThreadShutdown(); + + CFRelease(m->m_RunLoopRef); + + CFRelease(m->m_DnsWatcher); + + CFRelease(m->m_store); + + RTSemEventDestroy(m->m_evtStop); + + delete m; + m = NULL; +} + + +void HostDnsServiceDarwin::hostDnsServiceStoreCallback(void *, void *, void *info) +{ + HostDnsServiceDarwin *pThis = (HostDnsServiceDarwin *)info; + + ALock l(pThis); + pThis->updateInfo(); + pThis->notifyAll(); +} + + +HRESULT HostDnsServiceDarwin::init() +{ + SCDynamicStoreContext ctx; + RT_ZERO(ctx); + + ctx.info = this; + + m->m_store = SCDynamicStoreCreate(NULL, CFSTR("org.virtualbox.VBoxSVC"), + (SCDynamicStoreCallBack)HostDnsServiceDarwin::hostDnsServiceStoreCallback, + &ctx); + AssertReturn(m->m_store, E_FAIL); + + m->m_DnsWatcher = SCDynamicStoreCreateRunLoopSource(NULL, m->m_store, 0); + if (!m->m_DnsWatcher) + return E_OUTOFMEMORY; + + int rc = RTSemEventCreate(&m->m_evtStop); + AssertRCReturn(rc, E_FAIL); + + CFRunLoopSourceContext sctx; + RT_ZERO(sctx); + sctx.perform = HostDnsServiceDarwin::Data::performShutdownCallback; + m->m_Stopper = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sctx); + AssertReturn(m->m_Stopper, E_FAIL); + + HRESULT hrc = HostDnsMonitor::init(); + AssertComRCReturn(hrc, hrc); + + return updateInfo(); +} + + +void HostDnsServiceDarwin::monitorThreadShutdown() +{ + ALock l(this); + if (!m->m_fStop) + { + CFRunLoopSourceSignal(m->m_Stopper); + CFRunLoopWakeUp(m->m_RunLoopRef); + + RTSemEventWait(m->m_evtStop, RT_INDEFINITE_WAIT); + } +} + + +int HostDnsServiceDarwin::monitorWorker() +{ + m->m_RunLoopRef = CFRunLoopGetCurrent(); + AssertReturn(m->m_RunLoopRef, VERR_INTERNAL_ERROR); + + CFRetain(m->m_RunLoopRef); + + CFArrayRef watchingArrayRef = CFArrayCreate(NULL, + (const void **)&kStateNetworkGlobalDNSKey, + 1, &kCFTypeArrayCallBacks); + if (!watchingArrayRef) + { + CFRelease(m->m_DnsWatcher); + return E_OUTOFMEMORY; + } + + if(SCDynamicStoreSetNotificationKeys(m->m_store, watchingArrayRef, NULL)) + CFRunLoopAddSource(CFRunLoopGetCurrent(), m->m_DnsWatcher, kCFRunLoopCommonModes); + + CFRelease(watchingArrayRef); + + monitorThreadInitializationDone(); + + while (!m->m_fStop) + { + CFRunLoopRun(); + } + + CFRelease(m->m_RunLoopRef); + + /* We're notifying stopper thread. */ + RTSemEventSignal(m->m_evtStop); + + return VINF_SUCCESS; +} + + +HRESULT HostDnsServiceDarwin::updateInfo() +{ + CFPropertyListRef propertyRef = SCDynamicStoreCopyValue(m->m_store, + kStateNetworkGlobalDNSKey); + /** + * 0:vvl@nb-mbp-i7-2(0)# scutil + * > get State:/Network/Global/DNS + * > d.show + * { + * DomainName : vvl-domain + * SearchDomains : { + * 0 : vvl-domain + * 1 : de.vvl-domain.com + * } + * ServerAddresses : { + * 0 : 192.168.1.4 + * 1 : 192.168.1.1 + * 2 : 8.8.4.4 + * } + * } + */ + + if (!propertyRef) + return S_OK; + + HostDnsInformation info; + CFStringRef domainNameRef = (CFStringRef)CFDictionaryGetValue( + static_cast(propertyRef), CFSTR("DomainName")); + if (domainNameRef) + { + const char *pszDomainName = CFStringGetCStringPtr(domainNameRef, + CFStringGetSystemEncoding()); + if (pszDomainName) + info.domain = pszDomainName; + } + + int i, arrayCount; + CFArrayRef serverArrayRef = (CFArrayRef)CFDictionaryGetValue( + static_cast(propertyRef), CFSTR("ServerAddresses")); + if (serverArrayRef) + { + arrayCount = CFArrayGetCount(serverArrayRef); + for (i = 0; i < arrayCount; ++i) + { + CFStringRef serverAddressRef = (CFStringRef)CFArrayGetValueAtIndex(serverArrayRef, i); + if (!serverArrayRef) + continue; + + const char *pszServerAddress = CFStringGetCStringPtr(serverAddressRef, + CFStringGetSystemEncoding()); + if (!pszServerAddress) + continue; + + info.servers.push_back(std::string(pszServerAddress)); + } + } + + CFArrayRef searchArrayRef = (CFArrayRef)CFDictionaryGetValue( + static_cast(propertyRef), CFSTR("SearchDomains")); + if (searchArrayRef) + { + arrayCount = CFArrayGetCount(searchArrayRef); + + for (i = 0; i < arrayCount; ++i) + { + CFStringRef searchStringRef = (CFStringRef)CFArrayGetValueAtIndex(searchArrayRef, i); + if (!searchArrayRef) + continue; + + const char *pszSearchString = CFStringGetCStringPtr(searchStringRef, + CFStringGetSystemEncoding()); + if (!pszSearchString) + continue; + + info.searchList.push_back(std::string(pszSearchString)); + } + } + + CFRelease(propertyRef); + + setInfo(info); + + return S_OK; +} + +void HostDnsServiceDarwin::Data::performShutdownCallback(void *info) +{ + HostDnsServiceDarwin::Data *pThis = static_cast(info); + pThis->m_fStop = true; +} diff --git a/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp b/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp index a83297e4..5e68d02b 100644 --- a/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp +++ b/src/VBox/Main/src-server/darwin/HostPowerDarwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -25,43 +25,43 @@ #define POWER_SOURCE_OUTLET 1 #define POWER_SOURCE_BATTERY 2 -HostPowerServiceDarwin::HostPowerServiceDarwin (VirtualBox *aVirtualBox) - : HostPowerService (aVirtualBox) - , mThread (NULL) - , mRootPort (MACH_PORT_NULL) - , mNotifyPort (nil) - , mRunLoop (nil) - , mCritical (false) +HostPowerServiceDarwin::HostPowerServiceDarwin(VirtualBox *aVirtualBox) + : HostPowerService(aVirtualBox) + , mThread(NULL) + , mRootPort(MACH_PORT_NULL) + , mNotifyPort(nil) + , mRunLoop(nil) + , mCritical(false) { /* Create the new worker thread. */ - int rc = RTThreadCreate (&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536, - RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "MainPower"); + int rc = RTThreadCreate(&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536, + RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "MainPower"); if (RT_FAILURE(rc)) - LogFlow (("RTThreadCreate failed with %Rrc\n", rc)); + LogFlow(("RTThreadCreate failed with %Rrc\n", rc)); } HostPowerServiceDarwin::~HostPowerServiceDarwin() { /* Jump out of the run loop. */ - CFRunLoopStop (mRunLoop); + CFRunLoopStop(mRunLoop); /* Remove the sleep notification port from the application runloop. */ - CFRunLoopRemoveSource (CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource (mNotifyPort), - kCFRunLoopCommonModes); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), + IONotificationPortGetRunLoopSource(mNotifyPort), + kCFRunLoopCommonModes); /* Deregister for system sleep notifications. */ - IODeregisterForSystemPower (&mNotifierObject); + IODeregisterForSystemPower(&mNotifierObject); /* IORegisterForSystemPower implicitly opens the Root Power Domain * IOService so we close it here. */ - IOServiceClose (mRootPort); + IOServiceClose(mRootPort); /* Destroy the notification port allocated by IORegisterForSystemPower */ - IONotificationPortDestroy (mNotifyPort); + IONotificationPortDestroy(mNotifyPort); } -DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREAD /* ThreadSelf */, void *pInstance) +DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread(RTTHREAD /* ThreadSelf */, void *pInstance) { - HostPowerServiceDarwin *pPowerObj = static_cast (pInstance); + HostPowerServiceDarwin *pPowerObj = static_cast(pInstance); /* We have to initial set the critical state of the battery, cause we want * not the HostPowerService to inform about that state when a VM starts. @@ -69,19 +69,19 @@ DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREA pPowerObj->checkBatteryCriticalLevel(); /* Register to receive system sleep notifications */ - pPowerObj->mRootPort = IORegisterForSystemPower (pPowerObj, &pPowerObj->mNotifyPort, - HostPowerServiceDarwin::powerChangeNotificationHandler, - &pPowerObj->mNotifierObject); + pPowerObj->mRootPort = IORegisterForSystemPower(pPowerObj, &pPowerObj->mNotifyPort, + HostPowerServiceDarwin::powerChangeNotificationHandler, + &pPowerObj->mNotifierObject); if (pPowerObj->mRootPort == MACH_PORT_NULL) { - LogFlow (("IORegisterForSystemPower failed\n")); + LogFlow(("IORegisterForSystemPower failed\n")); return VERR_NOT_SUPPORTED; } pPowerObj->mRunLoop = CFRunLoopGetCurrent(); /* Add the notification port to the application runloop */ - CFRunLoopAddSource (pPowerObj->mRunLoop, - IONotificationPortGetRunLoopSource (pPowerObj->mNotifyPort), - kCFRunLoopCommonModes); + CFRunLoopAddSource(pPowerObj->mRunLoop, + IONotificationPortGetRunLoopSource(pPowerObj->mNotifyPort), + kCFRunLoopCommonModes); /* Register for all battery change events. The handler will check for low * power events itself. */ @@ -96,10 +96,10 @@ DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREA return VINF_SUCCESS; } -void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument) +void HostPowerServiceDarwin::powerChangeNotificationHandler(void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument) { - HostPowerServiceDarwin *pPowerObj = static_cast (pvData); - Log (( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument)); + HostPowerServiceDarwin *pPowerObj = static_cast(pvData); + Log(( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument)); switch (messageType) { @@ -113,18 +113,18 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se * you don't acknowledge this power change by calling either * IOAllowPowerChange or IOCancelPowerChange, the system will * wait 30 seconds then go to sleep. */ - IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast (pMessageArgument)); + IOAllowPowerChange(pPowerObj->mRootPort, reinterpret_cast(pMessageArgument)); break; } case kIOMessageSystemWillSleep: { /* The system will go for sleep. */ - pPowerObj->notify (HostPowerEvent_Suspend); + pPowerObj->notify(Reason_HostSuspend); /* If you do not call IOAllowPowerChange or IOCancelPowerChange to * acknowledge this message, sleep will be delayed by 30 seconds. * NOTE: If you call IOCancelPowerChange to deny sleep it returns * kIOReturnSuccess, however the system WILL still go to sleep. */ - IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast (pMessageArgument)); + IOAllowPowerChange(pPowerObj->mRootPort, reinterpret_cast(pMessageArgument)); break; } case kIOMessageSystemWillPowerOn: @@ -135,7 +135,7 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se case kIOMessageSystemHasPoweredOn: { /* System has finished the wake up process. */ - pPowerObj->notify (HostPowerEvent_Resume); + pPowerObj->notify(Reason_HostResume); break; } default: @@ -143,11 +143,11 @@ void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_se } } -void HostPowerServiceDarwin::lowPowerHandler (void *pvData) +void HostPowerServiceDarwin::lowPowerHandler(void *pvData) { - HostPowerServiceDarwin *pPowerObj = static_cast (pvData); + HostPowerServiceDarwin *pPowerObj = static_cast(pvData); - /* Following role for sending the BatteryLow event (5% is critical): + /* Following role for sending the BatteryLow event(5% is critical): * - Not at VM start even if the battery is in an critical state already. * - When the power cord is removed so the power supply change from AC to * battery & the battery is in an critical state nothing is triggered. @@ -156,15 +156,15 @@ void HostPowerServiceDarwin::lowPowerHandler (void *pvData) * changed from normal to critical. The state transition from critical to * normal triggers nothing. */ bool fCriticalStateChanged = false; - pPowerObj->checkBatteryCriticalLevel (&fCriticalStateChanged); + pPowerObj->checkBatteryCriticalLevel(&fCriticalStateChanged); if (fCriticalStateChanged) - pPowerObj->notify (HostPowerEvent_BatteryLow); + pPowerObj->notify(Reason_HostBatteryLow); } -void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged) +void HostPowerServiceDarwin::checkBatteryCriticalLevel(bool *pfCriticalChanged) { CFTypeRef pBlob = IOPSCopyPowerSourcesInfo(); - CFArrayRef pSources = IOPSCopyPowerSourcesList (pBlob); + CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob); CFDictionaryRef pSource = NULL; const void *psValue; @@ -172,30 +172,30 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged) int powerSource = POWER_SOURCE_OUTLET; bool critical = false; - if (CFArrayGetCount (pSources) > 0) + if (CFArrayGetCount(pSources) > 0) { - for (int i = 0; i < CFArrayGetCount (pSources); ++i) + for (int i = 0; i < CFArrayGetCount(pSources); ++i) { - pSource = IOPSGetPowerSourceDescription (pBlob, CFArrayGetValueAtIndex (pSources, i)); + pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i)); /* If the source is empty skip over to the next one. */ if (!pSource) continue; /* Skip all power sources which are currently not present like a * second battery. */ - if (CFDictionaryGetValue (pSource, CFSTR (kIOPSIsPresentKey)) == kCFBooleanFalse) + if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse) continue; /* Only internal power types are of interest. */ - result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSTransportTypeKey), &psValue); + result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue); if (result && - CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSInternalType), 0) == kCFCompareEqualTo) + CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo) { /* First check which power source we are connect on. */ - result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSPowerSourceStateKey), &psValue); + result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue); if (result && - CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSACPowerValue), 0) == kCFCompareEqualTo) + CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo) powerSource = POWER_SOURCE_OUTLET; else if (result && - CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) + CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) powerSource = POWER_SOURCE_BATTERY; int curCapacity = 0; @@ -203,22 +203,22 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged) float remCapacity = 0.0f; /* Fetch the current capacity value of the power source */ - result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSCurrentCapacityKey), &psValue); + result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue); if (result) - CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity); + CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity); /* Fetch the maximum capacity value of the power source */ - result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSMaxCapacityKey), &psValue); + result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue); if (result) - CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity); + CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity); /* Calculate the remaining capacity in percent */ remCapacity = ((float)curCapacity/(float)maxCapacity * 100.0); /* Check for critical. 5 percent is default. */ int criticalValue = 5; - result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSDeadWarnLevelKey), &psValue); + result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue); if (result) - CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue); + CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue); critical = (remCapacity < criticalValue); /* We have to take action only if we are on battery, the * previous state wasn't critical, the state has changed & the @@ -228,14 +228,14 @@ void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged) mCritical != critical && pfCriticalChanged) *pfCriticalChanged = true; - Log (("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1)); + Log(("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1)); } } } /* Save the new state */ mCritical = critical; - CFRelease (pBlob); - CFRelease (pSources); + CFRelease(pBlob); + CFRelease(pSources); } diff --git a/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp b/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp index 99cf52e2..cfde818e 100644 --- a/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp +++ b/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -85,7 +85,7 @@ int NetIfList(std::list > &list) memcpy(pNew->szName, pEtherNICs->szName, cbNameLen); struct ifreq IfReq; - strcpy(IfReq.ifr_name, pNew->szShortName); + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName); if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) { Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); @@ -391,7 +391,7 @@ int NetIfList(std::list > &list) if (pSdl->sdl_type == IFT_ETHER) { struct ifreq IfReq; - strcpy(IfReq.ifr_name, pNew->szShortName); + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName); if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) { Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); @@ -401,7 +401,7 @@ int NetIfList(std::list > &list) pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN; HostNetworkInterfaceType_T enmType; - if (strncmp("vboxnet", pNew->szName, 7)) + if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet"))) enmType = HostNetworkInterfaceType_Bridged; else enmType = HostNetworkInterfaceType_HostOnly; @@ -511,7 +511,7 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) pInfo->Uuid = uuid; struct ifreq IfReq; - strcpy(IfReq.ifr_name, pInfo->szShortName); + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pInfo->szShortName); if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) { Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); @@ -528,4 +528,17 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) return rc; } +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/) +{ + return VERR_NOT_IMPLEMENTED; +} #endif diff --git a/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp b/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp index e3daa585..ea040bd0 100644 --- a/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp +++ b/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include "Performance.h" /* The following declarations are missing in 10.4.x SDK */ @@ -63,7 +65,8 @@ public: virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used); private: - ULONG totalRAM; + ULONG totalRAM; + uint32_t nCpus; }; CollectorHAL *createHAL() @@ -73,19 +76,19 @@ CollectorHAL *createHAL() CollectorDarwin::CollectorDarwin() { - uint64_t hostMemory; - int mib[2]; - size_t size; - - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - - size = sizeof(hostMemory); - if (sysctl(mib, 2, &hostMemory, &size, NULL, 0) == -1) { - Log(("sysctl() -> %s", strerror(errno))); - hostMemory = 0; + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) + totalRAM = 0; + else + totalRAM = (ULONG)(cb / 1024); + nCpus = RTMpGetOnlineCount(); + Assert(nCpus); + if (nCpus == 0) + { + /* It is rather unsual to have no CPUs, but the show must go on. */ + nCpus = 1; } - totalRAM = (ULONG)(hostMemory / 1024); } int CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle) @@ -112,23 +115,16 @@ int CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_ int CollectorDarwin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - kern_return_t krc; - mach_msg_type_number_t count; - vm_statistics_data_t info; - - count = HOST_VM_INFO_COUNT; - - krc = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count); - if (krc != KERN_SUCCESS) + AssertReturn(totalRAM, VERR_INTERNAL_ERROR); + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_SUCCESS(rc)) { - Log(("host_statistics() -> %s", mach_error_string(krc))); - return RTErrConvertFromDarwinKern(krc); + *total = totalRAM; + *available = cb / 1024; + *used = *total - *available; } - - *total = totalRAM; - *available = info.free_count * (PAGE_SIZE / 1024); - *used = *total - *available; - return VINF_SUCCESS; + return rc; } static int getProcessInfo(RTPROCESS process, struct proc_taskinfo *tinfo) @@ -156,8 +152,12 @@ int CollectorDarwin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uin int rc = getProcessInfo(process, &tinfo); if (RT_SUCCESS(rc)) { - *user = tinfo.pti_total_user; - *kernel = tinfo.pti_total_system; + /* + * Adjust user and kernel values so 100% is when ALL cores are fully + * utilized (see @bugref{6345}). + */ + *user = tinfo.pti_total_user / nCpus; + *kernel = tinfo.pti_total_system / nCpus; *total = mach_absolute_time(); } return rc; @@ -175,10 +175,5 @@ int CollectorDarwin::getProcessMemoryUsage(RTPROCESS process, ULONG *used) return rc; } -int getDiskListByFs(const char *name, DiskList& list) -{ - return VERR_NOT_IMPLEMENTED; -} - } diff --git a/src/VBox/Main/src-server/darwin/iokit.cpp b/src/VBox/Main/src-server/darwin/iokit.cpp index 0045e7c0..69c572f2 100644 --- a/src/VBox/Main/src-server/darwin/iokit.cpp +++ b/src/VBox/Main/src-server/darwin/iokit.cpp @@ -8,7 +8,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -373,7 +373,7 @@ static void darwinDumpDictCallback(const void *pvKey, const void *pvValue, void double rd; CFIndex iCF; } u; - memset(&u, 0, sizeof(u)); + RT_ZERO(u); CFNumberType NumType = CFNumberGetType((CFNumberRef)pvValue); if (CFNumberGetValue((CFNumberRef)pvValue, NumType, &u)) { @@ -1354,7 +1354,7 @@ PDARWINDVD DarwinGetDVDDrives(void) if (*pszVendor && *pszProduct) RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", pszVendor, pszProduct, i); else - RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", *pszVendor ? pszVendor : pszProduct, i); + RTStrPrintf(szName, sizeof(szName), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i); break; } } diff --git a/src/VBox/Main/src-server/darwin/iokit.h b/src/VBox/Main/src-server/darwin/iokit.h index 8cb80a52..ff81b3c7 100644 --- a/src/VBox/Main/src-server/darwin/iokit.h +++ b/src/VBox/Main/src-server/darwin/iokit.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp index b654f5a6..c65e47c3 100644 --- a/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp +++ b/src/VBox/Main/src-server/freebsd/HostHardwareFreeBSD.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,7 +31,6 @@ #include #include #include -#include /* for RTThreadSleep() */ #include #ifdef RT_OS_FREEBSD @@ -172,8 +171,8 @@ static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess) struct dev_match_pattern DeviceMatchPattern; struct dev_match_result *paMatches = NULL; - memset(&DeviceCCB, 0, sizeof(union ccb)); - memset(&DeviceMatchPattern, 0, sizeof(struct device_match_pattern)); + RT_ZERO(DeviceCCB); + RT_ZERO(DeviceMatchPattern); /* We want to get all devices. */ DeviceCCB.ccb_h.func_code = XPT_DEV_MATCH; @@ -236,9 +235,9 @@ static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess) struct periph_match_result *pPeriphResult = NULL; unsigned iPeriphMatch = 0; - memset(&PeriphCCB, 0, sizeof(union ccb)); - memset(&PeriphMatchPattern, 0, sizeof(struct dev_match_pattern)); - memset(aPeriphMatches, 0, sizeof(aPeriphMatches)); + RT_ZERO(PeriphCCB); + RT_ZERO(PeriphMatchPattern); + RT_ZERO(aPeriphMatches); /* This time we only want the specific nodes for the device. */ PeriphCCB.ccb_h.func_code = XPT_DEV_MATCH; diff --git a/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp b/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp index 7066dab9..049aaaf6 100644 --- a/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp +++ b/src/VBox/Main/src-server/freebsd/NetIf-freebsd.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -271,7 +272,7 @@ int NetIfList(std::list > &list) if (pSdl->sdl_type == IFT_ETHER || pSdl->sdl_type == IFT_L2VLAN) { struct ifreq IfReq; - strcpy(IfReq.ifr_name, pNew->szShortName); + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName); if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) { Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); @@ -281,7 +282,7 @@ int NetIfList(std::list > &list) pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN; HostNetworkInterfaceType_T enmType; - if (strncmp("vboxnet", pNew->szName, 7)) + if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet"))) enmType = HostNetworkInterfaceType_Bridged; else enmType = HostNetworkInterfaceType_HostOnly; @@ -388,7 +389,7 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) pInfo->Uuid = uuid; struct ifreq IfReq; - strcpy(IfReq.ifr_name, pInfo->szShortName); + RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pInfo->szShortName); if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) { Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); @@ -405,3 +406,16 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) return rc; } +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/) +{ + return VERR_NOT_IMPLEMENTED; +} diff --git a/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp index 0b817842..6770c75b 100644 --- a/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp +++ b/src/VBox/Main/src-server/freebsd/PerformanceFreeBSD.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -39,7 +39,7 @@ CollectorHAL *createHAL() int CollectorFreeBSD::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorFreeBSD::getHostCpuMHz(ULONG *mhz) @@ -101,12 +101,17 @@ int CollectorFreeBSD::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *avail int CollectorFreeBSD::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorFreeBSD::getProcessMemoryUsage(RTPROCESS process, ULONG *used) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; +} + +int getDiskListByFs(const char *name, DiskList& list) +{ + return VERR_NOT_IMPLEMENTED; } } /* namespace pm */ diff --git a/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp index ef8856a3..98535312 100644 --- a/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp +++ b/src/VBox/Main/src-server/freebsd/USBProxyServiceFreeBSD.cpp @@ -266,7 +266,7 @@ PUSBDEVICE USBProxyServiceFreeBSD::getDevices(void) LogFlowFunc((": %s opened successfully\n", pszDevicePath)); struct usb_device_info UsbDevInfo; - memset(&UsbDevInfo, 0, sizeof(struct usb_device_info)); + RT_ZERO(UsbDevInfo); rc = ioctl(FileUsb, USB_GET_DEVICEINFO, &UsbDevInfo); if (rc < 0) diff --git a/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp b/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp index 923e75fe..07aafe23 100644 --- a/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp +++ b/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2010 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -78,7 +78,7 @@ int AutostartDb::autostartModifyDb(bool fAutostart, bool fAddVM) char abBuf[16 + 1]; /* trailing \0 */ uint32_t cAutostartVms = 0; - memset(abBuf, 0, sizeof(abBuf)); + RT_ZERO(abBuf); /* Check if the file was just created. */ if (cbFile) diff --git a/src/VBox/Main/src-server/generic/NetIf-generic.cpp b/src/VBox/Main/src-server/generic/NetIf-generic.cpp index fdf72d6f..2f99585b 100644 --- a/src/VBox/Main/src-server/generic/NetIf-generic.cpp +++ b/src/VBox/Main/src-server/generic/NetIf-generic.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2010 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,6 +21,15 @@ #include #include #include +#include +#include +#include +#include +#include + +#if defined(RT_OS_SOLARIS) +# include +#endif #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) # include @@ -218,6 +227,11 @@ int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox, char szBuf[128]; /* We are not interested in long error messages. */ if (fgets(szBuf, sizeof(szBuf), fp)) { + /* Remove trailing new line characters. */ + char *pLast = szBuf + strlen(szBuf) - 1; + if (pLast >= szBuf && *pLast == '\n') + *pLast = 0; + if (!strncmp(VBOXNETADPCTL_NAME ":", szBuf, sizeof(VBOXNETADPCTL_NAME))) { progress->notifyComplete(E_FAIL, @@ -227,9 +241,6 @@ int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox, pclose(fp); return E_FAIL; } - char *pLast = szBuf + strlen(szBuf) - 1; - if (pLast >= szBuf && *pLast == '\n') - *pLast = 0; size_t cbNameLen = strlen(szBuf) + 1; PNETIFINFO pInfo = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen])); @@ -307,7 +318,7 @@ int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVBox, IN_GUID aId, ComPtr host; int rc = VINF_SUCCESS; HRESULT hr = pVBox->COMGETTER(Host)(host.asOutParam()); - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { Bstr ifname; ComPtr iface; @@ -320,7 +331,7 @@ int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVBox, IN_GUID aId, rc = progress->init(pVBox, host, Bstr("Removing host network interface").raw(), FALSE /* aCancelable */); - if(SUCCEEDED(rc)) + if (SUCCEEDED(rc)) { progress.queryInterfaceTo(aProgress); rc = NetIfAdpCtl(Utf8Str(ifname).c_str(), "remove", NULL, NULL); @@ -352,8 +363,34 @@ int NetIfGetConfig(HostNetworkInterface * /* pIf */, NETIFINFO *) return VERR_NOT_IMPLEMENTED; } -int NetIfDhcpRediscover(VirtualBox * /* pVbox */, HostNetworkInterface * /* pIf */) +int NetIfDhcpRediscover(VirtualBox * /* pVBox */, HostNetworkInterface * /* pIf */) { return VERR_NOT_IMPLEMENTED; } +/** + * Obtain the current state of the interface. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param penmState Where to store the retrieved state. + */ +int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState) +{ + int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) + return VERR_OUT_OF_RESOURCES; + struct ifreq Req; + RT_ZERO(Req); + RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName); + if (ioctl(sock, SIOCGIFFLAGS, &Req) < 0) + { + Log(("NetIfGetState: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); + *penmState = NETIF_S_UNKNOWN; + } + else + *penmState = (Req.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN; + close(sock); + return VINF_SUCCESS; +} diff --git a/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp new file mode 100644 index 00000000..89de18df --- /dev/null +++ b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp @@ -0,0 +1,233 @@ +/* $Id: HostDnsServiceLinux.cpp $ */ +/** @file + * Linux specific DNS information fetching. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include "../HostDnsService.h" + + +static int g_DnsMonitorStop[2]; + +static const std::string g_EtcFolder = "/etc"; +static const std::string g_ResolvConf = "resolv.conf"; +static const std::string g_ResolvConfFullPath = "/etc/resolv.conf"; + +class FileDescriptor +{ + public: + FileDescriptor(int d = -1):fd(d){} + + virtual ~FileDescriptor() { + if (fd != -1) + close(fd); + } + + int fileDescriptor() const {return fd;} + + protected: + int fd; +}; + + +class AutoNotify:public FileDescriptor +{ + public: + AutoNotify() + { + FileDescriptor::fd = inotify_init(); + AssertReturnVoid(FileDescriptor::fd != -1); + } +}; + +struct InotifyEventWithName +{ + struct inotify_event e; + char name[NAME_MAX]; +}; + +HostDnsServiceLinux::~HostDnsServiceLinux() +{ + monitorThreadShutdown(); +} + + +int HostDnsServiceLinux::monitorWorker() +{ + + AutoNotify a; + + int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop); + AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL); + + FileDescriptor stopper0(g_DnsMonitorStop[0]); + FileDescriptor stopper1(g_DnsMonitorStop[1]); + + pollfd polls[2]; + RT_ZERO(polls); + + polls[0].fd = a.fileDescriptor(); + polls[0].events = POLLIN; + + polls[1].fd = g_DnsMonitorStop[1]; + polls[1].events = POLLIN; + + monitorThreadInitializationDone(); + + int wd[2]; + wd[0] = wd[1] = -1; + /* inotify inialization */ + wd[0] = inotify_add_watch(a.fileDescriptor(), + g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF); + + /** + * If /etc/resolv.conf exists we want to listen for movements: because + * # mv /etc/resolv.conf ... + * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1]. + * + * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion, + * it's recognizible on directory level (wd[1]) only. + */ + wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), + wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE); + + struct InotifyEventWithName combo; + while(true) + { + rc = poll(polls, 2, -1); + if (rc == -1) + continue; + + AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0) + && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0), + ("Debug Me"), VERR_INTERNAL_ERROR); + + if (polls[1].revents & POLLIN) + return VINF_SUCCESS; /* time to shutdown */ + + if (polls[0].revents & POLLIN) + { + RT_ZERO(combo); + ssize_t r = read(polls[0].fd, static_cast(&combo), sizeof(combo)); + + if (combo.e.wd == wd[0]) + { + if (combo.e.mask & IN_CLOSE_WRITE) + { + readResolvConf(); + /* notifyAll() takes required locks */ + notifyAll(); + } + else if (combo.e.mask & IN_DELETE_SELF) + { + inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */ + inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), + IN_MOVED_TO|IN_CREATE); /* alter folder watcher */ + } + else if (combo.e.mask & IN_IGNORED) + { + wd[0] = -1; /* we want receive any events on this watch */ + } + else + { + /** + * It shouldn't happen, in release we will just ignore in debug + * we will have to chance to look at into inotify_event + */ + AssertMsgFailed(("Debug Me!!!")); + } + } + else if (combo.e.wd == wd[1]) + { + if ( combo.e.mask & IN_MOVED_FROM + || combo.e.mask & IN_DELETE) + { + if (g_ResolvConf == combo.e.name) + { + /** + * Our file has been moved so we should change watching mode. + */ + inotify_rm_watch(a.fileDescriptor(), wd[0]); + wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), + IN_MOVED_TO|IN_CREATE); + AssertMsg(wd[1] != -1, + ("It shouldn't happen, further investigation is needed\n")); + } + } + else + { + AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE), + ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n", + combo.e.mask)); + if (g_ResolvConf == combo.e.name) + { + AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n")); + + /* alter folder watcher*/ + wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), + IN_MOVED_FROM|IN_DELETE); + AssertMsg(wd[1] != -1, ("It shouldn't happen.\n")); + + wd[0] = inotify_add_watch(a.fileDescriptor(), + g_ResolvConfFullPath.c_str(), + IN_CLOSE_WRITE | IN_DELETE_SELF); + AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n", + g_ResolvConfFullPath.c_str())); + + /* Notify our listeners */ + readResolvConf(); + notifyAll(); + + } + } + } + else + { + /* It shouldn't happen */ + AssertMsgFailed(("Shouldn't happen! Please debug me!")); + } + } + } +} + + +void HostDnsServiceLinux::monitorThreadShutdown() +{ + send(g_DnsMonitorStop[0], "", 1, 0); +} diff --git a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp index 2dc722cc..1ff26d81 100644 --- a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp +++ b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -37,7 +37,6 @@ #include #include #include -#include /* for RTThreadSleep() */ #include #include @@ -1282,7 +1281,7 @@ hotplugInotifyImpl::hotplugInotifyImpl(const char *pcszDevicesRoot) : break; if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW))) break; - } while(0); + } while (0); mStatus = rc; if (RT_FAILURE(rc)) term(); diff --git a/src/VBox/Main/src-server/linux/NetIf-linux.cpp b/src/VBox/Main/src-server/linux/NetIf-linux.cpp index 6fe799cf..2384cc52 100644 --- a/src/VBox/Main/src-server/linux/NetIf-linux.cpp +++ b/src/VBox/Main/src-server/linux/NetIf-linux.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -37,14 +37,23 @@ #include "netif.h" #include "Logging.h" +/** + * Obtain the name of the interface used for default routing. + * + * NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp. + * + * @returns VBox status code. + * + * @param pszName The buffer of IFNAMSIZ+1 length where to put the name. + */ static int getDefaultIfaceName(char *pszName) { FILE *fp = fopen("/proc/net/route", "r"); char szBuf[1024]; char szIfName[17]; - char szAddr[129]; - char szGateway[129]; - char szMask[129]; + uint32_t uAddr; + uint32_t uGateway; + uint32_t uMask; int iTmp; unsigned uFlags; @@ -52,13 +61,13 @@ static int getDefaultIfaceName(char *pszName) { while (fgets(szBuf, sizeof(szBuf)-1, fp)) { - int n = sscanf(szBuf, "%16s %128s %128s %X %d %d %d %128s %d %d %d\n", - szIfName, szAddr, szGateway, &uFlags, &iTmp, &iTmp, &iTmp, - szMask, &iTmp, &iTmp, &iTmp); + int n = sscanf(szBuf, "%16s %x %x %x %d %d %d %x %d %d %d\n", + szIfName, &uAddr, &uGateway, &uFlags, &iTmp, &iTmp, &iTmp, + &uMask, &iTmp, &iTmp, &iTmp); if (n < 10 || !(uFlags & RTF_UP)) continue; - if (strcmp(szAddr, "00000000") == 0 && strcmp(szMask, "00000000") == 0) + if (uAddr == 0 && uMask == 0) { fclose(fp); strncpy(pszName, szIfName, 16); @@ -71,14 +80,55 @@ static int getDefaultIfaceName(char *pszName) return VERR_INTERNAL_ERROR; } +static uint32_t getInterfaceSpeed(const char *pszName) +{ + /* + * I wish I could do simple ioctl here, but older kernels require root + * privileges for any ethtool commands. + */ + char szBuf[256]; + uint32_t uSpeed = 0; + /* First, we try to retrieve the speed via sysfs. */ + RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName); + FILE *fp = fopen(szBuf, "r"); + if (fp) + { + if (fscanf(fp, "%u", &uSpeed) != 1) + uSpeed = 0; + fclose(fp); + } + if (uSpeed == 10) + { + /* Check the cable is plugged in at all */ + unsigned uCarrier = 0; + RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName); + fp = fopen(szBuf, "r"); + if (fp) + { + if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0) + uSpeed = 0; + fclose(fp); + } + } + + if (uSpeed == 0) + { + /* Failed to get speed via sysfs, go to plan B. */ + int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf)); + if (RT_SUCCESS(rc)) + uSpeed = RTStrToUInt32(szBuf); + } + return uSpeed; +} + static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo) { // Zeroing out pInfo is a bad idea as it should contain both short and long names at // this point. So make sure the structure is cleared by the caller if necessary! // memset(pInfo, 0, sizeof(*pInfo)); struct ifreq Req; - memset(&Req, 0, sizeof(Req)); - strncpy(Req.ifr_name, pszName, sizeof(Req.ifr_name) - 1); + RT_ZERO(Req); + RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName); if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0) { switch (Req.ifr_hwaddr.sa_family) @@ -122,7 +172,7 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo) char szName[30]; for (;;) { - memset(szName, 0, sizeof(szName)); + RT_ZERO(szName); int n = fscanf(fp, "%08x%08x%08x%08x" " %02x %02x %02x %02x %20s\n", @@ -152,31 +202,10 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo) * Don't even try to get speed for non-Ethernet interfaces, it only * produces errors. */ - pInfo->uSpeedMbits = 0; if (pInfo->enmMediumType == NETIF_T_ETHERNET) - { - /* - * I wish I could do simple ioctl here, but older kernels require root - * privileges for any ethtool commands. - */ - char szBuf[256]; - /* First, we try to retrieve the speed via sysfs. */ - RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName); - fp = fopen(szBuf, "r"); - if (fp) - { - if (fscanf(fp, "%u", &pInfo->uSpeedMbits) != 1) - pInfo->uSpeedMbits = 0; - fclose(fp); - } - if (pInfo->uSpeedMbits == 0) - { - /* Failed to get speed via sysfs, go to plan B. */ - int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf)); - if (RT_SUCCESS(rc)) - pInfo->uSpeedMbits = RTStrToUInt32(szBuf); - } - } + pInfo->uSpeedMbits = getInterfaceSpeed(pszName); + else + pInfo->uSpeedMbits = 0; } return VINF_SUCCESS; } @@ -216,7 +245,7 @@ int NetIfList(std::list > &list) IfObj.createObject(); HostNetworkInterfaceType_T enmType; - if (strncmp("vboxnet", pszName, 7)) + if (strncmp(pszName, RT_STR_TUPLE("vboxnet"))) enmType = HostNetworkInterfaceType_Bridged; else enmType = HostNetworkInterfaceType_HostOnly; @@ -251,3 +280,35 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) close(sock); return rc; } + +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits) +{ + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + return VERR_OUT_OF_RESOURCES; + struct ifreq Req; + RT_ZERO(Req); + RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName); + if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0) + { + if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0) + if (Req.ifr_flags & IFF_UP) + { + close(sock); + *puMbits = getInterfaceSpeed(pcszIfName); + return VINF_SUCCESS; + } + } + close(sock); + *puMbits = 0; + return VWRN_NOT_FOUND; +} diff --git a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp index 4e165ee3..77ccb9b8 100644 --- a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp +++ b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -27,8 +27,11 @@ #include #include #include +#include #include +#include #include +#include #include #include @@ -36,6 +39,8 @@ #include "Logging.h" #include "Performance.h" +#define VBOXVOLINFO_NAME "VBoxVolInfo" + namespace pm { class CollectorLinux : public CollectorHAL @@ -45,15 +50,23 @@ public: virtual int preCollect(const CollectorHints& hints, uint64_t /* iTick */); virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available); virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available); + virtual int getHostDiskSize(const char *name, uint64_t *size); virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used); virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle); virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx); virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms); virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); + + virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad); private: virtual int _getRawHostCpuLoad(); int getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uint64_t *cpuKernel, ULONG *memPagesUsed); + void getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits); + void addVolumeDependencies(const char *pcszVolume, DiskList& listDisks); + void addRaidDisks(const char *pcszDevice, DiskList& listDisks); + char *trimTrailingDigits(char *pszName); + char *trimNewline(char *pszName); struct VMProcessStats { @@ -68,6 +81,7 @@ private: uint64_t mUser, mKernel, mIdle; uint64_t mSingleUser, mSingleKernel, mSingleIdle; uint32_t mHZ; + ULONG totalRAM; }; CollectorHAL *createHAL() @@ -88,6 +102,13 @@ CollectorLinux::CollectorLinux() else mHZ = hz; LogFlowThisFunc(("mHZ=%u\n", mHZ)); + + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) + totalRAM = 0; + else + totalRAM = (ULONG)(cb / 1024); } int CollectorLinux::preCollect(const CollectorHints& hints, uint64_t /* iTick */) @@ -190,35 +211,21 @@ int CollectorLinux::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint int CollectorLinux::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - int rc = VINF_SUCCESS; - ULONG buffers, cached; - FILE *f = fopen("/proc/meminfo", "r"); - - if (f) + AssertReturn(totalRAM, VERR_INTERNAL_ERROR); + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_SUCCESS(rc)) { - int processed = fscanf(f, "MemTotal: %u kB\n", total); - processed += fscanf(f, "MemFree: %u kB\n", available); - processed += fscanf(f, "Buffers: %u kB\n", &buffers); - processed += fscanf(f, "Cached: %u kB\n", &cached); - if (processed == 4) - { - *available += buffers + cached; - *used = *total - *available; - } - else - rc = VERR_FILE_IO_ERROR; - fclose(f); + *total = totalRAM; + *available = cb / 1024; + *used = *total - *available; } - else - rc = VERR_ACCESS_DENIED; - return rc; } int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available) { struct statvfs stats; - const unsigned _MB = 1024 * 1024; if (statvfs(path, &stats) == -1) { @@ -226,13 +233,35 @@ int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG return VERR_ACCESS_DENIED; } uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize; - *total = (ULONG)(cbBlock * stats.f_blocks / _MB); - *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _MB); - *available = (ULONG)(cbBlock * stats.f_bavail / _MB); + *total = (ULONG)(cbBlock * stats.f_blocks / _1M); + *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M); + *available = (ULONG)(cbBlock * stats.f_bavail / _1M); return VINF_SUCCESS; } +int CollectorLinux::getHostDiskSize(const char *pszFile, uint64_t *size) +{ + char *pszPath = NULL; + + RTStrAPrintf(&pszPath, "/sys/block/%s/size", pszFile); + Assert(pszPath); + + int rc = VINF_SUCCESS; + if (!RTLinuxSysFsExists(pszPath)) + rc = VERR_FILE_NOT_FOUND; + else + { + int64_t cSize = RTLinuxSysFsReadIntFile(0, pszPath); + if (cSize < 0) + rc = VERR_ACCESS_DENIED; + else + *size = cSize * 512; + } + RTStrFree(pszPath); + return rc; +} + int CollectorLinux::getProcessMemoryUsage(RTPROCESS process, ULONG *used) { VMProcessMap::const_iterator it = mProcessStats.find(process); @@ -261,9 +290,8 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin char buf[80]; /* @todo: this should be tied to max allowed proc name. */ RTStrAPrintf(&pszName, "/proc/%d/stat", process); - //printf("Opening %s...\n", pszName); FILE *f = fopen(pszName, "r"); - RTMemFree(pszName); + RTStrFree(pszName); if (f) { @@ -288,42 +316,35 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin return rc; } -int CollectorLinux::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx) +int CollectorLinux::getRawHostNetworkLoad(const char *pszFile, uint64_t *rx, uint64_t *tx) { - int rc = VINF_SUCCESS; char szIfName[/*IFNAMSIZ*/ 16 + 36]; - long long unsigned int u64Rx, u64Tx; - RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", name); - FILE *f = fopen(szIfName, "r"); - if (f) - { - if (fscanf(f, "%llu", &u64Rx) == 1) - *rx = u64Rx; - else - rc = VERR_FILE_IO_ERROR; - fclose(f); - RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", name); - f = fopen(szIfName, "r"); - if (f) - { - if (fscanf(f, "%llu", &u64Tx) == 1) - *tx = u64Tx; - else - rc = VERR_FILE_IO_ERROR; - fclose(f); - } - else - rc = VERR_ACCESS_DENIED; - } - else - rc = VERR_ACCESS_DENIED; + RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", pszFile); + if (!RTLinuxSysFsExists(szIfName)) + return VERR_FILE_NOT_FOUND; - return rc; + int64_t cSize = RTLinuxSysFsReadIntFile(0, szIfName); + if (cSize < 0) + return VERR_ACCESS_DENIED; + + *rx = cSize; + + RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", pszFile); + if (!RTLinuxSysFsExists(szIfName)) + return VERR_FILE_NOT_FOUND; + + cSize = RTLinuxSysFsReadIntFile(0, szIfName); + if (cSize < 0) + return VERR_ACCESS_DENIED; + + *tx = cSize; + return VINF_SUCCESS; } int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms) { +#if 0 int rc = VINF_SUCCESS; char szIfName[/*IFNAMSIZ*/ 16 + 36]; long long unsigned int u64Busy, tmp; @@ -344,28 +365,184 @@ int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint } else rc = VERR_ACCESS_DENIED; +#else + int rc = VERR_MISSING; + FILE *f = fopen("/proc/diskstats", "r"); + if (f) + { + char szBuf[128]; + while (fgets(szBuf, sizeof(szBuf), f)) + { + char *pszBufName = szBuf; + while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */ + while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip major */ + while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */ + while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip minor */ + while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */ + + char *pszBufData = strchr(pszBufName, ' '); + if (!pszBufData) + { + LogRel(("CollectorLinux::getRawHostDiskLoad() failed to parse disk stats: %s\n", szBuf)); + continue; + } + *pszBufData++ = '\0'; + if (!strcmp(name, pszBufName)) + { + long long unsigned int u64Busy, tmp; + + if (sscanf(pszBufData, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &u64Busy, &tmp) == 11) + { + *disk_ms = u64Busy; + *total_ms = (uint64_t)(mSingleUser + mSingleKernel + mSingleIdle) * 1000 / mHZ; + rc = VINF_SUCCESS; + } + else + rc = VERR_FILE_IO_ERROR; + break; + } + } + fclose(f); + } +#endif return rc; } -static char *getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName) +char *CollectorLinux::trimNewline(char *pszName) +{ + unsigned cbName = strlen(pszName); + if (cbName == 0) + return pszName; + + char *pszEnd = pszName + cbName - 1; + while (pszEnd > pszName && *pszEnd == '\n') + pszEnd--; + pszEnd[1] = '\0'; + + return pszName; +} + +char *CollectorLinux::trimTrailingDigits(char *pszName) +{ + unsigned cbName = strlen(pszName); + if (cbName == 0) + return pszName; + + char *pszEnd = pszName + cbName - 1; + while (pszEnd > pszName && (RT_C_IS_DIGIT(*pszEnd) || *pszEnd == '\n')) + pszEnd--; + pszEnd[1] = '\0'; + + return pszName; +} + +/** + * Use the partition name to get the name of the disk. Any path component is stripped. + * if fTrimDigits is true, trailing digits are stripped as well, for example '/dev/sda5' + * is converted to 'sda'. + * + * @param pszDiskName Where to store the name of the disk. + * @param cbDiskName The size of the buffer pszDiskName points to. + * @param pszDevName The device name used to get the disk name. + * @param fTrimDigits Trim trailing digits (e.g. /dev/sda5) + */ +void CollectorLinux::getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits) { unsigned cbName = 0; unsigned cbDevName = strlen(pszDevName); const char *pszEnd = pszDevName + cbDevName - 1; - while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd)) - pszEnd--; + if (fTrimDigits) + while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd)) + pszEnd--; while (pszEnd > pszDevName && *pszEnd != '/') { cbName++; pszEnd--; } RTStrCopy(pszDiskName, RT_MIN(cbName + 1, cbDiskName), pszEnd + 1); - return pszDiskName; } +void CollectorLinux::addRaidDisks(const char *pcszDevice, DiskList& listDisks) +{ + FILE *f = fopen("/proc/mdstat", "r"); + if (f) + { + char szBuf[128]; + while (fgets(szBuf, sizeof(szBuf), f)) + { + char *pszBufName = szBuf; -int getDiskListByFs(const char *pszPath, DiskList& listDisks) + char *pszBufData = strchr(pszBufName, ' '); + if (!pszBufData) + { + LogRel(("CollectorLinux::addRaidDisks() failed to parse disk stats: %s\n", szBuf)); + continue; + } + *pszBufData++ = '\0'; + if (!strcmp(pcszDevice, pszBufName)) + { + while (*pszBufData == ':') ++pszBufData; /* Skip delimiter */ + while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */ + while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip status */ + while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */ + while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip type */ + + while (*pszBufData != '\0') + { + while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */ + char *pszDisk = pszBufData; + while (RT_C_IS_ALPHA(*pszBufData)) + ++pszBufData; + if (*pszBufData) + { + *pszBufData++ = '\0'; + listDisks.push_back(RTCString(pszDisk)); + while (*pszBufData != '\0' && *pszBufData != ' ') + ++pszBufData; + } + else + listDisks.push_back(RTCString(pszDisk)); + } + break; + } + } + fclose(f); + } +} + +void CollectorLinux::addVolumeDependencies(const char *pcszVolume, DiskList& listDisks) +{ + char szVolInfo[RTPATH_MAX]; + int rc = RTPathAppPrivateArch(szVolInfo, + sizeof(szVolInfo) - sizeof("/" VBOXVOLINFO_NAME " ") - strlen(pcszVolume)); + if (RT_FAILURE(rc)) + { + LogRel(("VolInfo: Failed to get program path, rc=%Rrc\n", rc)); + return; + } + strcat(szVolInfo, "/" VBOXVOLINFO_NAME " "); + strcat(szVolInfo, pcszVolume); + + FILE *fp = popen(szVolInfo, "r"); + if (fp) + { + char szBuf[128]; + + while (fgets(szBuf, sizeof(szBuf), fp)) + if (strncmp(szBuf, RT_STR_TUPLE("dm-"))) + listDisks.push_back(RTCString(trimTrailingDigits(szBuf))); + else + listDisks.push_back(RTCString(trimNewline(szBuf))); + + pclose(fp); + } + else + listDisks.push_back(RTCString(pcszVolume)); +} + +int CollectorLinux::getDiskListByFs(const char *pszPath, DiskList& listUsage, DiskList& listLoad) { FILE *mtab = setmntent("/etc/mtab", "r"); if (mtab) @@ -373,10 +550,45 @@ int getDiskListByFs(const char *pszPath, DiskList& listDisks) struct mntent *mntent; while ((mntent = getmntent(mtab))) { + /* Skip rootfs entry, there must be another root mount. */ + if (strcmp(mntent->mnt_fsname, "rootfs") == 0) + continue; if (strcmp(pszPath, mntent->mnt_dir) == 0) { - char szDevName[32]; - listDisks.push_back(RTCString(getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname))); + char szDevName[128]; + char szFsName[1024]; + /* Try to resolve symbolic link if necessary. Yes, we access the file system here! */ + int rc = RTPathReal(mntent->mnt_fsname, szFsName, sizeof(szFsName)); + if (RT_FAILURE(rc)) + continue; /* something got wrong, just ignore this path */ + /* check against the actual mtab entry, NOT the real path as /dev/mapper/xyz is + * often a symlink to something else */ + if (!strncmp(mntent->mnt_fsname, RT_STR_TUPLE("/dev/mapper"))) + { + /* LVM */ + getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname, false /*=fTrimDigits*/); + addVolumeDependencies(szDevName, listUsage); + listLoad = listUsage; + } + else if (!strncmp(szFsName, RT_STR_TUPLE("/dev/md"))) + { + /* Software RAID */ + getDiskName(szDevName, sizeof(szDevName), szFsName, false /*=fTrimDigits*/); + listUsage.push_back(RTCString(szDevName)); + addRaidDisks(szDevName, listLoad); + } + else + { + /* Plain disk partition. Trim the trailing digits to get the drive name */ + getDiskName(szDevName, sizeof(szDevName), szFsName, true /*=fTrimDigits*/); + listUsage.push_back(RTCString(szDevName)); + listLoad.push_back(RTCString(szDevName)); + } + if (listUsage.empty() || listLoad.empty()) + { + LogRel(("Failed to retrive disk info: getDiskName(%s) --> %s\n", + mntent->mnt_fsname, szDevName)); + } break; } } diff --git a/src/VBox/Main/src-server/linux/USBGetDevices.cpp b/src/VBox/Main/src-server/linux/USBGetDevices.cpp index d824a017..b4ef0df7 100644 --- a/src/VBox/Main/src-server/linux/USBGetDevices.cpp +++ b/src/VBox/Main/src-server/linux/USBGetDevices.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -357,11 +357,11 @@ static int usbReadSpeed(const char *pszValue, USBDEVICESPEED *pSpd, char **ppszN { pszValue = RTStrStripL(pszValue); /* verified with Linux 2.4.0 ... Linux 2.6.25 */ - if (!strncmp(pszValue, "1.5", 3)) + if (!strncmp(pszValue, RT_STR_TUPLE("1.5"))) *pSpd = USBDEVICESPEED_LOW; - else if (!strncmp(pszValue, "12 ", 3)) + else if (!strncmp(pszValue, RT_STR_TUPLE("12 "))) *pSpd = USBDEVICESPEED_FULL; - else if (!strncmp(pszValue, "480", 3)) + else if (!strncmp(pszValue, RT_STR_TUPLE("480"))) *pSpd = USBDEVICESPEED_HIGH; else *pSpd = USBDEVICESPEED_UNKNOWN; @@ -593,7 +593,7 @@ static PUSBDEVICE getDevicesFromUsbfs(const char *pcszUsbfsRoot, bool testfs) deviceFreeMembers(&Dev); /* Reset device state */ - memset(&Dev, 0, sizeof (Dev)); + RT_ZERO(Dev); Dev.enmState = USBDEVICESTATE_UNUSED; cHits = 1; @@ -1122,7 +1122,7 @@ static int usbGetPortFromSysfsPath(const char *pszPath, uint8_t *pu8Port) if (!pchDash && !pchDot) { /* No -/. so it must be a root hub. Check that it's usb. */ - if (strncmp(pszLastComp, "usb", sizeof("usb") - 1) != 0) + if (strncmp(pszLastComp, RT_STR_TUPLE("usb")) != 0) { Log(("usbGetPortFromSysfsPath(%s): failed [2]\n", pszPath)); return VERR_INVALID_PARAMETER; @@ -1430,7 +1430,7 @@ void TestUSBSetInotifyAvailable(bool fHaveInotifyLibC, bool fHaveInotifyKernel) s_fHaveInotifyKernel = fHaveInotifyKernel; } # define dlsym testDLSym -# define close(a) do {} while(0) +# define close(a) do {} while (0) #endif /** Is inotify available and working on this system? This is a requirement @@ -1586,7 +1586,7 @@ void TestUSBSetEnv(const char *pcszEnvUsb, const char *pcszEnvUsbRoot) * what is available on the host and what if anything the user has specified * in the environment. * @returns iprt status value - * @param pfUsingUsbfsDevices on success this will be set to true if + * @param pfUsingUsbfsDevices on success this will be set to true if * the prefered access method is USBFS-like and to * false if it is sysfs/device node-like * @param ppcszDevicesRoot on success the root of the tree of USBFS-like diff --git a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp index a89c3e00..82c97aa9 100644 --- a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp +++ b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp @@ -320,7 +320,7 @@ int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies) aMillies = 500; } - memset(&PollFds, 0, sizeof(PollFds)); + RT_ZERO(PollFds); PollFds[0].fd = RTFileToNative(mhFile); PollFds[0].events = POLLIN; PollFds[1].fd = RTPipeToNative(mhWakeupPipeR); diff --git a/src/VBox/Main/src-server/linux/vbox-libhal.cpp b/src/VBox/Main/src-server/linux/vbox-libhal.cpp index 2e7c2716..ade8f072 100644 --- a/src/VBox/Main/src-server/linux/vbox-libhal.cpp +++ b/src/VBox/Main/src-server/linux/vbox-libhal.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/os2/NetIf-os2.cpp b/src/VBox/Main/src-server/os2/NetIf-os2.cpp index d0c287b5..cac174a7 100644 --- a/src/VBox/Main/src-server/os2/NetIf-os2.cpp +++ b/src/VBox/Main/src-server/os2/NetIf-os2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,23 +33,24 @@ int NetIfList(std::list > &list) return VERR_NOT_IMPLEMENTED; } -int NetIfEnableStaticIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf, ULONG ip, ULONG mask) +int NetIfEnableStaticIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf, ULONG ip, ULONG mask) { return VERR_NOT_IMPLEMENTED; } -int NetIfEnableStaticIpConfigV6(VirtualBox *pVbox, HostNetworkInterface * pIf, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength) +int NetIfEnableStaticIpConfigV6(VirtualBox *pVBox, HostNetworkInterface * pIf, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength) { return VERR_NOT_IMPLEMENTED; } -int NetIfEnableDynamicIpConfig(VirtualBox *pVbox, HostNetworkInterface * pIf) +int NetIfEnableDynamicIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf) { return VERR_NOT_IMPLEMENTED; } -int NetIfDhcpRediscover(VirtualBox *pVbox, HostNetworkInterface * pIf) +int NetIfDhcpRediscover(VirtualBox *pVBox, HostNetworkInterface * pIf) { return VERR_NOT_IMPLEMENTED; } + diff --git a/src/VBox/Main/src-server/os2/PerformanceOs2.cpp b/src/VBox/Main/src-server/os2/PerformanceOs2.cpp index e004ab83..054932ff 100644 --- a/src/VBox/Main/src-server/os2/PerformanceOs2.cpp +++ b/src/VBox/Main/src-server/os2/PerformanceOs2.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -39,30 +39,25 @@ CollectorHAL *createHAL() int CollectorOS2::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorOS2::getHostCpuMHz(ULONG *mhz) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorOS2::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorOS2::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel) { - return E_NOTIMPL; + return VERR_NOT_IMPLEMENTED; } int CollectorOS2::getProcessMemoryUsage(RTPROCESS process, ULONG *used) -{ - return E_NOTIMPL; -} - -int getDiskListByFs(const char *name, DiskList& list) { return VERR_NOT_IMPLEMENTED; } diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp index 4bd864f1..a38b7654 100644 --- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h index 4fc35b8a..e306dac0 100644 --- a/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h +++ b/src/VBox/Main/src-server/solaris/DynLoadLibSolaris.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp index bc700820..82e8a338 100644 --- a/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp +++ b/src/VBox/Main/src-server/solaris/NetIf-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -73,10 +74,10 @@ static uint32_t getInstance(const char *pszIfaceName, char *pszDevName) return uInstance; } -static uint64_t kstatGet(const char *name) +static uint32_t kstatGet(const char *name) { kstat_ctl_t *kc; - uint64_t uSpeed = 0; + uint32_t uSpeed = 0; if ((kc = kstat_open()) == 0) { @@ -84,14 +85,14 @@ static uint64_t kstatGet(const char *name) return 0; } - kstat_t *ksAdapter = kstat_lookup(kc, "link", -1, (char *)name); + kstat_t *ksAdapter = kstat_lookup(kc, (char *)"link", -1, (char *)name); if (ksAdapter == 0) { char szModule[KSTAT_STRLEN]; uint32_t uInstance = getInstance(name, szModule); - ksAdapter = kstat_lookup(kc, szModule, uInstance, "phys"); + ksAdapter = kstat_lookup(kc, szModule, uInstance, (char *)"phys"); if (ksAdapter == 0) - ksAdapter = kstat_lookup(kc, szModule, uInstance, name); + ksAdapter = kstat_lookup(kc, szModule, uInstance, (char*)name); } if (ksAdapter == 0) LogRel(("Failed to get network statistics for %s\n", name)); @@ -103,15 +104,21 @@ static uint64_t kstatGet(const char *name) if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"ifspeed")) == 0) LogRel(("kstat_data_lookup(ifspeed) -> %d, name=%s\n", errno, name)); else - uSpeed = kn->value.ul; + uSpeed = kn->value.ul / 1000000; /* bits -> Mbits */ } kstat_close(kc); + LogFlow(("kstatGet(%s) -> %u Mbit/s\n", name, uSpeed)); return uSpeed; } static void queryIfaceSpeed(PNETIFINFO pInfo) { - pInfo->uSpeedMbits = kstatGet(pInfo->szShortName) / 1000000; /* bits -> Mbits */ + /* Don't query interface speed for inactive interfaces (see @bugref{6345}). */ + if (pInfo->enmStatus == NETIF_S_UP) + pInfo->uSpeedMbits = kstatGet(pInfo->szShortName); + else + pInfo->uSpeedMbits = 0; + LogFlow(("queryIfaceSpeed(%s) -> %u\n", pInfo->szShortName, pInfo->uSpeedMbits)); } static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNetworkInterfaceList) @@ -192,12 +199,12 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe * Try to get IP V4 address and netmask as well as Ethernet address. */ NETIFINFO Info; - memset(&Info, 0, sizeof(Info)); + RT_ZERO(Info); int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); if (Sock > 0) { struct lifreq IfReq; - strcpy(IfReq.lifr_name, szNICInstance); + RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance); if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0) { memcpy(Info.IPAddress.au8, &((struct sockaddr_in *)&IfReq.lifr_addr)->sin_addr.s_addr, @@ -236,7 +243,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe if (Sock > 0) { struct lifreq IfReq; - strcpy(IfReq.lifr_name, szNICInstance); + RTStrCopy(IfReq.lifr_name, sizeof(IfReq.lifr_name), szNICInstance); if (ioctl(Sock, SIOCGLIFADDR, &IfReq) >= 0) { memcpy(Info.IPv6Address.au8, ((struct sockaddr_in6 *)&IfReq.lifr_addr)->sin6_addr.s6_addr, @@ -269,7 +276,7 @@ static void vboxSolarisAddHostIface(char *pszIface, int Instance, void *pvHostNe strncpy(Info.szShortName, szNICInstance, sizeof(Info.szShortName) - 1); HostNetworkInterfaceType_T enmType; - if (strncmp("vboxnet", szNICInstance, 7)) + if (strncmp(szNICInstance, RT_STR_TUPLE("vboxnet"))) enmType = HostNetworkInterfaceType_Bridged; else enmType = HostNetworkInterfaceType_HostOnly; @@ -285,15 +292,15 @@ static boolean_t vboxSolarisAddLinkHostIface(const char *pszIface, void *pvHostN /* * Skip IPSEC interfaces. It's at IP level. */ - if (!strncmp(pszIface, "ip.tun", 6)) + if (!strncmp(pszIface, RT_STR_TUPLE("ip.tun"))) return _B_FALSE; /* * Skip our own dynamic VNICs but don't skip VNIC templates. * These names originate from VBoxNetFltBow-solaris.c, hardcoded here for now. */ - if ( strncmp(pszIface, "vboxvnic_template", 17) - && !strncmp(pszIface, "vboxvnic", 8)) + if ( strncmp(pszIface, RT_STR_TUPLE("vboxvnic_template")) + && !strncmp(pszIface, RT_STR_TUPLE("vboxvnic"))) return _B_FALSE; /* @@ -406,59 +413,65 @@ int NetIfList(std::list > &list) if (Sock > 0) { struct lifnum IfNum; - memset(&IfNum, 0, sizeof(IfNum)); + RT_ZERO(IfNum); IfNum.lifn_family = AF_INET; int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum); if (!rc) { - struct lifreq Ifaces[24]; - struct lifconf IfConfig; - memset(&IfConfig, 0, sizeof(IfConfig)); - IfConfig.lifc_family = AF_INET; - IfConfig.lifc_len = sizeof(Ifaces); - IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]); - rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig); - if (!rc) + int cIfaces = RT_MIN(1024, IfNum.lifn_count); /* sane limit */ + int cbIfaces = cIfaces * sizeof(struct lifreq); + struct lifreq *Ifaces = (struct lifreq *)RTMemTmpAlloc(cbIfaces); + if (Ifaces) { - for (int i = 0; i < IfNum.lifn_count; i++) + struct lifconf IfConfig; + RT_ZERO(IfConfig); + IfConfig.lifc_family = AF_INET; + IfConfig.lifc_len = cbIfaces; + IfConfig.lifc_buf = (caddr_t)Ifaces; + rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig); + if (!rc) { - /* - * Skip loopback interfaces. - */ - if (!strncmp(Ifaces[i].lifr_name, "lo", 2)) - continue; - -#if 0 - rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i])); - if (rc >= 0) + for (int i = 0; i < cIfaces; i++) { - memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data, - sizeof(Info.IPAddress.au8)); - // SIOCGLIFNETMASK - struct arpreq ArpReq; - memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in)); - /* - * We might fail if the interface has not been assigned an IP address. - * That doesn't matter; as long as it's plumbed we can pick it up. - * But, if it has not acquired an IP address we cannot obtain it's MAC - * address this way, so we just use all zeros there. + * Skip loopback interfaces. */ - rc = ioctl(Sock, SIOCGARP, &ArpReq); + if (!strncmp(Ifaces[i].lifr_name, RT_STR_TUPLE("lo"))) + continue; + +#if 0 + rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i])); if (rc >= 0) - memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress)); + { + memcpy(Info.IPAddress.au8, ((struct sockaddr *)&Ifaces[i].lifr_addr)->sa_data, + sizeof(Info.IPAddress.au8)); + // SIOCGLIFNETMASK + struct arpreq ArpReq; + memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in)); + + /* + * We might fail if the interface has not been assigned an IP address. + * That doesn't matter; as long as it's plumbed we can pick it up. + * But, if it has not acquired an IP address we cannot obtain it's MAC + * address this way, so we just use all zeros there. + */ + rc = ioctl(Sock, SIOCGARP, &ArpReq); + if (rc >= 0) + memcpy(&Info.MACAddress, ArpReq.arp_ha.sa_data, sizeof(Info.MACAddress)); + + char szNICDesc[LIFNAMSIZ + 256]; + char *pszIface = Ifaces[i].lifr_name; + strcpy(szNICDesc, pszIface); + + vboxSolarisAddLinkHostIface(pszIface, &list); + } +#endif - char szNICDesc[LIFNAMSIZ + 256]; char *pszIface = Ifaces[i].lifr_name; - strcpy(szNICDesc, pszIface); - vboxSolarisAddLinkHostIface(pszIface, &list); } -#endif - - char *pszIface = Ifaces[i].lifr_name; - vboxSolarisAddLinkHostIface(pszIface, &list); } + RTMemTmpFree(Ifaces); } } close(Sock); @@ -486,3 +499,17 @@ int NetIfGetConfigByName(PNETIFINFO pInfo) return VERR_NOT_IMPLEMENTED; } +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits) +{ + *puMbits = kstatGet(pcszIfName); + return VINF_SUCCESS; +} diff --git a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp index 7abeae04..ed935116 100644 --- a/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/PerformanceSolaris.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -26,33 +26,85 @@ #include #include #include +#include +#include #include #include #include #include #include -#include +#include +#include + +#include "Logging.h" #include "Performance.h" +#include + +#include +#include + +#include + namespace pm { + typedef libzfs_handle_t *(*PFNZFSINIT)(void); + typedef void (*PFNZFSFINI)(libzfs_handle_t *); + typedef zfs_handle_t *(*PFNZFSOPEN)(libzfs_handle_t *, const char *, int); + typedef void (*PFNZFSCLOSE)(zfs_handle_t *); + typedef uint64_t (*PFNZFSPROPGETINT)(zfs_handle_t *, zfs_prop_t); + typedef zpool_handle_t *(*PFNZPOOLOPEN)(libzfs_handle_t *, const char *); + typedef void (*PFNZPOOLCLOSE)(zpool_handle_t *); + typedef nvlist_t *(*PFNZPOOLGETCONFIG)(zpool_handle_t *, nvlist_t **); + typedef char *(*PFNZPOOLVDEVNAME)(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, boolean_t); + + typedef std::map FsMap; + class CollectorSolaris : public CollectorHAL { public: CollectorSolaris(); virtual ~CollectorSolaris(); virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available); + virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available); + virtual int getHostDiskSize(const char *name, uint64_t *size); virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used); virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle); virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx); + virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms); virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); + + virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad); private: static uint32_t getInstance(const char *pszIfaceName, char *pszDevName); - kstat_ctl_t *mKC; - kstat_t *mSysPages; - kstat_t *mZFSCache; + uint64_t getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName); + void updateFilesystemMap(void); + RTCString physToInstName(const char *pcszPhysName); + RTCString pathToInstName(const char *pcszDevPathName); + uint64_t wrapCorrection(uint32_t cur, uint64_t prev, const char *name); + uint64_t wrapDetection(uint64_t cur, uint64_t prev, const char *name); + + kstat_ctl_t *mKC; + kstat_t *mSysPages; + kstat_t *mZFSCache; + + void *mZfsSo; + libzfs_handle_t *mZfsLib; + PFNZFSINIT mZfsInit; + PFNZFSFINI mZfsFini; + PFNZFSOPEN mZfsOpen; + PFNZFSCLOSE mZfsClose; + PFNZFSPROPGETINT mZfsPropGetInt; + PFNZPOOLOPEN mZpoolOpen; + PFNZPOOLCLOSE mZpoolClose; + PFNZPOOLGETCONFIG mZpoolGetConfig; + PFNZPOOLVDEVNAME mZpoolVdevName; + + FsMap mFsMap; + uint32_t mCpus; + ULONG totalRAM; }; CollectorHAL *createHAL() @@ -66,7 +118,9 @@ CollectorHAL *createHAL() CollectorSolaris::CollectorSolaris() : mKC(0), mSysPages(0), - mZFSCache(0) + mZFSCache(0), + mZfsLib(0), + mCpus(0) { if ((mKC = kstat_open()) == 0) { @@ -84,12 +138,55 @@ CollectorSolaris::CollectorSolaris() { Log(("kstat_lookup(system_pages) -> %d\n", errno)); } + + /* Try to load libzfs dynamically, it may be missing. */ + mZfsSo = dlopen("libzfs.so", RTLD_LAZY); + if (mZfsSo) + { + mZfsInit = (PFNZFSINIT)(uintptr_t)dlsym(mZfsSo, "libzfs_init"); + mZfsFini = (PFNZFSFINI)(uintptr_t)dlsym(mZfsSo, "libzfs_fini"); + mZfsOpen = (PFNZFSOPEN)(uintptr_t)dlsym(mZfsSo, "zfs_open"); + mZfsClose = (PFNZFSCLOSE)(uintptr_t)dlsym(mZfsSo, "zfs_close"); + mZfsPropGetInt = (PFNZFSPROPGETINT)(uintptr_t)dlsym(mZfsSo, "zfs_prop_get_int"); + mZpoolOpen = (PFNZPOOLOPEN)(uintptr_t)dlsym(mZfsSo, "zpool_open"); + mZpoolClose = (PFNZPOOLCLOSE)(uintptr_t)dlsym(mZfsSo, "zpool_close"); + mZpoolGetConfig = (PFNZPOOLGETCONFIG)(uintptr_t)dlsym(mZfsSo, "zpool_get_config"); + mZpoolVdevName = (PFNZPOOLVDEVNAME)(uintptr_t)dlsym(mZfsSo, "zpool_vdev_name"); + + if ( mZfsInit + && mZfsOpen + && mZfsClose + && mZfsPropGetInt + && mZpoolOpen + && mZpoolClose + && mZpoolGetConfig + && mZpoolVdevName) + mZfsLib = mZfsInit(); + else + LogRel(("Incompatible libzfs? libzfs_init=%p zfs_open=%p zfs_close=%p zfs_prop_get_int=%p\n", + mZfsInit, mZfsOpen, mZfsClose, mZfsPropGetInt)); + } + + updateFilesystemMap(); + /* Notice that mCpus member will be initialized by HostCpuLoadRaw::init() */ + + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) + totalRAM = 0; + else + totalRAM = (ULONG)(cb / 1024); } CollectorSolaris::~CollectorSolaris() { if (mKC) kstat_close(mKC); + /* Not calling libzfs_fini() causes file descriptor leaks (#6788). */ + if (mZfsFini && mZfsLib) + mZfsFini(mZfsLib); + if (mZfsSo) + dlclose(mZfsSo); } int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle) @@ -123,6 +220,8 @@ int CollectorSolaris::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64 Log(("no cpu stats found!\n")); return VERR_INTERNAL_ERROR; } + else + mCpus = cpus; if (user) *user = tmpUser; if (kernel) *kernel = tmpKernel; @@ -148,8 +247,18 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui { //Assert((pid_t)process == pstatus.pr_pid); //Log(("user=%u kernel=%u total=%u\n", prusage.pr_utime.tv_sec, prusage.pr_stime.tv_sec, prusage.pr_tstamp.tv_sec)); - *user = (uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec; - *kernel = (uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec; + /* + * The CPU time spent must be adjusted by the number of cores for compatibility with + * other platforms (see @bugref{6345}). + */ + Assert(mCpus); + if (mCpus) + { + *user = ((uint64_t)prusage.pr_utime.tv_sec * 1000000000 + prusage.pr_utime.tv_nsec) / mCpus; + *kernel = ((uint64_t)prusage.pr_stime.tv_sec * 1000000000 + prusage.pr_stime.tv_nsec) / mCpus; + } + else + *user = *kernel = 0; *total = (uint64_t)prusage.pr_tstamp.tv_sec * 1000000000 + prusage.pr_tstamp.tv_nsec; //Log(("user=%llu kernel=%llu total=%llu\n", *user, *kernel, *total)); } @@ -171,61 +280,15 @@ int CollectorSolaris::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, ui int CollectorSolaris::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - int rc = VINF_SUCCESS; - - kstat_named_t *kn; - - if (mKC == 0 || mSysPages == 0) - return VERR_INTERNAL_ERROR; - - if (kstat_read(mKC, mSysPages, 0) == -1) + AssertReturn(totalRAM, VERR_INTERNAL_ERROR); + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_SUCCESS(rc)) { - Log(("kstat_read(sys_pages) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; + *total = totalRAM; + *available = cb / 1024; + *used = *total - *available; } - if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"freemem")) == 0) - { - Log(("kstat_data_lookup(freemem) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; - } - *available = kn->value.ul * (PAGE_SIZE/1024); - - if (kstat_read(mKC, mZFSCache, 0) != -1) - { - if (mZFSCache) - { - if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"size"))) - { - ulong_t ulSize = kn->value.ul; - - if ((kn = (kstat_named_t *)kstat_data_lookup(mZFSCache, (char *)"c_min"))) - { - /* - * Account for ZFS minimum arc cache size limit. - * "c_min" is the target minimum size of the ZFS cache, and not the hard limit. It's possible - * for "size" to shrink below "c_min" (e.g: during boot & high memory consumption). - */ - ulong_t ulMin = kn->value.ul; - *available += ulSize > ulMin ? (ulSize - ulMin) / 1024 : 0; - } - else - Log(("kstat_data_lookup(c_min) ->%d\n", errno)); - } - else - Log(("kstat_data_lookup(size) -> %d\n", errno)); - } - else - Log(("mZFSCache missing.\n")); - } - - if ((kn = (kstat_named_t *)kstat_data_lookup(mSysPages, (char *)"physmem")) == 0) - { - Log(("kstat_data_lookup(physmem) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; - } - *total = kn->value.ul * (PAGE_SIZE/1024); - *used = *total - *available; - return rc; } @@ -285,21 +348,53 @@ uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevNam return uInstance; } +uint64_t CollectorSolaris::wrapCorrection(uint32_t cur, uint64_t prev, const char *name) +{ + NOREF(name); + uint64_t corrected = (prev & 0xffffffff00000000) + cur; + if (cur < (prev & 0xffffffff)) + { + /* wrap has occurred */ + corrected += 0x100000000; + LogFlowThisFunc(("Corrected wrap on %s (%u < %u), returned %llu.\n", + name, cur, (uint32_t)prev, corrected)); + } + return corrected; +} + +uint64_t CollectorSolaris::wrapDetection(uint64_t cur, uint64_t prev, const char *name) +{ + static bool fNotSeen = true; + + if (fNotSeen && cur < prev) + { + fNotSeen = false; + LogRel(("Detected wrap on %s (%llu < %llu).\n", name, cur, prev)); + } + return cur; +} + +/* + * WARNING! This function expects the previous values of rx and tx counter to + * be passed in as well as returnes new values in the same parameters. This is + * needed to provide a workaround for 32-bit counter wrapping. + */ int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx) { + static bool g_fNotReported = true; AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER); LogFlowThisFunc(("m=%s i=%d n=%s\n", "link", -1, name)); - kstat_t *ksAdapter = kstat_lookup(mKC, "link", -1, (char *)name); + kstat_t *ksAdapter = kstat_lookup(mKC, (char *)"link", -1, (char *)name); if (ksAdapter == 0) { char szModule[KSTAT_STRLEN]; uint32_t uInstance = getInstance(name, szModule); LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, "phys")); - ksAdapter = kstat_lookup(mKC, szModule, uInstance, "phys"); + ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)"phys"); if (ksAdapter == 0) { LogFlowThisFunc(("m=%s i=%u n=%s\n", szModule, uInstance, name)); - ksAdapter = kstat_lookup(mKC, szModule, uInstance, name); + ksAdapter = kstat_lookup(mKC, szModule, uInstance, (char *)name); if (ksAdapter == 0) { LogRel(("Failed to get network statistics for %s\n", name)); @@ -313,24 +408,311 @@ int CollectorSolaris::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint return VERR_INTERNAL_ERROR; } kstat_named_t *kn; - if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0) + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes64")) == 0) { - LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); - return VERR_INTERNAL_ERROR; + if (g_fNotReported) + { + g_fNotReported = false; + LogRel(("Failed to locate rbytes64, falling back to 32-bit counters...\n")); + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"rbytes")) == 0) + { + LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); + return VERR_INTERNAL_ERROR; + } + *rx = wrapCorrection(kn->value.ul, *rx, "rbytes"); } - *rx = kn->value.ul; - if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0) + else + *rx = wrapDetection(kn->value.ull, *rx, "rbytes64"); + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes64")) == 0) { - LogRel(("kstat_data_lookup(obytes) -> %d\n", errno)); - return VERR_INTERNAL_ERROR; + if (g_fNotReported) + { + g_fNotReported = false; + LogRel(("Failed to locate obytes64, falling back to 32-bit counters...\n")); + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksAdapter, (char *)"obytes")) == 0) + { + LogRel(("kstat_data_lookup(obytes) -> %d\n", errno)); + return VERR_INTERNAL_ERROR; + } + *tx = wrapCorrection(kn->value.ul, *tx, "obytes"); + } + else + *tx = wrapDetection(kn->value.ull, *tx, "obytes64"); + return VINF_SUCCESS; +} + +int CollectorSolaris::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms) +{ + int rc = VINF_SUCCESS; + AssertReturn(strlen(name) < KSTAT_STRLEN, VERR_INVALID_PARAMETER); + LogFlowThisFunc(("n=%s\n", name)); + kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, (char *)name); + if (ksDisk != 0) + { + if (kstat_read(mKC, ksDisk, 0) == -1) + { + LogRel(("kstat_read(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + else + { + kstat_io_t *ksIo = KSTAT_IO_PTR(ksDisk); + /* + * We do not care for wrap possibility here, although we may + * reconsider in about 300 years (9223372036854775807 ns). + */ + *disk_ms = ksIo->rtime / 1000000; + *total_ms = ksDisk->ks_snaptime / 1000000; + } } - *tx = kn->value.ul; + else + { + LogRel(("kstat_lookup(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + + return rc; +} + +uint64_t CollectorSolaris::getZfsTotal(uint64_t cbTotal, const char *szFsType, const char *szFsName) +{ + if (strcmp(szFsType, "zfs")) + return cbTotal; + FsMap::iterator it = mFsMap.find(szFsName); + if (it == mFsMap.end()) + return cbTotal; + + char *pszDataset = strdup(it->second.c_str()); + char *pszEnd = pszDataset + strlen(pszDataset); + uint64_t uAvail = 0; + while (pszEnd) + { + zfs_handle_t *hDataset; + + *pszEnd = 0; + hDataset = mZfsOpen(mZfsLib, pszDataset, ZFS_TYPE_DATASET); + if (!hDataset) + break; + + if (uAvail == 0) + { + uAvail = mZfsPropGetInt(hDataset, ZFS_PROP_REFQUOTA); + if (uAvail == 0) + uAvail = UINT64_MAX; + } + + uint64_t uQuota = mZfsPropGetInt(hDataset, ZFS_PROP_QUOTA); + if (uQuota && uAvail > uQuota) + uAvail = uQuota; + + pszEnd = strrchr(pszDataset, '/'); + if (!pszEnd) + { + uint64_t uPoolSize = mZfsPropGetInt(hDataset, ZFS_PROP_USED) + + mZfsPropGetInt(hDataset, ZFS_PROP_AVAILABLE); + if (uAvail > uPoolSize) + uAvail = uPoolSize; + } + mZfsClose(hDataset); + } + free(pszDataset); + + return uAvail ? uAvail : cbTotal; +} + +int CollectorSolaris::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available) +{ + struct statvfs64 stats; + + if (statvfs64(path, &stats) == -1) + { + LogRel(("Failed to collect %s filesystem usage: errno=%d.\n", path, errno)); + return VERR_ACCESS_DENIED; + } + uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize; + *total = (ULONG)(getZfsTotal(cbBlock * stats.f_blocks, stats.f_basetype, path) / _1M); + LogFlowThisFunc(("f_blocks=%llu.\n", stats.f_blocks)); + *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M); + *available = (ULONG)(cbBlock * stats.f_bavail / _1M); + return VINF_SUCCESS; } -int getDiskListByFs(const char *name, DiskList& list) +int CollectorSolaris::getHostDiskSize(const char *name, uint64_t *size) { - return VERR_NOT_IMPLEMENTED; + int rc = VINF_SUCCESS; + AssertReturn(strlen(name) + 5 < KSTAT_STRLEN, VERR_INVALID_PARAMETER); + LogFlowThisFunc(("n=%s\n", name)); + char szName[KSTAT_STRLEN]; + strcpy(szName, name); + strcat(szName, ",err"); + kstat_t *ksDisk = kstat_lookup(mKC, NULL, -1, szName); + if (ksDisk != 0) + { + if (kstat_read(mKC, ksDisk, 0) == -1) + { + LogRel(("kstat_read(%s) -> %d\n", name, errno)); + rc = VERR_INTERNAL_ERROR; + } + else + { + kstat_named_t *kn; + if ((kn = (kstat_named_t *)kstat_data_lookup(ksDisk, (char *)"Size")) == 0) + { + LogRel(("kstat_data_lookup(rbytes) -> %d, name=%s\n", errno, name)); + return VERR_INTERNAL_ERROR; + } + *size = kn->value.ull; + } + } + else + { + LogRel(("kstat_lookup(%s) -> %d\n", szName, errno)); + rc = VERR_INTERNAL_ERROR; + } + + + return rc; +} + +RTCString CollectorSolaris::physToInstName(const char *pcszPhysName) +{ + FILE *fp = fopen("/etc/path_to_inst", "r"); + if (!fp) + return RTCString(); + + RTCString strInstName; + size_t cbName = strlen(pcszPhysName); + char szBuf[RTPATH_MAX]; + while (fgets(szBuf, sizeof(szBuf), fp)) + { + if (szBuf[0] == '"' && strncmp(szBuf + 1, pcszPhysName, cbName) == 0) + { + char *pszDriver, *pszInstance; + pszDriver = strrchr(szBuf, '"'); + if (pszDriver) + { + *pszDriver = '\0'; + pszDriver = strrchr(szBuf, '"'); + if (pszDriver) + { + *pszDriver++ = '\0'; + pszInstance = strrchr(szBuf, ' '); + if (pszInstance) + { + *pszInstance = '\0'; + pszInstance = strrchr(szBuf, ' '); + if (pszInstance) + { + *pszInstance++ = '\0'; + strInstName = pszDriver; + strInstName += pszInstance; + break; + } + } + } + } + } + } + fclose(fp); + + return strInstName; +} + +RTCString CollectorSolaris::pathToInstName(const char *pcszDevPathName) +{ + char szLink[RTPATH_MAX]; + if (readlink(pcszDevPathName, szLink, sizeof(szLink)) != -1) + { + char *pszStart, *pszEnd; + pszStart = strstr(szLink, "/devices/"); + pszEnd = strrchr(szLink, ':'); + if (pszStart && pszEnd) + { + pszStart += 8; // Skip "/devices" + *pszEnd = '\0'; // Trim partition + return physToInstName(pszStart); + } + } + + return RTCString(pcszDevPathName); +} + +int CollectorSolaris::getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad) +{ + FsMap::iterator it = mFsMap.find(name); + if (it == mFsMap.end()) + return VERR_INVALID_PARAMETER; + + RTCString strName = it->second.substr(0, it->second.find("/")); + if (mZpoolOpen && mZpoolClose && mZpoolGetConfig && !strName.isEmpty()) + { + zpool_handle_t *zh = mZpoolOpen(mZfsLib, strName.c_str()); + if (zh) + { + unsigned int cChildren = 0; + nvlist_t **nvChildren = NULL; + nvlist_t *nvRoot = NULL; + nvlist_t *nvConfig = mZpoolGetConfig(zh, NULL); + if ( !nvlist_lookup_nvlist(nvConfig, ZPOOL_CONFIG_VDEV_TREE, &nvRoot) + && !nvlist_lookup_nvlist_array(nvRoot, ZPOOL_CONFIG_CHILDREN, &nvChildren, &cChildren)) + { + for (unsigned int i = 0; i < cChildren; ++i) + { + uint64_t fHole = 0; + uint64_t fLog = 0; + + nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_HOLE, &fHole); + nvlist_lookup_uint64(nvChildren[i], ZPOOL_CONFIG_IS_LOG, &fLog); + + if (!fHole && !fLog) + { + char *pszChildName = mZpoolVdevName(mZfsLib, zh, nvChildren[i], _B_FALSE); + Assert(pszChildName); + RTCString strDevPath("/dev/dsk/"); + strDevPath += pszChildName; + char szLink[RTPATH_MAX]; + if (readlink(strDevPath.c_str(), szLink, sizeof(szLink)) != -1) + { + char *pszStart, *pszEnd; + pszStart = strstr(szLink, "/devices/"); + pszEnd = strrchr(szLink, ':'); + if (pszStart && pszEnd) + { + pszStart += 8; // Skip "/devices" + *pszEnd = '\0'; // Trim partition + listUsage.push_back(physToInstName(pszStart)); + } + } + free(pszChildName); + } + } + } + mZpoolClose(zh); + } + } + else + listUsage.push_back(pathToInstName(it->second.c_str())); + listLoad = listUsage; + return VINF_SUCCESS; +} + +void CollectorSolaris::updateFilesystemMap(void) +{ + FILE *fp = fopen("/etc/mnttab", "r"); + if (fp) + { + struct mnttab Entry; + int rc = 0; + resetmnttab(fp); + while ((rc = getmntent(fp, &Entry)) == 0) + mFsMap[Entry.mnt_mountp] = Entry.mnt_special; + fclose(fp); + if (rc != -1) + LogRel(("Error while reading mnttab: %d\n", rc)); + } } } diff --git a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp index 8261d990..0d6d85e8 100644 --- a/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp +++ b/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp @@ -173,7 +173,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg) char *pszCompatNames = NULL; int cCompatNames = di_compatible_names(Node, &pszCompatNames); for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1) - if (!strncmp(pszCompatNames, "usb", 3)) + if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb"))) { fUSBDevice = true; break; @@ -304,7 +304,7 @@ static int solarisWalkDeviceNode(di_node_t Node, void *pvArg) pList->pTail = pList->pHead = pCur; rc = DI_WALK_CONTINUE; - } while(0); + } while (0); di_devfs_path_free(pszDevicePath); if (!fValidDevice) @@ -322,7 +322,7 @@ static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node if (!pszDriverName) return USBDEVICESTATE_UNUSED; - if (!strncmp(pszDriverName, VBOXUSB_DRIVER_NAME, sizeof(VBOXUSB_DRIVER_NAME) - 1)) + if (!strncmp(pszDriverName, RT_STR_TUPLE(VBOXUSB_DRIVER_NAME))) return USBDEVICESTATE_HELD_BY_PROXY; NOREF(pDevice); diff --git a/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp b/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp new file mode 100644 index 00000000..1bd72233 --- /dev/null +++ b/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp @@ -0,0 +1,233 @@ +/* -*- indent-tabs-mode: nil; -*- */ +#include +#include + + +#include +#include + +#include + +#include +#include +#include "../HostDnsService.h" + +struct HostDnsServiceWin::Data +{ + HostDnsServiceWin::Data(){} + HKEY hKeyTcpipParameters; +#define DATA_DNS_UPDATE_EVENT 0 +#define DATA_SHUTDOWN_EVENT 1 +#define DATA_MAX_EVENT 2 + HANDLE haDataEvent[DATA_MAX_EVENT]; +}; + +static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent) +{ + LONG lrc = RegNotifyChangeKeyValue(hKey, + TRUE, + REG_NOTIFY_CHANGE_LAST_SET, + hEvent, + TRUE); + AssertMsgReturn(lrc == ERROR_SUCCESS, + ("Failed to register event on the key. Please debug me!"), + VERR_INTERNAL_ERROR); + + return VINF_SUCCESS; +} + +HostDnsServiceWin::HostDnsServiceWin():HostDnsMonitor(true), m(NULL) +{ + m = new Data(); + + m->haDataEvent[DATA_DNS_UPDATE_EVENT] = CreateEvent(NULL, + TRUE, FALSE, NULL); + AssertReleaseMsg(m->haDataEvent[DATA_DNS_UPDATE_EVENT], + ("Failed to create event for DNS event (%d)\n", GetLastError())); + + m->haDataEvent[DATA_SHUTDOWN_EVENT] = CreateEvent(NULL, + TRUE, FALSE, NULL); + AssertReleaseMsg(m->haDataEvent[DATA_SHUTDOWN_EVENT], + ("Failed to create event for Shutdown signal (%d)\n", GetLastError())); + + LONG lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), + 0, KEY_READ|KEY_NOTIFY, &m->hKeyTcpipParameters); + AssertReleaseMsg(lrc == ERROR_SUCCESS, + ("Failed to open Registry Key for read and update notifications (%d)\n", + GetLastError())); +} + + +HostDnsServiceWin::~HostDnsServiceWin() +{ + if (m && !m->hKeyTcpipParameters) + { + RegCloseKey(m->hKeyTcpipParameters); + m->hKeyTcpipParameters = 0; + + CloseHandle(m->haDataEvent[DATA_DNS_UPDATE_EVENT]); + CloseHandle(m->haDataEvent[DATA_SHUTDOWN_EVENT]); + + delete m; + + m = NULL; + } +} + + +HRESULT HostDnsServiceWin::init() +{ + HRESULT hrc = HostDnsMonitor::init(); + AssertComRCReturn(hrc, hrc); + + return updateInfo(); +} + + +void HostDnsServiceWin::monitorThreadShutdown() +{ + SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]); +} + + +int HostDnsServiceWin::monitorWorker() +{ + registerNotification(m->hKeyTcpipParameters, + m->haDataEvent[DATA_DNS_UPDATE_EVENT]); + + monitorThreadInitializationDone(); + + DWORD dwRc; + while (true) + { + dwRc = WaitForMultipleObjects(DATA_MAX_EVENT, + m->haDataEvent, + FALSE, + INFINITE); + AssertMsgReturn(dwRc != WAIT_FAILED, + ("WaitForMultipleObjects failed (%d) to wait! Please debug", + GetLastError()), VERR_INTERNAL_ERROR); + + if ((dwRc - WAIT_OBJECT_0) == DATA_DNS_UPDATE_EVENT) + { + updateInfo(); + notifyAll(); + ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]); + registerNotification(m->hKeyTcpipParameters, + m->haDataEvent[DATA_DNS_UPDATE_EVENT]); + + } + else if ((dwRc - WAIT_OBJECT_0) == DATA_SHUTDOWN_EVENT) + { + break; + } + else + { + AssertMsgFailedReturn( + ("WaitForMultipleObjects returns out of bound index %d. Please debug!", + dwRc), + VERR_INTERNAL_ERROR); + } + } + return VINF_SUCCESS; +} + + +HRESULT HostDnsServiceWin::updateInfo() +{ + HRESULT hrc; + DWORD regIndex; + BYTE abDomain[256]; + BYTE abNameServers[256]; + BYTE abSearchList[256]; + + RT_ZERO(abDomain); + RT_ZERO(abNameServers); + RT_ZERO(abSearchList); + + regIndex = 0; + do { + CHAR keyName[256]; + DWORD cbKeyName = sizeof(keyName); + DWORD keyType = 0; + BYTE keyData[1024]; + DWORD cbKeyData = sizeof(keyData); + + hrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex, keyName, &cbKeyName, 0, + &keyType, keyData, &cbKeyData); + if ( hrc == ERROR_SUCCESS + || hrc == ERROR_MORE_DATA) + { + if ( RTStrICmp("Domain", keyName) == 0 + && cbKeyData > 1 + && cbKeyData < sizeof(abDomain)) + memcpy(abDomain, keyData, cbKeyData); + + else if ( RTStrICmp("DhcpDomain", keyName) == 0 + && cbKeyData > 1 + && abDomain[0] == 0 + && cbKeyData < sizeof(abDomain)) + memcpy(abDomain, keyData, cbKeyData); + + else if ( RTStrICmp("NameServer", keyName) == 0 + && cbKeyData > 1 + && cbKeyData < sizeof(abNameServers)) + memcpy(abNameServers, keyData, cbKeyData); + + else if ( RTStrICmp("DhcpNameServer", keyName) == 0 + && cbKeyData > 1 + && abNameServers[0] == 0 + && cbKeyData < sizeof(abNameServers)) + memcpy(abNameServers, keyData, cbKeyData); + + else if ( RTStrICmp("SearchList", keyName) == 0 + && cbKeyData > 1 + && cbKeyData < sizeof(abSearchList)) + memcpy(abSearchList, keyData, cbKeyData); + } + regIndex++; + } while (hrc != ERROR_NO_MORE_ITEMS); + + /* OK, now parse and update DNS structures. */ + /* domain name */ + HostDnsInformation info; + info.domain = (char*)abDomain; + + /* server list */ + strList2List(info.servers, (char *)abNameServers); + /* search list */ + strList2List(info.searchList, (char *)abSearchList); + + HostDnsMonitor::setInfo(info); + + return S_OK; +} + + +void HostDnsServiceWin::strList2List(std::vector& lst, char *strLst) +{ + char *next, *current; + char address[512]; + + AssertPtrReturnVoid(strLst); + + if (strlen(strLst) == 0) + return; + + current = strLst; + do { + RT_ZERO(address); + next = RTStrStr(current, " "); + + if (next) + strncpy(address, current, RT_MIN(sizeof(address)-1, next - current)); + else + strcpy(address, current); + + lst.push_back(std::string(address)); + + current = next + 1; + } while(next); + +} diff --git a/src/VBox/Main/src-server/win/HostPowerWin.cpp b/src/VBox/Main/src-server/win/HostPowerWin.cpp index ae806fd7..34826f9d 100644 --- a/src/VBox/Main/src-server/win/HostPowerWin.cpp +++ b/src/VBox/Main/src-server/win/HostPowerWin.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,12 +31,12 @@ extern "C" { static WCHAR gachWindowClassName[] = L"VBoxPowerNotifyClass"; -HostPowerServiceWin::HostPowerServiceWin(VirtualBox *aVirtualBox) : HostPowerService(aVirtualBox) +HostPowerServiceWin::HostPowerServiceWin(VirtualBox *aVirtualBox) : HostPowerService(aVirtualBox), mThread(NIL_RTTHREAD) { mHwnd = 0; - int rc = RTThreadCreate (&mThread, HostPowerServiceWin::NotificationThread, this, 65536, - RTTHREADTYPE_GUI, RTTHREADFLAGS_WAITABLE, "MainPower"); + int rc = RTThreadCreate(&mThread, HostPowerServiceWin::NotificationThread, this, 65536, + RTTHREADTYPE_GUI, RTTHREADFLAGS_WAITABLE, "MainPower"); if (RT_FAILURE(rc)) { @@ -55,12 +55,14 @@ HostPowerServiceWin::~HostPowerServiceWin() SetWindowLongPtr(mHwnd, 0, 0); /* Send the quit message and wait for it be processed. */ SendMessage(mHwnd, WM_QUIT, 0, 0); + RTThreadWait(mThread, 5000, NULL); + mThread = NIL_RTTHREAD; } } -DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf, void *pInstance) +DECLCALLBACK(int) HostPowerServiceWin::NotificationThread(RTTHREAD ThreadSelf, void *pInstance) { HostPowerServiceWin *pPowerObj = (HostPowerServiceWin *)pInstance; HWND hwnd = 0; @@ -68,7 +70,7 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf, /* Create a window and make it a power event notification handler. */ int rc = VINF_SUCCESS; - HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL); + HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL); /* Register the Window Class. */ WNDCLASS wc; @@ -94,10 +96,10 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf, else { /* Create the window. */ - hwnd = pPowerObj->mHwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, - gachWindowClassName, gachWindowClassName, - WS_POPUPWINDOW, - -200, -200, 100, 100, NULL, NULL, hInstance, NULL); + hwnd = pPowerObj->mHwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, + gachWindowClassName, gachWindowClassName, + WS_POPUPWINDOW, + -200, -200, 100, 100, NULL, NULL, hInstance, NULL); if (hwnd == NULL) { @@ -121,11 +123,11 @@ DECLCALLBACK(int) HostPowerServiceWin::NotificationThread (RTTHREAD ThreadSelf, Log(("HostPowerServiceWin::NotificationThread: exit thread\n")); if (hwnd) - DestroyWindow (hwnd); + DestroyWindow(hwnd); if (atomWindowClass != 0) { - UnregisterClass (gachWindowClassName, hInstance); + UnregisterClass(gachWindowClassName, hInstance); atomWindowClass = 0; } @@ -146,11 +148,11 @@ LRESULT CALLBACK HostPowerServiceWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam switch(wParam) { case PBT_APMSUSPEND: - pPowerObj->notify(HostPowerEvent_Suspend); + pPowerObj->notify(Reason_HostSuspend); break; case PBT_APMRESUMEAUTOMATIC: - pPowerObj->notify(HostPowerEvent_Resume); + pPowerObj->notify(Reason_HostResume); break; case PBT_APMPOWERSTATUSCHANGE: @@ -177,27 +179,27 @@ LRESULT CALLBACK HostPowerServiceWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam if ( rc == 0 /* STATUS_SUCCESS */ && BatteryState.EstimatedTime < 60*5) { - pPowerObj->notify(HostPowerEvent_BatteryLow); + pPowerObj->notify(Reason_HostBatteryLow); } } else /* If the machine has less than 5% battery left (and is not connected to the AC), then we should save the state. */ if (SystemPowerStatus.BatteryFlag == 4 /* critical battery status; less than 5% */) { - pPowerObj->notify(HostPowerEvent_BatteryLow); + pPowerObj->notify(Reason_HostBatteryLow); } } } break; } default: - return DefWindowProc (hwnd, msg, wParam, lParam); + return DefWindowProc(hwnd, msg, wParam, lParam); } } return TRUE; } default: - return DefWindowProc (hwnd, msg, wParam, lParam); + return DefWindowProc(hwnd, msg, wParam, lParam); } } diff --git a/src/VBox/Main/src-server/win/NetIf-win.cpp b/src/VBox/Main/src-server/win/NetIf-win.cpp index cce820da..3b86dabd 100644 --- a/src/VBox/Main/src-server/win/NetIf-win.cpp +++ b/src/VBox/Main/src-server/win/NetIf-win.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -954,7 +954,7 @@ static int vboxNetWinAddComponent(std::list > * if (hr == S_OK) { NETIFINFO Info; - memset(&Info, 0, sizeof(Info)); + RT_ZERO(Info); Info.Uuid = *(Guid(IfGuid).raw()); rc = collectNetIfInfo(name, Guid(IfGuid), &Info, iDefaultInterface); if (RT_FAILURE(rc)) @@ -1082,6 +1082,33 @@ int NetIfGetConfigByName(PNETIFINFO) return VERR_NOT_IMPLEMENTED; } +/** + * Obtain the current state of the interface. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param penmState Where to store the retrieved state. + */ +int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState) +{ + return VERR_NOT_IMPLEMENTED; +} + +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/) +{ + return VERR_NOT_IMPLEMENTED; +} + int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox, IHostNetworkInterface **aHostNetworkInterface, IProgress **aProgress, @@ -1485,7 +1512,7 @@ int NetIfList(std::list > &list) { hr = pBp->EnumBindingInterfaces(&pEnumBi); Assert(hr == S_OK); - if ( hr == S_OK ) + if (hr == S_OK) { hr = pEnumBi->Reset(); Assert(hr == S_OK); @@ -1493,7 +1520,7 @@ int NetIfList(std::list > &list) { while ((hr = pEnumBi->Next(1, &pBi, NULL)) == S_OK) { - hr = pBi->GetLowerComponent( &pMpNcc ); + hr = pBi->GetLowerComponent(&pMpNcc); Assert(hr == S_OK); if (hr == S_OK) { @@ -1527,7 +1554,7 @@ int NetIfList(std::list > &list) } else { - LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr)); + LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)\n", hr)); } VBoxNetCfgWinReleaseINetCfg(pNc, FALSE); diff --git a/src/VBox/Main/src-server/win/PerformanceWin.cpp b/src/VBox/Main/src-server/win/PerformanceWin.cpp index 48643c6d..74c2bf13 100644 --- a/src/VBox/Main/src-server/win/PerformanceWin.cpp +++ b/src/VBox/Main/src-server/win/PerformanceWin.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,8 +33,10 @@ extern "C" { } #include +#include #include #include +#include #include @@ -61,6 +63,7 @@ public: virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle); virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); + private: struct VMProcessStats { @@ -72,21 +75,20 @@ private: typedef std::map VMProcessMap; - VMProcessMap mProcessStats; + VMProcessMap mProcessStats; - typedef BOOL (WINAPI *PFNGST)( - LPFILETIME lpIdleTime, - LPFILETIME lpKernelTime, - LPFILETIME lpUserTime); - typedef NTSTATUS (WINAPI *PFNNQSI)( - SYSTEM_INFORMATION_CLASS SystemInformationClass, - PVOID SystemInformation, - ULONG SystemInformationLength, - PULONG ReturnLength); + typedef BOOL (WINAPI *PFNGST)(LPFILETIME lpIdleTime, + LPFILETIME lpKernelTime, + LPFILETIME lpUserTime); + typedef NTSTATUS (WINAPI *PFNNQSI)(SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); PFNGST mpfnGetSystemTimes; PFNNQSI mpfnNtQuerySystemInformation; - HMODULE mhNtDll; + + ULONG totalRAM; }; CollectorHAL *createHAL() @@ -94,35 +96,29 @@ CollectorHAL *createHAL() return new CollectorWin(); } -CollectorWin::CollectorWin() : CollectorHAL(), mhNtDll(0) +CollectorWin::CollectorWin() : CollectorHAL(), mpfnNtQuerySystemInformation(NULL) { - mpfnGetSystemTimes = (PFNGST)GetProcAddress( - GetModuleHandle(TEXT("kernel32.dll")), - "GetSystemTimes"); + /* Note! Both kernel32.dll and ntdll.dll can be assumed to always be present. */ + mpfnGetSystemTimes = (PFNGST)RTLdrGetSystemSymbol("kernel32.dll", "GetSystemTimes"); if (!mpfnGetSystemTimes) { /* Fall back to deprecated NtQuerySystemInformation */ - if (!(mhNtDll = LoadLibrary(TEXT("ntdll.dll")))) - { - LogRel(("Failed to load NTDLL.DLL with error 0x%x. GetSystemTimes() is" - " not available either. CPU and VM metrics will not be collected.\n", - GetLastError())); - mpfnNtQuerySystemInformation = 0; - } - else if (!(mpfnNtQuerySystemInformation = (PFNNQSI)GetProcAddress(mhNtDll, - "NtQuerySystemInformation"))) - { - LogRel(("Neither GetSystemTimes() nor NtQuerySystemInformation() is" - " not available. CPU and VM metrics will not be collected.\n")); - mpfnNtQuerySystemInformation = 0; - } + mpfnNtQuerySystemInformation = (PFNNQSI)RTLdrGetSystemSymbol("ntdll.dll", "NtQuerySystemInformation"); + if (!mpfnNtQuerySystemInformation) + LogRel(("Warning! Neither GetSystemTimes() nor NtQuerySystemInformation() is not available.\n" + " CPU and VM metrics will not be collected! (lasterr %u)\n", GetLastError())); } + + uint64_t cb; + int rc = RTSystemQueryTotalRam(&cb); + if (RT_FAILURE(rc)) + totalRAM = 0; + else + totalRAM = (ULONG)(cb / 1024); } CollectorWin::~CollectorWin() { - if (mhNtDll) - FreeLibrary(mhNtDll); } #define FILETTIME_TO_100NS(ft) (((uint64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime) @@ -278,7 +274,7 @@ int CollectorWin::getHostCpuMHz(ULONG *mhz) return VERR_NO_MEMORY; LONG ns = CallNtPowerInformation(ProcessorInformation, NULL, 0, ppi, - nProcessors * sizeof(PROCESSOR_POWER_INFORMATION)); + nProcessors * sizeof(PROCESSOR_POWER_INFORMATION)); if (ns) { Log(("CallNtPowerInformation() -> %x\n", ns)); @@ -300,19 +296,16 @@ int CollectorWin::getHostCpuMHz(ULONG *mhz) int CollectorWin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available) { - MEMORYSTATUSEX mstat; - - mstat.dwLength = sizeof(mstat); - if (GlobalMemoryStatusEx(&mstat)) + AssertReturn(totalRAM, VERR_INTERNAL_ERROR); + uint64_t cb; + int rc = RTSystemQueryAvailableRam(&cb); + if (RT_SUCCESS(rc)) { - *total = (ULONG)( mstat.ullTotalPhys / 1024 ); - *available = (ULONG)( mstat.ullAvailPhys / 1024 ); + *total = totalRAM; + *available = (ULONG)(cb / 1024); *used = *total - *available; } - else - return RTErrConvertFromWin32(GetLastError()); - - return VINF_SUCCESS; + return rc; } int CollectorWin::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel) @@ -348,9 +341,4 @@ int CollectorWin::getProcessMemoryUsage(RTPROCESS process, ULONG *used) return VINF_SUCCESS; } -int getDiskListByFs(const char *name, DiskList& list) -{ - return VERR_NOT_IMPLEMENTED; -} - } diff --git a/src/VBox/Main/src-server/win/svchlp.cpp b/src/VBox/Main/src-server/win/svchlp.cpp index 2191f3fa..a3c07ff6 100644 --- a/src/VBox/Main/src-server/win/svchlp.cpp +++ b/src/VBox/Main/src-server/win/svchlp.cpp @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/win/svchlp.h b/src/VBox/Main/src-server/win/svchlp.h index 0e8b8b80..a5df8dba 100644 --- a/src/VBox/Main/src-server/win/svchlp.h +++ b/src/VBox/Main/src-server/win/svchlp.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/win/svcmain.cpp b/src/VBox/Main/src-server/win/svcmain.cpp index 111c2dd4..5e2c251b 100644 --- a/src/VBox/Main/src-server/win/svcmain.cpp +++ b/src/VBox/Main/src-server/win/svcmain.cpp @@ -327,19 +327,26 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpC * registering/unregistering or calling the helper functionality. */ if (fRun) { + /** @todo Merge this code with server.cpp (use Logging.cpp?). */ + char szLogFile[RTPATH_MAX]; if (!pszLogFile) { - char szLogFile[RTPATH_MAX]; vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile)); if (RT_SUCCESS(vrc)) vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log"); - if (RT_SUCCESS(vrc)) - pszLogFile = RTStrDup(szLogFile); } + else + { + if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile)) + vrc = VERR_NO_MEMORY; + } + if (RT_FAILURE(vrc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc); + char szError[RTPATH_MAX + 128]; - vrc = com::VBoxLogRelCreate("COM Server", pszLogFile, + vrc = com::VBoxLogRelCreate("COM Server", szLogFile, RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG, - "all", "VBOXSVC_RELEASE_LOG", + VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG", RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */, cHistory, uHistoryFileTime, uHistoryFileSize, szError, sizeof(szError)); diff --git a/src/VBox/Main/src-server/xpcom/server.cpp b/src/VBox/Main/src-server/xpcom/server.cpp index 6c48fcba..24ff15a8 100644 --- a/src/VBox/Main/src-server/xpcom/server.cpp +++ b/src/VBox/Main/src-server/xpcom/server.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2004-2012 Oracle Corporation + * Copyright (C) 2004-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,10 +20,6 @@ #include -#ifdef XPCOM_GLUE -# include -#endif - #include #include @@ -66,7 +62,7 @@ #include "AudioAdapterImpl.h" #include "BandwidthControlImpl.h" #include "BandwidthGroupImpl.h" -#include "DHCPServerRunner.h" +#include "NetworkServiceRunner.h" #include "DHCPServerImpl.h" #include "GuestOSTypeImpl.h" #include "HostImpl.h" @@ -77,7 +73,6 @@ #include "NATEngineImpl.h" #include "NetworkAdapterImpl.h" #include "ParallelPortImpl.h" -#include "ProgressCombinedImpl.h" #include "ProgressProxyImpl.h" #include "SerialPortImpl.h" #include "SharedFolderImpl.h" @@ -85,6 +80,7 @@ #include "StorageControllerImpl.h" #include "SystemPropertiesImpl.h" #include "USBControllerImpl.h" +#include "USBDeviceFiltersImpl.h" #include "VFSExplorerImpl.h" #include "VirtualBoxImpl.h" #include "VRDEServerImpl.h" @@ -96,6 +92,8 @@ #ifdef VBOX_WITH_EXTPACK # include "ExtPackManagerImpl.h" #endif +# include "NATNetworkImpl.h" + /* implement nsISupports parts of our objects with support for nsIClassInfo */ @@ -126,18 +124,12 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot) NS_DECL_CLASSINFO(Medium) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Medium, IMedium) -NS_DECL_CLASSINFO(MediumFormat) -NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumFormat, IMediumFormat) - NS_DECL_CLASSINFO(MediumAttachment) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumAttachment, IMediumAttachment) NS_DECL_CLASSINFO(Progress) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress) -NS_DECL_CLASSINFO(CombinedProgress) -NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress) - NS_DECL_CLASSINFO(ProgressProxy) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress) @@ -156,6 +148,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostNetworkInterface, IHostNetworkInterface) NS_DECL_CLASSINFO(DHCPServer) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DHCPServer, IDHCPServer) +NS_DECL_CLASSINFO(NATNetwork) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NATNetwork, INATNetwork) + NS_DECL_CLASSINFO(GuestOSType) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType) @@ -175,6 +170,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort) NS_DECL_CLASSINFO(USBController) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController) +NS_DECL_CLASSINFO(USBDeviceFilters) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilters, IUSBDeviceFilters) + NS_DECL_CLASSINFO(StorageController) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(StorageController, IStorageController) @@ -881,23 +879,26 @@ int main(int argc, char **argv) nsresult rc; + /** @todo Merge this code with svcmain.cpp (use Logging.cpp?). */ + char szLogFile[RTPATH_MAX]; if (!pszLogFile) { - char szLogFile[RTPATH_MAX] = ""; vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile)); - if (vrc == VERR_ACCESS_DENIED) - return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open global settings directory '%s'", szLogFile); if (RT_SUCCESS(vrc)) vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log"); - if (RT_SUCCESS(vrc)) - pszLogFile = RTStrDup(szLogFile); - if (RT_FAILURE(vrc)) - return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to determine release log file (%Rrc)", vrc); } + else + { + if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile)) + vrc = VERR_NO_MEMORY; + } + if (RT_FAILURE(vrc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc); + char szError[RTPATH_MAX + 128]; - vrc = com::VBoxLogRelCreate("XPCOM Server", pszLogFile, + vrc = com::VBoxLogRelCreate("XPCOM Server", szLogFile, RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG, - "all", "VBOXSVC_RELEASE_LOG", + VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG", RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */, cHistory, uHistoryFileTime, uHistoryFileSize, szError, sizeof(szError)); diff --git a/src/VBox/Main/src-server/xpcom/server.h b/src/VBox/Main/src-server/xpcom/server.h index f14977af..4fbaa231 100644 --- a/src/VBox/Main/src-server/xpcom/server.h +++ b/src/VBox/Main/src-server/xpcom/server.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/src-server/xpcom/server_module.cpp b/src/VBox/Main/src-server/xpcom/server_module.cpp index 0647016c..11cf239e 100644 --- a/src/VBox/Main/src-server/xpcom/server_module.cpp +++ b/src/VBox/Main/src-server/xpcom/server_module.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -53,10 +53,9 @@ #include #include #include +#include #include -#include - #if defined(RT_OS_SOLARIS) # include #endif @@ -92,8 +91,8 @@ static bool IsVBoxSVCPathSet = false; * in sync with macros used for VirtualBox in server.cpp for the same purpose. */ -NS_DECL_CLASSINFO (VirtualBox) -NS_IMPL_CI_INTERFACE_GETTER1 (VirtualBox, IVirtualBox) +NS_DECL_CLASSINFO(VirtualBox) +NS_IMPL_CI_INTERFACE_GETTER1(VirtualBox, IVirtualBox) static nsresult vboxsvcSpawnDaemon(void) { @@ -137,7 +136,7 @@ static nsresult vboxsvcSpawnDaemon(void) writable = nsnull; char msg[10]; - memset(msg, '\0', sizeof(msg)); + RT_ZERO(msg); if ( PR_Read(readable, msg, sizeof(msg)-1) != 5 || strcmp(msg, "READY")) { @@ -168,8 +167,8 @@ end: * VirtualBox component defined on the server. */ static NS_IMETHODIMP -VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, - void **aResult) +VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID, + void **aResult) { LogFlowFuncEnter(); @@ -189,25 +188,25 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, { /* Get the directory containing XPCOM components -- the VBoxSVC * executable is expected in the parent directory. */ - nsCOMPtr dirServ = do_GetService (NS_DIRECTORY_SERVICE_CONTRACTID, &rc); + nsCOMPtr dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc); if (NS_SUCCEEDED(rc)) { - nsCOMPtr componentDir; - rc = dirServ->Get (NS_XPCOM_COMPONENT_DIR, - NS_GET_IID (nsIFile), getter_AddRefs (componentDir)); + nsCOMPtr componentDir; + rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(componentDir)); if (NS_SUCCEEDED(rc)) { nsCAutoString path; - componentDir->GetNativePath (path); + componentDir->GetNativePath(path); - LogFlowFunc (("component directory = \"%s\"\n", path.get())); - AssertBreakStmt (path.Length() + strlen (VBoxSVC_exe) < RTPATH_MAX, - rc = NS_ERROR_FAILURE); + LogFlowFunc(("component directory = \"%s\"\n", path.get())); + AssertBreakStmt(path.Length() + strlen(VBoxSVC_exe) < RTPATH_MAX, + rc = NS_ERROR_FAILURE); #if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING) char achKernArch[128]; - int cbKernArch = sysinfo (SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch)); + int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch)); if (cbKernArch > 0) { sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe); @@ -216,9 +215,9 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, else rc = NS_ERROR_UNEXPECTED; #else - strcpy (VBoxSVCPath, path.get()); - RTPathStripFilename (VBoxSVCPath); - strcat (VBoxSVCPath, VBoxSVC_exe); + strcpy(VBoxSVCPath, path.get()); + RTPathStripFilename(VBoxSVCPath); + strcat(VBoxSVCPath, VBoxSVC_exe); IsVBoxSVCPathSet = true; #endif @@ -228,7 +227,7 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, break; } - nsCOMPtr ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc); + nsCOMPtr ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc); if (NS_FAILED(rc)) break; @@ -239,13 +238,13 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, do { - LogFlowFunc (("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME)); + LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME)); PRUint32 serverID = 0; - rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID); + rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID); if (NS_FAILED(rc)) { - LogFlowFunc (("Starting server \"%s\"...\n", VBoxSVCPath)); + LogFlowFunc(("Starting server \"%s\"...\n", VBoxSVCPath)); startedOnce = true; @@ -256,8 +255,8 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, /* wait for the server process to establish a connection */ do { - RTThreadSleep (VBoxSVC_WaitSlice); - rc = ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID); + RTThreadSleep(VBoxSVC_WaitSlice); + rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID); if (NS_SUCCEEDED(rc)) break; if (timeLeft <= VBoxSVC_WaitSlice) @@ -276,20 +275,20 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, } } - LogFlowFunc (("Connecting to server (ID=%d)...\n", serverID)); + LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID)); - nsCOMPtr dconServ = - do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc); + nsCOMPtr dconServ = + do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc); if (NS_FAILED(rc)) break; - rc = dconServ->CreateInstance (serverID, - CLSID_VirtualBox, - aIID, aResult); + rc = dconServ->CreateInstance(serverID, + CLSID_VirtualBox, + aIID, aResult); if (NS_SUCCEEDED(rc)) break; - LogFlowFunc (("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc)); + LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc)); /* It's possible that the server gets shut down after we * successfully resolve the server name but before it @@ -298,12 +297,11 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, if (!startedOnce) { nsresult rc2 = - ipcServ->ResolveClientName (VBOXSVC_IPC_NAME, &serverID); + ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID); if (NS_SUCCEEDED(rc2)) break; - LogFlowFunc (("Server seems to have terminated before " - "receiving our request. Will try again.\n")); + LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n")); } else break; @@ -312,7 +310,7 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, } while (0); - LogFlowFunc (("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc)); + LogFlowFunc(("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc)); LogFlowFuncLeave(); return rc; @@ -331,19 +329,19 @@ VirtualBoxConstructor (nsISupports *aOuter, REFNSIID aIID, * @return */ static NS_IMETHODIMP -VirtualBoxRegistration (nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *aLoaderStr, - const char *aType, - const nsModuleComponentInfo *aInfo) +VirtualBoxRegistration(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *aLoaderStr, + const char *aType, + const nsModuleComponentInfo *aInfo) { nsCAutoString modulePath; - aPath->GetNativePath (modulePath); + aPath->GetNativePath(modulePath); nsCAutoString moduleTarget; - aPath->GetNativeTarget (moduleTarget); + aPath->GetNativeTarget(moduleTarget); - LogFlowFunc (("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n", - modulePath.get(), moduleTarget.get(), aLoaderStr, aType)); + LogFlowFunc(("aPath=%s, aTarget=%s, aLoaderStr=%s, aType=%s\n", + modulePath.get(), moduleTarget.get(), aLoaderStr, aType)); nsresult rc = NS_OK; @@ -372,4 +370,4 @@ static const nsModuleComponentInfo components[] = } }; -NS_IMPL_NSGETMODULE (VirtualBox_Server_Module, components) +NS_IMPL_NSGETMODULE(VirtualBox_Server_Module, components) diff --git a/src/VBox/Main/testcase/Makefile.kmk b/src/VBox/Main/testcase/Makefile.kmk index 76ba6455..e08f5979 100644 --- a/src/VBox/Main/testcase/Makefile.kmk +++ b/src/VBox/Main/testcase/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2004-2012 Oracle Corporation +# Copyright (C) 2004-2013 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -18,6 +18,7 @@ SUB_DEPTH = ../../../.. include $(KBUILD_PATH)/subheader.kmk + # # Target and globals (small mess) # @@ -26,10 +27,12 @@ ifndef VBOX_ONLY_SDK PROGRAMS += \ tstAPI \ $(if $(VBOX_OSE),,tstOVF) \ - $(if $(VBOX_WITH_XPCOM),tstVBoxAPILinux,tstVBoxAPIWin) \ + $(if $(VBOX_WITH_XPCOM),tstVBoxAPIXPCOM,tstVBoxAPIWin) \ $(if $(VBOX_WITH_RESOURCE_USAGE_API),tstCollector,) \ $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlParseBuffer,) \ - $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) + $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) \ + tstMediumLock \ + tstMouseImpl PROGRAMS.linux += \ $(if $(VBOX_WITH_USB),tstUSBProxyLinux,) endif # !VBOX_WITH_TESTCASES @@ -47,43 +50,27 @@ endif # samplesMSCOM_MODE = a+r,u+w samplesMSCOM_INST = $(INST_SDK)bindings/mscom/samples/ -samplesMSCOM_SOURCES = tstVBoxAPIWin.cpp +samplesMSCOM_SOURCES = tstVBoxAPIWin.cpp makefile.tstVBoxAPIWin=>Makefile samplesXPCOM_MODE = a+r,u+w samplesXPCOM_INST = $(INST_SDK)bindings/xpcom/samples/ -samplesXPCOM_SOURCES = tstVBoxAPILinux.cpp makefile.tstVBoxAPILinux=>Makefile +samplesXPCOM_SOURCES = tstVBoxAPIXPCOM.cpp makefile.tstVBoxAPIXPCOM=>Makefile # # tstAPI # -tstAPI_TEMPLATE = VBOXMAINCLIENTEXE +tstAPI_TEMPLATE = VBOXMAINCLIENTTSTEXE #tstAPI_INST = $(INST_SDK)bindings/gluecom/samples/ tstAPI_SOURCES = tstAPI.cpp -ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template. -tstAPI_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h -else -tstAPI_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h -endif -ifdef VBOX_WITH_RESOURCE_USAGE_API -tstAPI_DEFS += VBOX_WITH_RESOURCE_USAGE_API -endif # # tstOVF # -tstOVF_TEMPLATE = VBOXMAINCLIENTEXE +tstOVF_TEMPLATE = VBOXMAINCLIENTTSTEXE #tstOVF_INST = $(INST_SDK)bindings/gluecom/samples/ tstOVF_SOURCES = tstOVF.cpp -ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template. -tstOVF_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h -else -tstOVF_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h -endif -ifdef VBOX_WITH_RESOURCE_USAGE_API -tstOVF_DEFS += VBOX_WITH_RESOURCE_USAGE_API -endif ifndef VBOX_OSE # @@ -101,82 +88,58 @@ endif # -# tstVBoxAPILinux +# tstVBoxAPIXPCOM # # We only build the testcase here to make sure it builds. # It comes with a custom makefile which should be tested as well! # -tstVBoxAPILinux_TEMPLATE = VBOXR3EXE -tstVBoxAPILinux_SOURCES = tstVBoxAPILinux.cpp -tstVBoxAPILinux_CXXFLAGS = -Wno-non-virtual-dtor -fshort-wchar -tstVBoxAPILinux_LDFLAGS.solaris += '$(VBOX_GCC_RPATH_OPT)$$(VBOX_ORIGIN)/../../..' -ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP - tstVBoxAPILinux_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -endif -tstVBoxAPILinux_INCS = \ - $(VBOX_XPCOM_INCS) \ - $(VBOX_PATH_SDK)/bindings/xpcom/include -tstVBoxAPILinux_LIBPATH = $(LIBPATH_XPCOM) -tstVBoxAPILinux_LIBS = $(LIB_XPCOM) $(LIB_RUNTIME) -tstVBoxAPILinux_DEPS = \ - $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h +tstVBoxAPIXPCOM_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstVBoxAPIXPCOM_SOURCES = tstVBoxAPIXPCOM.cpp # # tstVBoxAPIWin # -tstVBoxAPIWin_TEMPLATE = VBOXMAINCLIENTEXE +tstVBoxAPIWin_TEMPLATE = VBOXMAINCLIENTTSTEXE tstVBoxAPIWin_SOURCES = \ tstVBoxAPIWin.cpp \ $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c -tstVBoxAPIWin_DEPS = \ - $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h # # tstCollector # -tstCollector_TEMPLATE = VBOXMAINCLIENTEXE +tstCollector_TEMPLATE = VBOXMAINCLIENTTSTEXE tstCollector_SOURCES = \ tstCollector.cpp \ ../src-server/Performance.cpp tstCollector_INCS = ../include tstCollector_DEFS += VBOX_COLLECTOR_TEST_CASE tstCollector_LDFLAGS.darwin += -lproc -tstCollector_LDFLAGS.solaris += -lkstat +tstCollector_LDFLAGS.solaris += -lkstat -lnvpair tstCollector_LDFLAGS.win += psapi.lib powrprof.lib # # tstGuestCtrlParseBuffer # -tstGuestCtrlParseBuffer_TEMPLATE = VBOXMAINCLIENTEXE -tstGuestCtrlParseBuffer_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL +tstGuestCtrlParseBuffer_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuestCtrlParseBuffer_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE tstGuestCtrlParseBuffer_SOURCES = \ tstGuestCtrlParseBuffer.cpp \ ../src-client/GuestCtrlPrivate.cpp tstGuestCtrlParseBuffer_INCS = ../include -ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template. - tstGuestCtrlParseBuffer_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h -else - tstGuestCtrlParseBuffer_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h -endif # # tstGuestCtrlContextID # -tstGuestCtrlContextID_TEMPLATE = VBOXMAINCLIENTEXE -tstGuestCtrlContextID_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL +tstGuestCtrlContextID_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuestCtrlContextID_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE tstGuestCtrlContextID_SOURCES = \ tstGuestCtrlContextID.cpp \ ../src-client/GuestCtrlPrivate.cpp tstGuestCtrlContextID_INCS = ../include -ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template. - tstGuestCtrlContextID_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h -else - tstGuestCtrlContextID_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h -endif # @@ -205,6 +168,39 @@ tstUSBProxyLinux_LIBS += \ $(PATH_OUT)/lib/VBoxCOM.a +# +# tstMediumLock +# +tstMediumLock_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstMediumLock_SOURCES = tstMediumLock.cpp + + +# +# tstMouseImpl +# +tstMouseImpl_TEMPLATE = VBOXMAINTSTEXE +tstMouseImpl_SOURCES = \ + tstMouseImpl.cpp \ + ../src-client/MouseImpl.cpp \ + ../src-all/EventImpl.cpp \ + ../src-all/VirtualBoxBase.cpp \ + ../src-all/VirtualBoxErrorInfoImpl.cpp \ + $(VBOX_AUTOGEN_EVENT_CPP) \ + $(VBOX_XML_SCHEMADEFS_CPP) +tstMouseImpl_INCS = ../include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(dir $(VBOX_XML_SCHEMADEFS_H)) +tstMouseImpl_LIBS = \ + $(PATH_STAGE_LIB)/VBoxAPIWrap$(VBOX_SUFF_LIB) \ + $(LIB_VMM) +# Super ugly hack to make the code work well enough without having ATL/COM +# completely initialized, without it there are crashes caused by ComObjPtr +# and many other pieces of glue code, as the inproc code path is more picky. +tstMouseImpl_DEFS.win += VBOX_COM_OUTOFPROC_MODULE + + # generate rules. include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp b/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp index a2e6c1bc..cdc19c8a 100644 --- a/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp +++ b/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp @@ -1,6 +1,6 @@ Type=Exe Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINDOWS\system32\stdole2.tlb#OLE Automation -Reference=*\G{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}#1.0#0#VBoxC.dll#InnoTek VirtualBox Machine Type Library +Reference=*\G{D7569351-1750-46F0-936E-BD127D5BC264}#1.3#0#VBoxC.dll#InnoTek VirtualBox Machine Type Library Form=TestForm.frm Startup="TestForm" ExeName32="VBoxVBTest.exe" diff --git a/src/VBox/Main/testcase/makefile.tstVBoxAPILinux b/src/VBox/Main/testcase/makefile.tstVBoxAPILinux deleted file mode 100644 index 4239d50e..00000000 --- a/src/VBox/Main/testcase/makefile.tstVBoxAPILinux +++ /dev/null @@ -1,48 +0,0 @@ -# -# tstVBoxAPILinux makefile -# -# -# Copyright (C) 2006-2007 Oracle Corporation -# -# This file is part of VirtualBox Open Source Edition (OSE), as -# available from http://www.virtualbox.org. This file is free software; -# you can redistribute it and/or modify it under the terms of the GNU -# General Public License (GPL) as published by the Free Software -# Foundation, in version 2 as it comes in the "COPYING" file of the -# VirtualBox OSE distribution. VirtualBox OSE is distributed in the -# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -# - -PATH_XPCOM = .. -PATH_BIN = ../../../../ - -# This setting must be the same as used when building VBoxXPCOM.so. -# If you get a lot of unresolved symbols, try commenting it out. -VBOX_WITH_XPCOM_NAMESPACE_CLEANUP=1 - -PATH_XPCOM_IDL = $(PATH_XPCOM)/idl -INCS_XPCOM = $(PATH_XPCOM)/include \ - $(PATH_XPCOM)/include/nsprpub \ - $(PATH_XPCOM)/include/string \ - $(PATH_XPCOM)/include/xpcom \ - $(PATH_XPCOM)/include/ipcd - -ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP - DEFS_XPCOM += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP -endif - - -# -# Link with the public XPCOM libraries -# -tstVBoxAPILinux: tstVBoxAPILinux.o - g++ -g -o $@ $^ \ - $(PATH_BIN)/VBoxXPCOM.so \ - -Wl,-rpath $(PATH_BIN)/ \ - -ldl -lpthread - -tstVBoxAPILinux.o: tstVBoxAPILinux.cpp - g++ -c -DRT_OS_LINUX -g -fshort-wchar $(addprefix -I, $(INCS_XPCOM)) $(addprefix -D, $(DEFS_XPCOM)) -o $@ tstVBoxAPILinux.cpp - -clean: - rm -f tstVBoxAPILinux tstVBoxAPILinux.o diff --git a/src/VBox/Main/testcase/makefile.tstVBoxAPIWin b/src/VBox/Main/testcase/makefile.tstVBoxAPIWin new file mode 100644 index 00000000..fbbc16bf --- /dev/null +++ b/src/VBox/Main/testcase/makefile.tstVBoxAPIWin @@ -0,0 +1,88 @@ +# +# tstVBoxAPILinux makefile +# +# +# Copyright (C) 2006-2013 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# Several assumptions and propositions: +# - Visual Studio has already installed on machine or you already have nmake.exe, cl.exe, link.exe +# - Windows SDK has already installed on machine or you already have Uuid.Lib Ole32.Lib OleAut32.Lib OleDlg.Lib +# - VirtualBox SDK was downloaded and was placed into folder where VirtualBox had been installed. +# - nmake is a default tool that builds projects based on commands contained in this description file +# - cl is cl.exe - Windows compiler +# - link is link.exe - Windows linker +# - all needed paths have been set in working environment. It means that when you type "cl" from the console, +# Windows shall find cl.exe by using enviroment variable PATH or something similar. +# +# The best way to accomplish it is to run a script vcvars32.bat located in the Visual studio "bin" directory. +# This script installs needed paths in your working environment. +# Important!!! +# Script vcvars32.bat sets up needed paths only for local console session. +# For permanent using, needed paths must be added globally. +# +# Several possible examples of paths: +# VS_INSTALL_PATH = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\" +# VS_INCLUDE_PATH = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include" +# VS_ATLMFC_INCLUDE_PATH = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include" +# WIN_SDK_INCLUDE_PATH = "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include" +# WIN_SDK_LIB_PATH = "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\x64\" +# VB_INSTALL_PATH = "C:\Program Files\Oracle\VirtualBox" +# + + +CXX = cl +LINK = link +PATH_MSCOM = ../../../bindings/mscom +INCS_MSCOM = $(PATH_MSCOM)/include +LIBS_MSCOM = $(PATH_MSCOM)/lib + +LIBS_DEPS = "Uuid.Lib" "Ole32.Lib" "OleAut32.Lib" "OleDlg.Lib" + +tstVBoxAPIWin_SOURCES = $(LIBS_MSCOM)/VirtualBox_i.c +tstVBoxAPIWin_DEPS = $(INCS_MSCOM) + +COMPILER_CMDLINE = /Zi /nologo /W3 /WX- /Od /Oy- /Gm /EHsc /RTC1 /GS /fp:precise /Gd /analyze- /errorReport:queue + +LINKER_CMDLINE = /INCREMENTAL /DEBUG /SUBSYSTEM:CONSOLE + +# default linking +tstVBoxAPIWin.exe: tstVBoxAPIWin.obj VirtualBox_i.obj + $(LINK) /out:tstVBoxAPIWin.exe $** $(LIBS_DEPS) + +# default compilation +tstVBoxAPIWin.obj: + $(CXX) /c /I$(INCS_MSCOM) tstVBoxAPIWin.cpp + +# default compilation +VirtualBox_i.obj: + $(CXX) /c /I$(INCS_MSCOM) $(tstVBoxAPIWin_SOURCES) + +# linking with defined linker's options +#tstVBoxAPIWin.exe: tstVBoxAPIWin.obj VirtualBox_i.obj +# $(LINK) $(LINKER_CMDLINE) /out:tstVBoxAPIWin.exe $** $(LIBS_DEPS) + +# compile with pre-defined compiler's options and locally defined paths +#tstVBoxAPIWin.obj: +# $(CXX) /c $(COMPILER_CMDLINE) /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) tstVBoxAPIWin.cpp + +# compile with locally defined paths +#tstVBoxAPIWin.obj: +# $(CXX) /c /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) tstVBoxAPIWin.cpp + +# compile with pre-defined compiler's options and locally defined paths +#VirtualBox_i.obj: +# $(CXX) /c $(COMPILER_CMDLINE) /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) $(tstVBoxAPIWin_SOURCES) + +# compile with locally defined paths +#VirtualBox_i.obj: +# $(CXX) /c /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) $(tstVBoxAPIWin_SOURCES) + + diff --git a/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM b/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM new file mode 100644 index 00000000..09fc2b80 --- /dev/null +++ b/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM @@ -0,0 +1,48 @@ +# +# tstVBoxAPIXPCOM makefile +# +# +# Copyright (C) 2006-2013 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +PATH_XPCOM = .. +PATH_BIN = ../../../../ + +# This setting must be the same as used when building VBoxXPCOM.so. +# If you get a lot of unresolved symbols, try commenting it out. +VBOX_WITH_XPCOM_NAMESPACE_CLEANUP=1 + +PATH_XPCOM_IDL = $(PATH_XPCOM)/idl +INCS_XPCOM = $(PATH_XPCOM)/include \ + $(PATH_XPCOM)/include/nsprpub \ + $(PATH_XPCOM)/include/string \ + $(PATH_XPCOM)/include/xpcom \ + $(PATH_XPCOM)/include/ipcd + +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + DEFS_XPCOM += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +endif + + +# +# Link with the public XPCOM libraries +# +tstVBoxAPIXPCOM: tstVBoxAPIXPCOM.o + g++ -g -o $@ $^ \ + $(PATH_BIN)/VBoxXPCOM.so \ + -Wl,-rpath $(PATH_BIN)/ \ + -ldl -lpthread + +tstVBoxAPIXPCOM.o: tstVBoxAPIXPCOM.cpp + g++ -c -g -fshort-wchar $(addprefix -I, $(INCS_XPCOM)) $(addprefix -D, $(DEFS_XPCOM)) -o $@ tstVBoxAPIXPCOM.cpp + +clean: + rm -f tstVBoxAPIXPCOM tstVBoxAPIXPCOM.o diff --git a/src/VBox/Main/testcase/tstAPI.cpp b/src/VBox/Main/testcase/tstAPI.cpp index 978d0a25..a18499e4 100644 --- a/src/VBox/Main/testcase/tstAPI.cpp +++ b/src/VBox/Main/testcase/tstAPI.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,7 +24,6 @@ #include #include #include -#include #include @@ -369,11 +368,6 @@ int main(int argc, char *argv[]) } #endif - // create the event queue - // (here it is necessary only to process remaining XPCOM/IPC events - // after the session is closed) - EventQueue eventQ; - #if 0 // the simplest COM API test //////////////////////////////////////////////////////////////////////////// @@ -1157,7 +1151,7 @@ int main(int argc, char *argv[]) RTPrintf("\n"); #endif -#if 0 +#if 1 do { // Get host ComPtr host; @@ -1212,6 +1206,35 @@ int main(int argc, char *argv[]) } while (0); #endif +#if 0 + // DNS & Co. + /////////////////////////////////////////////////////////////////////////// + /* XXX: Note it's endless loop */ + do + { + ComPtr host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + { + Bstr domainName; + CHECK_ERROR_BREAK(host,COMGETTER(DomainName)(domainName.asOutParam())); + RTPrintf("Domain name: %ls\n", domainName.raw()); + } + + com::SafeArray strs; + CHECK_ERROR_BREAK(host, COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs))); + + unsigned int i; + for (i = 0; i < strs.size(); ++i) + RTPrintf("Name server[%d]:%s\n", i, com::Utf8Str(strs[i]).c_str()); + + RTThreadSleep(1000); + } + while (1); + RTPrintf("\n"); +#endif + + #if 0 && defined(VBOX_WITH_RESOURCE_USAGE_API) do { // Get collector @@ -1495,7 +1518,7 @@ int main(int argc, char *argv[]) /* get the mutable session machine */ session->COMGETTER(Machine)(machine.asOutParam()); CHECK_ERROR_BREAK(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam())); - + RTPrintf("Creating bandwidth group named '%ls'...\n", grpName.raw()); CHECK_ERROR_BREAK(bwCtrl, CreateBandwidthGroup(grpName.raw(), BandwidthGroupType_Network, 123)); diff --git a/src/VBox/Main/testcase/tstCollector.cpp b/src/VBox/Main/testcase/tstCollector.cpp index 1798d30e..63aaff4f 100644 --- a/src/VBox/Main/testcase/tstCollector.cpp +++ b/src/VBox/Main/testcase/tstCollector.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -63,7 +63,7 @@ if (RT_FAILURE(rc)) \ break; \ ++nCalls; \ - } while(RTTimeMilliTS() - start < RUN_TIME_MS); \ + } while (RTTimeMilliTS() - start < RUN_TIME_MS); \ if (RT_FAILURE(rc)) \ { \ RTPrintf("tstCollector: "#fn" -> %Rrc\n", rc); \ @@ -152,8 +152,9 @@ int testNetwork(pm::CollectorHAL *collector) uint64_t hostRxStart, hostTxStart; uint64_t hostRxStop, hostTxStop, speed = 125000000; /* Assume 1Gbit/s */ - RTPrintf("tstCollector: TESTING - Network load, sleeping for 5 sec...\n"); + RTPrintf("tstCollector: TESTING - Network load, sleeping for 5 s...\n"); + hostRxStart = hostTxStart = 0; int rc = collector->preCollect(hints, 0); if (RT_FAILURE(rc)) { @@ -161,36 +162,43 @@ int testNetwork(pm::CollectorHAL *collector) return 1; } rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStart, &hostTxStart); - if (RT_FAILURE(rc)) + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getRawHostNetworkLoad() not implemented, skipping\n"); + else { - RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); - return 1; - } + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); + return 1; + } - RTThreadSleep(5000); // Sleep for five seconds + RTThreadSleep(5000); // Sleep for five seconds - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStop, &hostTxStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); - return 1; + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + hostRxStop = hostRxStart; + hostTxStop = hostTxStart; + rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStop, &hostTxStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host network speed = %llu bytes/sec (%llu mbit/sec)\n", + speed, speed/(1000000/8)); + RTPrintf("tstCollector: host network rx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n", + (hostRxStop - hostRxStart)/5, (hostRxStop - hostRxStart)/(5000000/8), + (hostRxStop - hostRxStart) * 100 / (speed * 5), + (hostRxStop - hostRxStart) * 10000 / (speed * 5) % 100); + RTPrintf("tstCollector: host network tx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n\n", + (hostTxStop - hostTxStart)/5, (hostTxStop - hostTxStart)/(5000000/8), + (hostTxStop - hostTxStart) * 100 / (speed * 5), + (hostTxStop - hostTxStart) * 10000 / (speed * 5) % 100); } - RTPrintf("tstCollector: host network speed = %llu bytes/sec (%llu mbit/sec)\n", - speed, speed/(1000000/8)); - RTPrintf("tstCollector: host network rx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n", - (hostRxStop - hostRxStart)/5, (hostRxStop - hostRxStart)/(5000000/8), - (hostRxStop - hostRxStart) * 100 / (speed * 5), - (hostRxStop - hostRxStart) * 10000 / (speed * 5) % 100); - RTPrintf("tstCollector: host network tx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n\n", - (hostTxStop - hostTxStart)/5, (hostTxStop - hostTxStart)/(5000000/8), - (hostTxStop - hostTxStart) * 100 / (speed * 5), - (hostTxStop - hostTxStart) * 10000 / (speed * 5) % 100); return 0; } @@ -203,14 +211,19 @@ int testFsUsage(pm::CollectorHAL *collector) ULONG total, used, available; int rc = collector->getHostFilesystemUsage(FSNAME, &total, &used, &available); - if (RT_FAILURE(rc)) + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getHostFilesystemUsage() not implemented, skipping\n"); + else { - RTPrintf("tstCollector: getHostFilesystemUsage() -> %Rrc\n", rc); - return 1; + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostFilesystemUsage() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host root fs total = %lu mB\n", total); + RTPrintf("tstCollector: host root fs used = %lu mB\n", used); + RTPrintf("tstCollector: host root fs available = %lu mB\n\n", available); } - RTPrintf("tstCollector: host root fs total = %lu mB\n", total); - RTPrintf("tstCollector: host root fs used = %lu mB\n", used); - RTPrintf("tstCollector: host root fs available = %lu mB\n\n", available); return 0; } @@ -220,54 +233,82 @@ int testDisk(pm::CollectorHAL *collector) uint64_t diskMsStart, totalMsStart; uint64_t diskMsStop, totalMsStop; - std::list disks; - int rc = pm::getDiskListByFs(FSNAME, disks); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getDiskListByFs(%s) -> %Rrc\n", FSNAME, rc); - return 1; - } - if (disks.empty()) + pm::DiskList disksUsage, disksLoad; + int rc = collector->getDiskListByFs(FSNAME, disksUsage, disksLoad); + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getDiskListByFs() not implemented, skipping\n"); + else { - RTPrintf("tstCollector: getDiskListByFs(%s) returned empty list\n", FSNAME); - return 1; - } - - RTPrintf("tstCollector: TESTING - Disk utilization, sleeping for 5 sec...\n"); - - hints.collectHostCpuLoad(); - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostDiskLoad(disks.front().c_str(), &diskMsStart, &totalMsStart); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); - return 1; - } + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getDiskListByFs(%s) -> %Rrc\n", FSNAME, rc); + return 1; + } + if (disksUsage.empty()) + { + RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME); + return 1; + } + if (disksLoad.empty()) + { + RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME); + return 1; + } - RTThreadSleep(5000); // Sleep for five seconds + pm::DiskList::iterator it; + for (it = disksUsage.begin(); it != disksUsage.end(); ++it) + { + uint64_t diskSize = 0; + rc = collector->getHostDiskSize(it->c_str(), &diskSize); + RTPrintf("tstCollector: TESTING - Disk size (%s) = %llu\n", it->c_str(), diskSize); + if (rc == VERR_FILE_NOT_FOUND) + RTPrintf("tstCollector: getHostDiskSize(%s) returned VERR_FILE_NOT_FOUND\n", it->c_str()); + else if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostDiskSize() -> %Rrc\n", rc); + return 1; + } + } - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostDiskLoad(disks.front().c_str(), &diskMsStop, &totalMsStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); - return 1; + for (it = disksLoad.begin(); it != disksLoad.end(); ++it) + { + RTPrintf("tstCollector: TESTING - Disk utilization (%s), sleeping for 5 s...\n", it->c_str()); + + hints.collectHostCpuLoad(); + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStart, &totalMsStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc); + return 1; + } + + RTThreadSleep(5000); // Sleep for five seconds + + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStop, &totalMsStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host disk util = %llu msec (%u.%u %%), total = %llu msec\n\n", + (diskMsStop - diskMsStart), + (unsigned)((diskMsStop - diskMsStart) * 100 / (totalMsStop - totalMsStart)), + (unsigned)((diskMsStop - diskMsStart) * 10000 / (totalMsStop - totalMsStart) % 100), + totalMsStop - totalMsStart); + } } - RTPrintf("tstCollector: host disk util = %llu msec (%u.%u %%), total = %llu msec\n\n", - (diskMsStop - diskMsStart), - (unsigned)((diskMsStop - diskMsStart) * 100 / (totalMsStop - totalMsStart)), - (unsigned)((diskMsStop - diskMsStart) * 10000 / (totalMsStop - totalMsStart) % 100), - totalMsStop - totalMsStart); return 0; } @@ -276,6 +317,8 @@ int testDisk(pm::CollectorHAL *collector) int main(int argc, char *argv[]) { + bool cpuTest, ramTest, netTest, diskTest, fsTest, perfTest; + cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = false; /* * Initialize the VBox runtime without loading * the support driver. @@ -286,12 +329,38 @@ int main(int argc, char *argv[]) RTPrintf("tstCollector: RTR3InitExe() -> %d\n", rc); return 1; } - if (argc > 1 && !strcmp(argv[1], "-child")) + if (argc > 1) { - /* We have spawned ourselves as a child process -- scratch the leg */ - RTThreadSleep(1000000); - return 1; + if (!strcmp(argv[1], "-child")) + { + /* We have spawned ourselves as a child process -- scratch the leg */ + RTThreadSleep(1000000); + return 1; + } + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-cpu")) + cpuTest = true; + else if (!strcmp(argv[i], "-ram")) + ramTest = true; + else if (!strcmp(argv[i], "-net")) + netTest = true; + else if (!strcmp(argv[i], "-disk")) + diskTest = true; + else if (!strcmp(argv[i], "-fs")) + fsTest = true; + else if (!strcmp(argv[i], "-perf")) + perfTest = true; + else + { + RTPrintf("tstCollector: Unknown option: %s\n", argv[i]); + return 2; + } + } } + else + cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = true; + #ifdef RT_OS_WINDOWS HRESULT hRes = CoInitialize(NULL); /* @@ -313,12 +382,18 @@ int main(int argc, char *argv[]) RTPrintf("tstCollector: createMetricFactory() failed\n", rc); return 1; } -#if 1 + pm::CollectorHints hints; - hints.collectHostCpuLoad(); - hints.collectHostRamUsage(); - hints.collectProcessCpuLoad(RTProcSelf()); - hints.collectProcessRamUsage(RTProcSelf()); + if (cpuTest) + { + hints.collectHostCpuLoad(); + hints.collectProcessCpuLoad(RTProcSelf()); + } + if (ramTest) + { + hints.collectHostRamUsage(); + hints.collectProcessRamUsage(RTProcSelf()); + } uint64_t start; @@ -328,164 +403,164 @@ int main(int argc, char *argv[]) uint64_t processUserStart, processKernelStart, processTotalStart; uint64_t processUserStop, processKernelStop, processTotalStop; - RTPrintf("tstCollector: TESTING - CPU load, sleeping for 5 sec\n"); - rc = collector->preCollect(hints, 0); if (RT_FAILURE(rc)) { RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); return 1; } - rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); - if (RT_FAILURE(rc)) + if (cpuTest) { - RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); - return 1; - } + RTPrintf("tstCollector: TESTING - CPU load, sleeping for 5 s...\n"); + + rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } - RTThreadSleep(5000); // Sleep for 5 seconds + RTThreadSleep(5000); // Sleep for 5 seconds - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); - return 1; - } - hostTotal = hostUserStop - hostUserStart - + hostKernelStop - hostKernelStart - + hostIdleStop - hostIdleStart; - /*printf("tstCollector: host cpu user = %f sec\n", (hostUserStop - hostUserStart) / 10000000.); - printf("tstCollector: host cpu kernel = %f sec\n", (hostKernelStop - hostKernelStart) / 10000000.); - printf("tstCollector: host cpu idle = %f sec\n", (hostIdleStop - hostIdleStart) / 10000000.); - printf("tstCollector: host cpu total = %f sec\n", hostTotal / 10000000.);*/ - RTPrintf("tstCollector: host cpu user = %u.%u %%\n", - (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), - (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", - (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), - (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", - (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), - (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: process cpu user = %u.%u %%\n", - (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), - (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); - RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", - (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), - (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); - - RTPrintf("tstCollector: TESTING - CPU load, looping for 5 sec\n"); - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); - return 1; - } - start = RTTimeMilliTS(); - while(RTTimeMilliTS() - start < 5000) - ; // Loop for 5 seconds - rc = collector->preCollect(hints, 0); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); - return 1; - } - rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); - return 1; - } - hostTotal = hostUserStop - hostUserStart - + hostKernelStop - hostKernelStart - + hostIdleStop - hostIdleStart; - RTPrintf("tstCollector: host cpu user = %u.%u %%\n", - (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), - (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", - (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), - (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", - (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), - (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); - RTPrintf("tstCollector: process cpu user = %u.%u %%\n", - (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), - (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); - RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", - (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), - (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); - - RTPrintf("tstCollector: TESTING - Memory usage\n"); - - ULONG total, used, available, processUsed; - - rc = collector->getHostMemoryUsage(&total, &used, &available); - if (RT_FAILURE(rc)) - { - RTPrintf("tstCollector: getHostMemoryUsage() -> %Rrc\n", rc); - return 1; + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + hostTotal = hostUserStop - hostUserStart + + hostKernelStop - hostKernelStart + + hostIdleStop - hostIdleStart; + RTPrintf("tstCollector: host cpu user = %u.%u %%\n", + (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), + (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", + (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), + (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", + (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), + (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: process cpu user = %u.%u %%\n", + (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", + (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + + RTPrintf("tstCollector: TESTING - CPU load, looping for 5 s...\n"); + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + start = RTTimeMilliTS(); + while (RTTimeMilliTS() - start < 5000) + ; // Loop for 5 seconds + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + hostTotal = hostUserStop - hostUserStart + + hostKernelStop - hostKernelStart + + hostIdleStop - hostIdleStart; + RTPrintf("tstCollector: host cpu user = %u.%u %%\n", + (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), + (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", + (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), + (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", + (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), + (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: process cpu user = %u.%u %%\n", + (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", + (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); } - rc = collector->getProcessMemoryUsage(RTProcSelf(), &processUsed); - if (RT_FAILURE(rc)) + + if (ramTest) { - RTPrintf("tstCollector: getProcessMemoryUsage() -> %Rrc\n", rc); - return 1; + RTPrintf("tstCollector: TESTING - Memory usage\n"); + + ULONG total, used, available, processUsed; + + rc = collector->getHostMemoryUsage(&total, &used, &available); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostMemoryUsage() -> %Rrc\n", rc); + return 1; + } + rc = collector->getProcessMemoryUsage(RTProcSelf(), &processUsed); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getProcessMemoryUsage() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host mem total = %lu kB\n", total); + RTPrintf("tstCollector: host mem used = %lu kB\n", used); + RTPrintf("tstCollector: host mem available = %lu kB\n", available); + RTPrintf("tstCollector: process mem used = %lu kB\n\n", processUsed); } - RTPrintf("tstCollector: host mem total = %lu kB\n", total); - RTPrintf("tstCollector: host mem used = %lu kB\n", used); - RTPrintf("tstCollector: host mem available = %lu kB\n", available); - RTPrintf("tstCollector: process mem used = %lu kB\n\n", processUsed); -#endif -#if 1 - rc = testNetwork(collector); -#endif -#if 1 + + if (netTest) + rc = testNetwork(collector); + if (fsTest) rc = testFsUsage(collector); -#endif -#if 1 - rc = testDisk(collector); -#endif -#if 1 - RTPrintf("tstCollector: TESTING - Performance\n\n"); + if (diskTest) + rc = testDisk(collector); + if (perfTest) + { + RTPrintf("tstCollector: TESTING - Performance\n\n"); - measurePerformance(collector, argv[0], 100); -#endif + measurePerformance(collector, argv[0], 100); + } delete collector; diff --git a/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp b/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp index d7d74874..c9780a1d 100644 --- a/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp +++ b/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp @@ -34,7 +34,7 @@ using namespace com; int main() { RTTEST hTest; - int rc = RTTestInitAndCreate("tstMakeup", &hTest); + int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest); if (rc) return rc; RTTestBanner(hTest); @@ -51,11 +51,32 @@ int main() * -- we rely on the return values in the test(s) below. */ RTAssertSetQuiet(true); +#if 0 + for (int t = 0; t < 4 && !RTTestErrorCount(hTest); t++) + { + uint32_t uSession = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); + uint32_t uFilter = VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession); + RTTestIPrintf(RTTESTLVL_INFO, "Session: %RU32, Filter: %x\n", uSession, uFilter); + + uint32_t uSession2 = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); + uint32_t uCID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSession2, + RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_OBJECTS - 1), + RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_CONTEXTS - 1)); + RTTestIPrintf(RTTESTLVL_INFO, "CID: %x (Session: %d), Masked: %x\n", + uCID, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uCID), uCID & uFilter); + if ((uCID & uFilter) == uCID) + { + RTTestIPrintf(RTTESTLVL_INFO, "=========== Masking works: %x vs. %x\n", + uCID & uFilter, uFilter); + } + } +#endif + uint32_t uContextMax = UINT32_MAX; RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax); - /* Do 64 tests total. */ - for (int t = 0; t < 64 && !RTTestErrorCount(hTest); t++) + /* Do 4048 tests total. */ + for (int t = 0; t < 4048 && !RTTestErrorCount(hTest); t++) { /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */ uint32_t s = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); diff --git a/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp index 64dda854..93019a8c 100644 --- a/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp +++ b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/testcase/tstMediumLock.cpp b/src/VBox/Main/testcase/tstMediumLock.cpp new file mode 100644 index 00000000..2aebc845 --- /dev/null +++ b/src/VBox/Main/testcase/tstMediumLock.cpp @@ -0,0 +1,299 @@ +/* $Id: tstMediumLock.cpp $ */ + +/** @file + * + * Medium lock test cases. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#define LOG_ENABLED +#define LOG_GROUP LOG_GROUP_MAIN +#define LOG_INSTANCE NULL +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace com; + + +#define TEST_RT_SUCCESS(x,y,z) \ + do \ + { \ + int rc = (y); \ + if (RT_FAILURE(rc)) \ + RTTestFailed((x), "%s %Rrc", (z), rc); \ + } while (0) + +#define TEST_COM_SUCCESS(x,y,z) \ + do \ + { \ + HRESULT hrc = (y); \ + if (FAILED(hrc)) \ + RTTestFailed((x), "%s %Rhrc", (z), hrc); \ + } while (0) + +#define TEST_COM_FAILURE(x,y,z) \ + do \ + { \ + HRESULT hrc = (y); \ + if (SUCCEEDED(hrc)) \ + RTTestFailed((x), "%s", (z)); \ + } while (0) + +int main(int argc, char *argv[]) +{ + /* Init the runtime without loading the support driver. */ + RTR3InitExe(argc, &argv, 0); + + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstMediumLock", &hTest); + if (rcExit) + return rcExit; + RTTestBanner(hTest); + + bool fComInit = false; + ComPtr pVirtualBox; + char szPathTemp[RTPATH_MAX] = ""; + ComPtr pMedium; + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Constructing temp image name"); + TEST_RT_SUCCESS(hTest, RTPathTemp(szPathTemp, sizeof(szPathTemp)), "temp directory"); + RTUUID uuid; + RTUuidCreate(&uuid); + char szFile[50]; + RTStrPrintf(szFile, sizeof(szFile), "%RTuuid.vdi", &uuid); + TEST_RT_SUCCESS(hTest, RTPathAppend(szPathTemp, sizeof(szPathTemp), szFile), "concatenate image name"); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Initializing COM"); + TEST_COM_SUCCESS(hTest, Initialize(), "init"); + } + + if (!RTTestSubErrorCount(hTest)) + { + fComInit = true; + + RTTestSub(hTest, "Getting VirtualBox reference"); + TEST_COM_SUCCESS(hTest, pVirtualBox.createLocalObject(CLSID_VirtualBox), "vbox reference"); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Creating temp hard disk medium"); + TEST_COM_SUCCESS(hTest, pVirtualBox->CreateHardDisk(Bstr("VDI").raw(), Bstr(szPathTemp).raw(), pMedium.asOutParam()), "create medium"); + if (!pMedium.isNull()) + { + ComPtr pProgress; + SafeArray variant; + variant.push_back(MediumVariant_Standard); + TEST_COM_SUCCESS(hTest, pMedium->CreateBaseStorage(_1M, ComSafeArrayAsInParam(variant), pProgress.asOutParam()), "create base storage"); + if (!pProgress.isNull()) + TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of create"); + } + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Write locks"); + ComPtr pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockWrite(pToken1.asOutParam()), "write lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong lock write medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockWrite(pToken2.asOutParam()), "nested write lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "write unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Read locks"); + ComPtr pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken1.asOutParam()), "read lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong lock read medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken2.asOutParam()), "nested read lock failed"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken2.isNull()) + TEST_COM_SUCCESS(hTest, pToken2->Abandon(), "read nested unlock"); + else + RTTestFailed(hTest, "pToken2 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "read nested unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Mixing write and read locks"); + ComPtr pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockWrite(pToken1.asOutParam()), "write lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong lock write medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockRead(pToken2.asOutParam()), "write+read lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "write unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Mixing read and write locks"); + ComPtr pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken1.asOutParam()), "read lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong lock read medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockWrite(pToken2.asOutParam()), "read+write lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "read unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState); + } + + /* Cleanup, also part of the testcase */ + + if (!pMedium.isNull()) + { + RTTestSub(hTest, "Closing medium"); + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState == MediumState_Created) + { + ComPtr pProgress; + TEST_COM_SUCCESS(hTest, pMedium->DeleteStorage(pProgress.asOutParam()), "deleting storage"); + if (!pProgress.isNull()) + TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of delete"); + } + TEST_COM_SUCCESS(hTest, pMedium->Close(), "closing"); + pMedium.setNull(); + } + + pVirtualBox.setNull(); + + /* Make sure that there are no object references alive here, XPCOM does + * a very bad job at cleaning up such leftovers, spitting out warning + * messages in a debug build. */ + + if (fComInit) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n"); + Shutdown(); + } + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} diff --git a/src/VBox/Main/testcase/tstMouseImpl.cpp b/src/VBox/Main/testcase/tstMouseImpl.cpp new file mode 100644 index 00000000..361daf14 --- /dev/null +++ b/src/VBox/Main/testcase/tstMouseImpl.cpp @@ -0,0 +1,459 @@ +/* $Id: tstMouseImpl.cpp $ */ +/** @file + * Main unit test - Mouse class. + */ + +/* + * Copyright (C) 2011-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/****************************************************************************** +* Header Files * +******************************************************************************/ +#define IN_VMM_R3 /* Kill most Windows warnings on CFGMR3* implementations. */ +#include "MouseImpl.h" +#include "VMMDev.h" +#include "DisplayImpl.h" + +#include +#include +#include +#include +#include + +#ifndef RT_OS_WINDOWS +NS_DECL_CLASSINFO(Mouse) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Mouse, IMouse) +#endif + +PDMIVMMDEVPORT VMMDevPort; + +class TestVMMDev : public VMMDevMouseInterface +{ + PPDMIVMMDEVPORT getVMMDevPort(void) { return &VMMDevPort; } +}; + +class TestDisplay : public DisplayMouseInterface +{ + void getFramebufferDimensions(int32_t *px1, int32_t *py1, + int32_t *px2, int32_t *py2); + int getScreenResolution(uint32_t cScreen, ULONG *pcx, ULONG *pcy, + ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin); +}; + +class TestConsole : public ConsoleMouseInterface +{ +public: + VMMDevMouseInterface *getVMMDevMouseInterface() { return &mVMMDev; } + DisplayMouseInterface *getDisplayMouseInterface() { return &mDisplay; } + /** @todo why on earth is this not implemented? */ + void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, + BOOL supportsMT, BOOL needsHostCursor) {} + +private: + TestVMMDev mVMMDev; + TestDisplay mDisplay; +}; + +static int pdmdrvhlpAttach(PPDMDRVINS pDrvIns, uint32_t fFlags, + PPDMIBASE *ppBaseInterface) +{ + return VERR_PDM_NO_ATTACHED_DRIVER; +} + +static struct PDMDRVHLPR3 pdmHlpR3 = +{ + PDM_DRVHLPR3_VERSION, + pdmdrvhlpAttach, + NULL, /* pfnDetach */ + NULL, /* pfnDetachSelf */ + NULL, /* pfnMountPrepare */ + NULL, /* pfnAssertEMT */ + NULL, /* pfnAssertOther */ + NULL, /* pfnVMSetError */ + NULL, /* pfnVMSetErrorV */ + NULL, /* pfnVMSetRuntimeError */ + NULL, /* pfnVMSetRuntimeErrorV */ + NULL, /* pfnVMState */ + NULL, /* pfnVMTeleportedAndNotFullyResumedYet */ + NULL, /* pfnGetSupDrvSession */ + NULL, /* pfnQueueCreate */ + NULL, /* pfnTMGetVirtualFreq */ + NULL, /* pfnTMGetVirtualTime */ + NULL, /* pfnTMTimerCreate */ + NULL, /* pfnSSMRegister */ + NULL, /* pfnSSMDeregister */ + NULL, /* pfnDBGFInfoRegister */ + NULL, /* pfnDBGFInfoDeregister */ + NULL, /* pfnSTAMRegister */ + NULL, /* pfnSTAMRegisterF */ + NULL, /* pfnSTAMRegisterV */ + NULL, /* pfnSTAMDeregister */ + NULL, /* pfnSUPCallVMMR0Ex */ + NULL, /* pfnUSBRegisterHub */ + NULL, /* pfnSetAsyncNotification */ + NULL, /* pfnAsyncNotificationCompleted */ + NULL, /* pfnThreadCreate */ + NULL, /* pfnAsyncCompletionTemplateCreate */ +#ifdef VBOX_WITH_NETSHAPER + NULL, /* pfnNetShaperAttach */ + NULL, /* pfnNetShaperDetach */ +#endif + NULL, /* pfnLdrGetRCInterfaceSymbols */ + NULL, /* pfnLdrGetR0InterfaceSymbols */ + NULL, /* pfnCritSectInit */ + NULL, /* pfnCallR0 */ + NULL, /* pfnFTSetCheckpoint */ + NULL, /* pfnBlkCacheRetain */ + NULL, /* pfnVMGetSuspendReason */ + NULL, /* pfnVMGetResumeReason */ + NULL, /* pfnReserved0 */ + NULL, /* pfnReserved1 */ + NULL, /* pfnReserved2 */ + NULL, /* pfnReserved3 */ + NULL, /* pfnReserved4 */ + NULL, /* pfnReserved5 */ + NULL, /* pfnReserved6 */ + NULL, /* pfnReserved7 */ + NULL, /* pfnReserved8 */ + NULL, /* pfnReserved9 */ + PDM_DRVHLPR3_VERSION /* u32TheEnd */ +}; + +static struct +{ + int32_t dx; + int32_t dy; + int32_t dz; + int32_t dw; +} mouseEvent; + +static int mousePutEvent(PPDMIMOUSEPORT pInterface, int32_t iDeltaX, + int32_t iDeltaY, int32_t iDeltaZ, int32_t iDeltaW, + uint32_t fButtonStates) +{ + mouseEvent.dx = iDeltaX; + mouseEvent.dy = iDeltaY; + mouseEvent.dz = iDeltaZ; + mouseEvent.dw = iDeltaW; + return VINF_SUCCESS; +} + +static struct +{ + uint32_t cx; + uint32_t cy; + int32_t dz; + int32_t dw; + uint32_t fButtonStates; +} mouseEventAbs; + +static int mousePutEventAbs(PPDMIMOUSEPORT pInterface, uint32_t uX, + uint32_t uY, int32_t iDeltaZ, int32_t iDeltaW, + uint32_t fButtonStates) +{ + mouseEventAbs.cx = uX; + mouseEventAbs.cy = uY; + mouseEventAbs.dz = iDeltaZ; + mouseEventAbs.dw = iDeltaW; + mouseEventAbs.fButtonStates = fButtonStates; + return VINF_SUCCESS; +} + +static struct PDMIMOUSEPORT pdmiMousePort = +{ + mousePutEvent, + mousePutEventAbs, + NULL /* pfnPutEventMT */ +}; + +static void *pdmiBaseQuery(struct PDMIBASE *pInterface, const char *pszIID) +{ + return &pdmiMousePort; +} + +static struct PDMIBASE pdmiBase = +{ + pdmiBaseQuery +}; + +static struct PDMDRVINS pdmdrvInsCore = +{ + PDM_DRVINS_VERSION, + 0, /* iInstance */ + NIL_RTRCPTR, /* pHlpRC */ + NIL_RTRCPTR, /* pvInstanceDataRC */ + NIL_RTR0PTR, /* pHelpR0 */ + NIL_RTR0PTR, /* pvInstanceDataR0 */ + &pdmHlpR3, + NULL, /* pvInstanceDataR3 */ + NIL_RTR3PTR, /* pReg */ + NIL_RTR3PTR, /* pCfg */ + &pdmiBase, + NULL, /* pDownBase */ + { /* IBase */ + NULL /* pfnQueryInterface */ + }, + 0, /* fTracing */ + 0, /* idTracing */ +#if HC_ARCH_BITS == 32 + { 0 }, /* au32Padding */ +#endif + { + { 0 } /* padding */ + }, /* Internal */ + { 0 } /* achInstanceData */ +}; + +static struct PDMDRVINS *ppdmdrvIns = NULL; + +ComObjPtr pMouse; +ConsoleMouseInterface *pConsole = NULL; + +static struct +{ + int32_t x; + int32_t y; +} absoluteMouse; + +static int setAbsoluteMouse(PPDMIVMMDEVPORT, int32_t x, int32_t y) +{ + absoluteMouse.x = x; + absoluteMouse.y = y; + return VINF_SUCCESS; +} + +static int updateMouseCapabilities(PPDMIVMMDEVPORT, uint32_t, uint32_t) +{ + return VINF_SUCCESS; +} + +void TestDisplay::getFramebufferDimensions(int32_t *px1, int32_t *py1, + int32_t *px2, int32_t *py2) +{ + if (px1) + *px1 = -320; + if (py1) + *py1 = -240; + if (px2) + *px2 = 320; + if (py2) + *py2 = 240; +} + +int TestDisplay::getScreenResolution(uint32_t cScreen, ULONG *pcx, + ULONG *pcy, ULONG *pcBPP, LONG *pXOrigin, LONG *pYOrigin) +{ + NOREF(cScreen); + if (pcx) + *pcx = 640; + if (pcy) + *pcy = 480; + if (pcBPP) + *pcBPP = 32; + if (pXOrigin) + *pXOrigin = 0; + if (pYOrigin) + *pYOrigin = 0; + return S_OK; +} + +/****************************************************************************** +* Main test code * +******************************************************************************/ + +static int setup(void) +{ + PCFGMNODE pCfg = NULL; + Mouse *pMouse2; + int rc = VERR_NO_MEMORY; + VMMDevPort.pfnSetAbsoluteMouse = setAbsoluteMouse; + VMMDevPort.pfnUpdateMouseCapabilities = updateMouseCapabilities; + HRESULT hrc = pMouse.createObject(); + AssertComRC(hrc); + if (FAILED(hrc)) + return VERR_GENERAL_FAILURE; + pConsole = new TestConsole; + pMouse->init(pConsole); + ppdmdrvIns = (struct PDMDRVINS *) RTMemAllocZ( sizeof(struct PDMDRVINS) + + Mouse::DrvReg.cbInstance); + *ppdmdrvIns = pdmdrvInsCore; + pMouse2 = pMouse; + pCfg = CFGMR3CreateTree(NULL); + if (pCfg) + { + rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pMouse2); + if (RT_SUCCESS(rc)) + Mouse::DrvReg.pfnConstruct(ppdmdrvIns, pCfg, 0); + } + return rc; +} + +static void teardown(void) +{ + pMouse.setNull(); + if (pConsole) + delete pConsole; + if (ppdmdrvIns) + RTMemFree(ppdmdrvIns); +} + +static bool approxEq(int a, int b, int prec) +{ + return a - b < prec && b - a < prec; +} + +/** @test testAbsToVMMDevNewProtocol */ +static void testAbsToVMMDevNewProtocol(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to VMMDev, new protocol"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, true, false, false); + pMouse->onVMMDevGuestCapsChange( VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE + | VMMDEV_MOUSE_NEW_PROTOCOL); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(320, 240, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0xffff, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0xffff, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + RTTestSubDone(hTest); +} + +/** @test testAbsToVMMDevOldProtocol */ +static void testAbsToVMMDevOldProtocol(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to VMMDev, old protocol"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, true, false, false); + pMouse->onVMMDevGuestCapsChange(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE); + pMouse->PutMouseEventAbsolute(320, 240, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, 0, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, 0, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.x, -0x8000, 200), + ("absoluteMouse.x=%d\n", absoluteMouse.x)); + RTTESTI_CHECK_MSG(approxEq(absoluteMouse.y, -0x8000, 200), + ("absoluteMouse.y=%d\n", absoluteMouse.y)); + RTTestSubDone(hTest); +} + +/** @test testAbsToAbsDev */ +static void testAbsToAbsDev(RTTEST hTest) +{ + PPDMIBASE pBase; + PPDMIMOUSECONNECTOR pConnector; + + RTTestSub(hTest, "Absolute event to absolute device"); + pBase = &ppdmdrvIns->IBase; + pConnector = (PPDMIMOUSECONNECTOR)pBase->pfnQueryInterface(pBase, + PDMIMOUSECONNECTOR_IID); + pConnector->pfnReportModes(pConnector, false, true, false); + pMouse->onVMMDevGuestCapsChange(VMMDEV_MOUSE_NEW_PROTOCOL); + pMouse->PutMouseEventAbsolute(0, 0, 0, 0, 0); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0x8000, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0x8000, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + pMouse->PutMouseEventAbsolute(-319, -239, 0, 0, 3); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTESTI_CHECK_MSG(mouseEventAbs.fButtonStates == 3, + ("mouseEventAbs.fButtonStates=%u\n", + (unsigned) mouseEventAbs.fButtonStates)); + pMouse->PutMouseEventAbsolute(320, 240, -3, 2, 1); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cx, 0xffff, 200), + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(approxEq(mouseEventAbs.cy, 0xffff, 200), + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTESTI_CHECK_MSG(mouseEventAbs.fButtonStates == 1, + ("mouseEventAbs.fButtonStates=%u\n", + (unsigned) mouseEventAbs.fButtonStates)); + RTTESTI_CHECK_MSG(mouseEventAbs.dz == -3, + ("mouseEventAbs.dz=%d\n", (int) mouseEvent.dz)); + RTTESTI_CHECK_MSG(mouseEventAbs.dw == 2, + ("mouseEventAbs.dw=%d\n", (int) mouseEvent.dw)); + mouseEventAbs.cx = mouseEventAbs.cy = 0xffff; + pMouse->PutMouseEventAbsolute(-640, -480, 0, 0, 0); + RTTESTI_CHECK_MSG(mouseEventAbs.cx == 0xffff, + ("mouseEventAbs.cx=%d\n", mouseEventAbs.cx)); + RTTESTI_CHECK_MSG(mouseEventAbs.cy == 0xffff, + ("mouseEventAbs.cy=%d\n", mouseEventAbs.cy)); + RTTestSubDone(hTest); +} + +/** @todo generate this using the @test blocks above */ +typedef void (*PFNTEST)(RTTEST); +static PFNTEST g_tests[] = +{ + testAbsToVMMDevNewProtocol, + testAbsToVMMDevOldProtocol, + testAbsToAbsDev, + NULL +}; + +int main(void) +{ + /* + * Init the runtime, test and say hello. + */ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstMouseImpl", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + /* + * Run the tests. + */ + for (unsigned i = 0; g_tests[i]; ++i) + { + int rc = setup(); + AssertRC(rc); + if (RT_SUCCESS(rc)) + g_tests[i](hTest); + teardown(); + } + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/Main/testcase/tstOVF.cpp b/src/VBox/Main/testcase/tstOVF.cpp index 9265b1e8..de8c808d 100644 --- a/src/VBox/Main/testcase/tstOVF.cpp +++ b/src/VBox/Main/testcase/tstOVF.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -116,12 +115,12 @@ void importOVF(const char *pcszPrefix, com::SafeArray aTypes; com::SafeArray aRefs; com::SafeArray aOvfValues; - com::SafeArray aVboxValues; + com::SafeArray aVBoxValues; com::SafeArray aExtraConfigValues; rc = pVSys->GetDescription(ComSafeArrayAsOutParam(aTypes), ComSafeArrayAsOutParam(aRefs), ComSafeArrayAsOutParam(aOvfValues), - ComSafeArrayAsOutParam(aVboxValues), + ComSafeArrayAsOutParam(aVBoxValues), ComSafeArrayAsOutParam(aExtraConfigValues)); if (FAILED(rc)) throw MyError(rc, "VirtualSystemDescription::GetDescription() failed\n"); @@ -226,7 +225,7 @@ void importOVF(const char *pcszPrefix, RTPrintf(" vsys %2u item %2u: type %2d (%s), ovf: \"%ls\", vbox: \"%ls\", extra: \"%ls\"\n", u, u2, t, pcszType, aOvfValues[u2], - aVboxValues[u2], + aVBoxValues[u2], aExtraConfigValues[u2]); } } @@ -305,10 +304,6 @@ int main(int argc, char *argv[]) rc = pSession.createInprocObject(CLSID_Session); if (FAILED(rc)) throw MyError(rc, "failed to create a session object!\n"); - // create the event queue - // (here it is necessary only to process remaining XPCOM/IPC events after the session is closed) - EventQueue eventQ; - // for each testcase, we will copy the dummy VMDK image to the subdirectory with the OVF testcase // so that the import will find the disks it expects; this is just for testing the import since // the imported machines will obviously not be usable. @@ -355,7 +350,7 @@ int main(int argc, char *argv[]) if (FAILED(rc)) throw MyError(rc, "Machine::Unregister() failed\n"); ComPtr pProgress; - rc = pMachine->Delete(ComSafeArrayAsInParam(sfaMedia), pProgress.asOutParam()); + rc = pMachine->DeleteConfig(ComSafeArrayAsInParam(sfaMedia), pProgress.asOutParam()); if (FAILED(rc)) throw MyError(rc, "Machine::DeleteSettings() failed\n"); rc = pProgress->WaitForCompletion(-1); if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n"); diff --git a/src/VBox/Main/testcase/tstUSBLinux.h b/src/VBox/Main/testcase/tstUSBLinux.h index 5a9491a4..e5e0eb56 100644 --- a/src/VBox/Main/testcase/tstUSBLinux.h +++ b/src/VBox/Main/testcase/tstUSBLinux.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/testcase/tstVBoxAPILinux.cpp b/src/VBox/Main/testcase/tstVBoxAPILinux.cpp deleted file mode 100644 index 4c4830ad..00000000 --- a/src/VBox/Main/testcase/tstVBoxAPILinux.cpp +++ /dev/null @@ -1,629 +0,0 @@ -/** @file - * - * tstVBoxAPILinux - sample program to illustrate the VirtualBox - * XPCOM API for machine management on Linux. - * It only uses standard C/C++ and XPCOM semantics, - * no additional VBox classes/macros/helpers. - */ - -/* - * Copyright (C) 2006-2012 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -/* - * PURPOSE OF THIS SAMPLE PROGRAM - * ------------------------------ - * - * This sample program is intended to demonstrate the minimal code necessary - * to use VirtualBox XPCOM API for learning puroses only. The program uses - * pure XPCOM and doesn't have any extra dependencies to let you better - * understand what is going on when a client talks to the VirtualBox core - * using the XPCOM framework. - * - * However, if you want to write a real application, it is highly recommended - * to use our MS COM XPCOM Glue library and helper C++ classes. This way, you - * will get at least the following benefits: - * - * a) better portability: both the MS COM (used on Windows) and XPCOM (used - * everywhere else) VirtualBox client application from the same source code - * (including common smart C++ templates for automatic interface pointer - * reference counter and string data management); - * b) simpler XPCOM initialization and shutdown (only a single method call - * that does everything right). - * - * Currently, there is no separate sample program that uses the VirtualBox MS - * COM XPCOM Glue library. Please refer to the sources of stock VirtualBox - * applications such as the VirtualBox GUI frontend or the VBoxManage command - * line frontend. - * - * - * RUNNING THIS SAMPLE PROGRAM - * --------------------------- - * - * This sample program needs to know where the VirtualBox core files reside - * and where to search for VirtualBox shared libraries. Therefore, you need to - * use the following (or similar) command to execute it: - * - * $ env VBOX_XPCOM_HOME=../../.. LD_LIBRARY_PATH=../../.. ./tstVBoxAPILinux - * - * The above command assumes that VBoxRT.so, VBoxXPCOM.so and others reside in - * the directory ../../.. - */ - - -#include -#include -#include - -/* - * Include the XPCOM headers - */ - -#if defined(XPCOM_GLUE) -#include -#endif - -#include -#include -#include -#include - -#include - -/* - * VirtualBox XPCOM interface. This header is generated - * from IDL which in turn is generated from a custom XML format. - */ -#include "VirtualBox_XPCOM.h" - -/* - * Prototypes - */ - -char *nsIDToString(nsID *guid); -void printErrorInfo(); - - -/** - * Display all registered VMs on the screen with some information about each - * - * @param virtualBox VirtualBox instance object. - */ -void listVMs(IVirtualBox *virtualBox) -{ - nsresult rc; - - printf("----------------------------------------------------\n"); - printf("VM List:\n\n"); - - /* - * Get the list of all registered VMs - */ - IMachine **machines = NULL; - PRUint32 machineCnt = 0; - - rc = virtualBox->GetMachines(&machineCnt, &machines); - if (NS_SUCCEEDED(rc)) - { - /* - * Iterate through the collection - */ - for (PRUint32 i = 0; i < machineCnt; ++ i) - { - IMachine *machine = machines[i]; - if (machine) - { - PRBool isAccessible = PR_FALSE; - machine->GetAccessible(&isAccessible); - - if (isAccessible) - { - nsXPIDLString machineName; - machine->GetName(getter_Copies(machineName)); - char *machineNameAscii = ToNewCString(machineName); - printf("\tName: %s\n", machineNameAscii); - free(machineNameAscii); - } - else - { - printf("\tName: \n"); - } - - nsXPIDLString iid; - machine->GetId(getter_Copies(iid)); - const char *uuidString = ToNewCString(iid); - printf("\tUUID: %s\n", uuidString); - free((void*)uuidString); - - if (isAccessible) - { - nsXPIDLString configFile; - machine->GetSettingsFilePath(getter_Copies(configFile)); - char *configFileAscii = ToNewCString(configFile); - printf("\tConfig file: %s\n", configFileAscii); - free(configFileAscii); - - PRUint32 memorySize; - machine->GetMemorySize(&memorySize); - printf("\tMemory size: %uMB\n", memorySize); - - nsXPIDLString typeId; - machine->GetOSTypeId(getter_Copies(typeId)); - IGuestOSType *osType = nsnull; - virtualBox->GetGuestOSType (typeId.get(), &osType); - nsXPIDLString osName; - osType->GetDescription(getter_Copies(osName)); - char *osNameAscii = ToNewCString(osName); - printf("\tGuest OS: %s\n\n", osNameAscii); - free(osNameAscii); - osType->Release(); - } - - /* don't forget to release the objects in the array... */ - machine->Release(); - } - } - } - printf("----------------------------------------------------\n\n"); -} - -/** - * Create a sample VM - * - * @param virtualBox VirtualBox instance object. - */ -void createVM(IVirtualBox *virtualBox) -{ - nsresult rc; - /* - * First create a unnamed new VM. It will be unconfigured and not be saved - * in the configuration until we explicitely choose to do so. - */ - nsCOMPtr machine; - rc = virtualBox->CreateMachine(NULL, /* settings file */ - NS_LITERAL_STRING("A brand new name").get(), - 0, nsnull, /* groups (safearray)*/ - nsnull, /* ostype */ - nsnull, /* create flags */ - getter_AddRefs(machine)); - if (NS_FAILED(rc)) - { - printf("Error: could not create machine! rc=%08X\n", rc); - return; - } - - /* - * Set some properties - */ - /* alternative to illustrate the use of string classes */ - rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get()); - rc = machine->SetMemorySize(128); - - /* - * Now a more advanced property -- the guest OS type. This is - * an object by itself which has to be found first. Note that we - * use the ID of the guest OS type here which is an internal - * representation (you can find that by configuring the OS type of - * a machine in the GUI and then looking at the - * setting in the XML file. It is also possible to get the OS type from - * its description (win2k would be "Windows 2000") by getting the - * guest OS type collection and enumerating it. - */ - nsCOMPtr osType; - rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("win2k").get(), - getter_AddRefs(osType)); - if (NS_FAILED(rc)) - { - printf("Error: could not find guest OS type! rc=%08X\n", rc); - } - else - { - machine->SetOSTypeId (NS_LITERAL_STRING("win2k").get()); - } - - /* - * Register the VM. Note that this call also saves the VM config - * to disk. It is also possible to save the VM settings but not - * register the VM. - * - * Also note that due to current VirtualBox limitations, the machine - * must be registered *before* we can attach hard disks to it. - */ - rc = virtualBox->RegisterMachine(machine); - if (NS_FAILED(rc)) - { - printf("Error: could not register machine! rc=%08X\n", rc); - printErrorInfo(); - return; - } - - /* - * In order to manipulate the registered machine, we must open a session - * for that machine. Do it now. - */ - nsCOMPtr session; - { - nsCOMPtr manager; - rc = NS_GetComponentManager (getter_AddRefs (manager)); - if (NS_FAILED(rc)) - { - printf("Error: could not get component manager! rc=%08X\n", rc); - return; - } - rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID, - nsnull, - NS_GET_IID(ISession), - getter_AddRefs(session)); - if (NS_FAILED(rc)) - { - printf("Error, could not instantiate session object! rc=0x%x\n", rc); - return; - } - - rc = machine->LockMachine(session, LockType_Write); - if (NS_FAILED(rc)) - { - printf("Error, could not lock the machine for the session! rc=0x%x\n", rc); - return; - } - - /* - * After the machine is registered, the initial machine object becomes - * immutable. In order to get a mutable machine object, we must query - * it from the opened session object. - */ - rc = session->GetMachine(getter_AddRefs(machine)); - if (NS_FAILED(rc)) - { - printf("Error, could not get machine session! rc=0x%x\n", rc); - return; - } - } - - /* - * Create a virtual harddisk - */ - nsCOMPtr hardDisk = 0; - rc = virtualBox->CreateHardDisk(NS_LITERAL_STRING("VDI").get(), - NS_LITERAL_STRING("TestHardDisk.vdi").get(), - getter_AddRefs(hardDisk)); - if (NS_FAILED(rc)) - { - printf("Failed creating a hard disk object! rc=%08X\n", rc); - } - else - { - /* - * We have only created an object so far. No on disk representation exists - * because none of its properties has been set so far. Let's continue creating - * a dynamically expanding image. - */ - nsCOMPtr progress; - rc = hardDisk->CreateBaseStorage(100, // size in megabytes - MediumVariant_Standard, - getter_AddRefs(progress)); // optional progress object - if (NS_FAILED(rc)) - { - printf("Failed creating hard disk image! rc=%08X\n", rc); - } - else - { - /* - * Creating the image is done in the background because it can take quite - * some time (at least fixed size images). We have to wait for its completion. - * Here we wait forever (timeout -1) which is potentially dangerous. - */ - rc = progress->WaitForCompletion(-1); - PRInt32 resultCode; - progress->GetResultCode(&resultCode); - if (NS_FAILED(rc) || NS_FAILED(resultCode)) - { - printf("Error: could not create hard disk! rc=%08X\n", - NS_FAILED(rc) ? rc : resultCode); - } - else - { - /* - * Now that it's created, we can assign it to the VM. - */ - rc = machine->AttachDevice(NS_LITERAL_STRING("IDE Controller").get(), // controller identifier - 0, // channel number on the controller - 0, // device number on the controller - DeviceType_HardDisk, - hardDisk); - if (NS_FAILED(rc)) - { - printf("Error: could not attach hard disk! rc=%08X\n", rc); - } - } - } - } - - /* - * It's got a hard disk but that one is new and thus not bootable. Make it - * boot from an ISO file. This requires some processing. First the ISO file - * has to be registered and then mounted to the VM's DVD drive and selected - * as the boot device. - */ - nsCOMPtr dvdImage; - rc = virtualBox->OpenMedium(NS_LITERAL_STRING("/home/vbox/isos/winnt4ger.iso").get(), - DeviceType_DVD, - AccessMode_ReadOnly, - false /* fForceNewUuid */, - getter_AddRefs(dvdImage)); - if (NS_FAILED(rc)) - printf("Error: could not open CD image! rc=%08X\n", rc); - else - { - /* - * Now assign it to our VM - */ - rc = machine->MountMedium(NS_LITERAL_STRING("IDE Controller").get(), // controller identifier - 2, // channel number on the controller - 0, // device number on the controller - dvdImage, - PR_FALSE); // aForce - if (NS_FAILED(rc)) - { - printf("Error: could not mount ISO image! rc=%08X\n", rc); - } - else - { - /* - * Last step: tell the VM to boot from the CD. - */ - rc = machine->SetBootOrder (1, DeviceType::DVD); - if (NS_FAILED(rc)) - { - printf("Could not set boot device! rc=%08X\n", rc); - } - } - } - - /* - * Save all changes we've just made. - */ - rc = machine->SaveSettings(); - if (NS_FAILED(rc)) - { - printf("Could not save machine settings! rc=%08X\n", rc); - } - - /* - * It is always important to close the open session when it becomes not - * necessary any more. - */ - session->UnlockMachine(); -} - -// main -/////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char *argv[]) -{ - /* - * Check that PRUnichar is equal in size to what compiler composes L"" - * strings from; otherwise NS_LITERAL_STRING macros won't work correctly - * and we will get a meaningless SIGSEGV. This, of course, must be checked - * at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks - * compile-time assert macros and I'm not going to add them now. - */ - if (sizeof(PRUnichar) != sizeof(wchar_t)) - { - printf("Error: sizeof(PRUnichar) {%lu} != sizeof(wchar_t) {%lu}!\n" - "Probably, you forgot the -fshort-wchar compiler option.\n", - (unsigned long) sizeof(PRUnichar), - (unsigned long) sizeof(wchar_t)); - return -1; - } - - nsresult rc; - - /* - * This is the standard XPCOM init procedure. - * What we do is just follow the required steps to get an instance - * of our main interface, which is IVirtualBox. - */ -#if defined(XPCOM_GLUE) - XPCOMGlueStartup(nsnull); -#endif - - /* - * Note that we scope all nsCOMPtr variables in order to have all XPCOM - * objects automatically released before we call NS_ShutdownXPCOM at the - * end. This is an XPCOM requirement. - */ - { - nsCOMPtr serviceManager; - rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull); - if (NS_FAILED(rc)) - { - printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc); - return -1; - } - -#if 0 - /* - * Register our components. This step is only necessary if this executable - * implements XPCOM components itself which is not the case for this - * simple example. - */ - nsCOMPtr registrar = do_QueryInterface(serviceManager); - if (!registrar) - { - printf("Error: could not query nsIComponentRegistrar interface!\n"); - return -1; - } - registrar->AutoRegister(nsnull); -#endif - - /* - * Make sure the main event queue is created. This event queue is - * responsible for dispatching incoming XPCOM IPC messages. The main - * thread should run this event queue's loop during lengthy non-XPCOM - * operations to ensure messages from the VirtualBox server and other - * XPCOM IPC clients are processed. This use case doesn't perform such - * operations so it doesn't run the event loop. - */ - nsCOMPtr eventQ; - rc = NS_GetMainEventQ(getter_AddRefs (eventQ)); - if (NS_FAILED(rc)) - { - printf("Error: could not get main event queue! rc=%08X\n", rc); - return -1; - } - - /* - * Now XPCOM is ready and we can start to do real work. - * IVirtualBox is the root interface of VirtualBox and will be - * retrieved from the XPCOM component manager. We use the - * XPCOM provided smart pointer nsCOMPtr for all objects because - * that's very convenient and removes the need deal with reference - * counting and freeing. - */ - nsCOMPtr manager; - rc = NS_GetComponentManager (getter_AddRefs (manager)); - if (NS_FAILED(rc)) - { - printf("Error: could not get component manager! rc=%08X\n", rc); - return -1; - } - - nsCOMPtr virtualBox; - rc = manager->CreateInstanceByContractID (NS_VIRTUALBOX_CONTRACTID, - nsnull, - NS_GET_IID(IVirtualBox), - getter_AddRefs(virtualBox)); - if (NS_FAILED(rc)) - { - printf("Error, could not instantiate VirtualBox object! rc=0x%x\n", rc); - return -1; - } - printf("VirtualBox object created\n"); - - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - - - listVMs(virtualBox); - - createVM(virtualBox); - - - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - - /* this is enough to free the IVirtualBox instance -- smart pointers rule! */ - virtualBox = nsnull; - - /* - * Process events that might have queued up in the XPCOM event - * queue. If we don't process them, the server might hang. - */ - eventQ->ProcessPendingEvents(); - } - - /* - * Perform the standard XPCOM shutdown procedure. - */ - NS_ShutdownXPCOM(nsnull); -#if defined(XPCOM_GLUE) - XPCOMGlueShutdown(); -#endif - printf("Done!\n"); - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////////////////// -//// Helpers -////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Helper function to convert an nsID into a human readable string - * - * @returns result string, allocated. Has to be freed using free() - * @param guid Pointer to nsID that will be converted. - */ -char *nsIDToString(nsID *guid) -{ - char *res = (char*)malloc(39); - - if (res != NULL) - { - snprintf(res, 39, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - guid->m0, (PRUint32)guid->m1, (PRUint32)guid->m2, - (PRUint32)guid->m3[0], (PRUint32)guid->m3[1], (PRUint32)guid->m3[2], - (PRUint32)guid->m3[3], (PRUint32)guid->m3[4], (PRUint32)guid->m3[5], - (PRUint32)guid->m3[6], (PRUint32)guid->m3[7]); - } - return res; -} - -/** - * Helper function to print XPCOM exception information set on the current - * thread after a failed XPCOM method call. This function will also print - * extended VirtualBox error info if it is available. - */ -void printErrorInfo() -{ - nsresult rc; - - nsCOMPtr es; - es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); - if (NS_SUCCEEDED(rc)) - { - nsCOMPtr em; - rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); - if (NS_SUCCEEDED(rc)) - { - nsCOMPtr ex; - rc = em->GetCurrentException (getter_AddRefs (ex)); - if (NS_SUCCEEDED(rc) && ex) - { - nsCOMPtr info; - info = do_QueryInterface(ex, &rc); - if (NS_SUCCEEDED(rc) && info) - { - /* got extended error info */ - printf ("Extended error info (IVirtualBoxErrorInfo):\n"); - PRInt32 resultCode = NS_OK; - info->GetResultCode (&resultCode); - printf (" resultCode=%08X\n", resultCode); - nsXPIDLString component; - info->GetComponent (getter_Copies (component)); - printf (" component=%s\n", NS_ConvertUTF16toUTF8(component).get()); - nsXPIDLString text; - info->GetText (getter_Copies (text)); - printf (" text=%s\n", NS_ConvertUTF16toUTF8(text).get()); - } - else - { - /* got basic error info */ - printf ("Basic error info (nsIException):\n"); - nsresult resultCode = NS_OK; - ex->GetResult (&resultCode); - printf (" resultCode=%08X\n", resultCode); - nsXPIDLCString message; - ex->GetMessage (getter_Copies (message)); - printf (" message=%s\n", message.get()); - } - - /* reset the exception to NULL to indicate we've processed it */ - em->SetCurrentException (NULL); - - rc = NS_OK; - } - } - } -} diff --git a/src/VBox/Main/testcase/tstVBoxAPIWin.cpp b/src/VBox/Main/testcase/tstVBoxAPIWin.cpp index d3c0839c..6211e428 100644 --- a/src/VBox/Main/testcase/tstVBoxAPIWin.cpp +++ b/src/VBox/Main/testcase/tstVBoxAPIWin.cpp @@ -12,7 +12,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp b/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp new file mode 100644 index 00000000..1ea16f62 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp @@ -0,0 +1,655 @@ +/** @file + * + * tstVBoxAPILinux - sample program to illustrate the VirtualBox + * XPCOM API for machine management on Linux. + * It only uses standard C/C++ and XPCOM semantics, + * no additional VBox classes/macros/helpers. + */ + +/* + * Copyright (C) 2006-2014 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * PURPOSE OF THIS SAMPLE PROGRAM + * ------------------------------ + * + * This sample program is intended to demonstrate the minimal code necessary + * to use VirtualBox XPCOM API for learning puroses only. The program uses + * pure XPCOM and doesn't have any extra dependencies to let you better + * understand what is going on when a client talks to the VirtualBox core + * using the XPCOM framework. + * + * However, if you want to write a real application, it is highly recommended + * to use our MS COM XPCOM Glue library and helper C++ classes. This way, you + * will get at least the following benefits: + * + * a) better portability: both the MS COM (used on Windows) and XPCOM (used + * everywhere else) VirtualBox client application from the same source code + * (including common smart C++ templates for automatic interface pointer + * reference counter and string data management); + * b) simpler XPCOM initialization and shutdown (only a single method call + * that does everything right). + * + * Currently, there is no separate sample program that uses the VirtualBox MS + * COM XPCOM Glue library. Please refer to the sources of stock VirtualBox + * applications such as the VirtualBox GUI frontend or the VBoxManage command + * line frontend. + * + * + * RUNNING THIS SAMPLE PROGRAM + * --------------------------- + * + * This sample program needs to know where the VirtualBox core files reside + * and where to search for VirtualBox shared libraries. Therefore, you need to + * use the following (or similar) command to execute it: + * + * $ env VBOX_XPCOM_HOME=../../.. LD_LIBRARY_PATH=../../.. ./tstVBoxAPILinux + * + * The above command assumes that VBoxRT.so, VBoxXPCOM.so and others reside in + * the directory ../../.. + */ + + +#include +#include +#include + +/* + * Include the XPCOM headers + */ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + + +/* + * VirtualBox XPCOM interface. This header is generated + * from IDL which in turn is generated from a custom XML format. + */ +#include "VirtualBox_XPCOM.h" + +/* + * Prototypes + */ + +char *nsIDToString(nsID *guid); +void printErrorInfo(); + + +/** + * Display all registered VMs on the screen with some information about each + * + * @param virtualBox VirtualBox instance object. + */ +void listVMs(IVirtualBox *virtualBox) +{ + nsresult rc; + + RTPrintf("----------------------------------------------------\n"); + RTPrintf("VM List:\n\n"); + + /* + * Get the list of all registered VMs + */ + IMachine **machines = NULL; + PRUint32 machineCnt = 0; + + rc = virtualBox->GetMachines(&machineCnt, &machines); + if (NS_SUCCEEDED(rc)) + { + /* + * Iterate through the collection + */ + for (PRUint32 i = 0; i < machineCnt; ++ i) + { + IMachine *machine = machines[i]; + if (machine) + { + PRBool isAccessible = PR_FALSE; + machine->GetAccessible(&isAccessible); + + if (isAccessible) + { + nsXPIDLString machineName; + machine->GetName(getter_Copies(machineName)); + char *machineNameAscii = ToNewCString(machineName); + RTPrintf("\tName: %s\n", machineNameAscii); + free(machineNameAscii); + } + else + { + RTPrintf("\tName: \n"); + } + + nsXPIDLString iid; + machine->GetId(getter_Copies(iid)); + const char *uuidString = ToNewCString(iid); + RTPrintf("\tUUID: %s\n", uuidString); + free((void*)uuidString); + + if (isAccessible) + { + nsXPIDLString configFile; + machine->GetSettingsFilePath(getter_Copies(configFile)); + char *configFileAscii = ToNewCString(configFile); + RTPrintf("\tConfig file: %s\n", configFileAscii); + free(configFileAscii); + + PRUint32 memorySize; + machine->GetMemorySize(&memorySize); + RTPrintf("\tMemory size: %uMB\n", memorySize); + + nsXPIDLString typeId; + machine->GetOSTypeId(getter_Copies(typeId)); + IGuestOSType *osType = nsnull; + virtualBox->GetGuestOSType (typeId.get(), &osType); + nsXPIDLString osName; + osType->GetDescription(getter_Copies(osName)); + char *osNameAscii = ToNewCString(osName); + RTPrintf("\tGuest OS: %s\n\n", osNameAscii); + free(osNameAscii); + osType->Release(); + } + + /* don't forget to release the objects in the array... */ + machine->Release(); + } + } + } + RTPrintf("----------------------------------------------------\n\n"); +} + +/** + * Create a sample VM + * + * @param virtualBox VirtualBox instance object. + */ +void createVM(IVirtualBox *virtualBox) +{ + nsresult rc; + /* + * First create a unnamed new VM. It will be unconfigured and not be saved + * in the configuration until we explicitely choose to do so. + */ + nsCOMPtr machine; + rc = virtualBox->CreateMachine(NULL, /* settings file */ + NS_LITERAL_STRING("A brand new name").get(), + 0, nsnull, /* groups (safearray)*/ + nsnull, /* ostype */ + nsnull, /* create flags */ + getter_AddRefs(machine)); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not create machine! rc=%Rhrc\n", rc); + return; + } + + /* + * Set some properties + */ + /* alternative to illustrate the use of string classes */ + rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get()); + rc = machine->SetMemorySize(128); + + /* + * Now a more advanced property -- the guest OS type. This is + * an object by itself which has to be found first. Note that we + * use the ID of the guest OS type here which is an internal + * representation (you can find that by configuring the OS type of + * a machine in the GUI and then looking at the + * setting in the XML file. It is also possible to get the OS type from + * its description (win2k would be "Windows 2000") by getting the + * guest OS type collection and enumerating it. + */ + nsCOMPtr osType; + rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("Windows2000").get(), + getter_AddRefs(osType)); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not find guest OS type! rc=%Rhrc\n", rc); + } + else + { + machine->SetOSTypeId (NS_LITERAL_STRING("Windows2000").get()); + } + + /* + * Register the VM. Note that this call also saves the VM config + * to disk. It is also possible to save the VM settings but not + * register the VM. + * + * Also note that due to current VirtualBox limitations, the machine + * must be registered *before* we can attach hard disks to it. + */ + rc = virtualBox->RegisterMachine(machine); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not register machine! rc=%Rhrc\n", rc); + printErrorInfo(); + return; + } + + nsCOMPtr origMachine = machine; + + /* + * In order to manipulate the registered machine, we must open a session + * for that machine. Do it now. + */ + nsCOMPtr session; + nsCOMPtr sessionMachine; + { + nsCOMPtr manager; + rc = NS_GetComponentManager (getter_AddRefs (manager)); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not get component manager! rc=%Rhrc\n", rc); + return; + } + rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID, + nsnull, + NS_GET_IID(ISession), + getter_AddRefs(session)); + if (NS_FAILED(rc)) + { + RTPrintf("Error, could not instantiate session object! rc=%Rhrc\n", rc); + return; + } + + rc = machine->LockMachine(session, LockType_Write); + if (NS_FAILED(rc)) + { + RTPrintf("Error, could not lock the machine for the session! rc=%Rhrc\n", rc); + return; + } + + /* + * After the machine is registered, the initial machine object becomes + * immutable. In order to get a mutable machine object, we must query + * it from the opened session object. + */ + rc = session->GetMachine(getter_AddRefs(sessionMachine)); + if (NS_FAILED(rc)) + { + RTPrintf("Error, could not get machine session! rc=%Rhrc\n", rc); + return; + } + } + + /* + * Create a virtual harddisk + */ + nsCOMPtr hardDisk = 0; + rc = virtualBox->CreateHardDisk(NS_LITERAL_STRING("VDI").get(), + NS_LITERAL_STRING("TestHardDisk.vdi").get(), + getter_AddRefs(hardDisk)); + if (NS_FAILED(rc)) + { + RTPrintf("Failed creating a hard disk object! rc=%Rhrc\n", rc); + } + else + { + /* + * We have only created an object so far. No on disk representation exists + * because none of its properties has been set so far. Let's continue creating + * a dynamically expanding image. + */ + nsCOMPtr progress; + com::SafeArray mediumVariant; + mediumVariant.push_back(MediumVariant_Standard); + rc = hardDisk->CreateBaseStorage(100, // size in megabytes + ComSafeArrayAsInParam(mediumVariant), + getter_AddRefs(progress)); // optional progress object + if (NS_FAILED(rc)) + { + RTPrintf("Failed creating hard disk image! rc=%Rhrc\n", rc); + } + else + { + /* + * Creating the image is done in the background because it can take quite + * some time (at least fixed size images). We have to wait for its completion. + * Here we wait forever (timeout -1) which is potentially dangerous. + */ + rc = progress->WaitForCompletion(-1); + PRInt32 resultCode; + progress->GetResultCode(&resultCode); + if (NS_FAILED(rc) || NS_FAILED(resultCode)) + { + RTPrintf("Error: could not create hard disk! rc=%Rhrc\n", + NS_FAILED(rc) ? rc : resultCode); + } + else + { + /* + * Now that it's created, we can assign it to the VM. + */ + rc = sessionMachine->AttachDevice( + NS_LITERAL_STRING("IDE Controller").get(), // controller identifier + 0, // channel number on the controller + 0, // device number on the controller + DeviceType_HardDisk, + hardDisk); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not attach hard disk! rc=%Rhrc\n", rc); + } + } + } + } + + /* + * It's got a hard disk but that one is new and thus not bootable. Make it + * boot from an ISO file. This requires some processing. First the ISO file + * has to be registered and then mounted to the VM's DVD drive and selected + * as the boot device. + */ + nsCOMPtr dvdImage; + rc = virtualBox->OpenMedium(NS_LITERAL_STRING("/home/vbox/isos/winnt4ger.iso").get(), + DeviceType_DVD, + AccessMode_ReadOnly, + false /* fForceNewUuid */, + getter_AddRefs(dvdImage)); + if (NS_FAILED(rc)) + RTPrintf("Error: could not open CD image! rc=%Rhrc\n", rc); + else + { + /* + * Now assign it to our VM + */ + rc = sessionMachine->MountMedium( + NS_LITERAL_STRING("IDE Controller").get(), // controller identifier + 2, // channel number on the controller + 0, // device number on the controller + dvdImage, + PR_FALSE); // aForce + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not mount ISO image! rc=%Rhrc\n", rc); + } + else + { + /* + * Last step: tell the VM to boot from the CD. + */ + rc = sessionMachine->SetBootOrder (1, DeviceType::DVD); + if (NS_FAILED(rc)) + { + RTPrintf("Could not set boot device! rc=%Rhrc\n", rc); + } + } + } + + /* + * Save all changes we've just made. + */ + rc = sessionMachine->SaveSettings(); + if (NS_FAILED(rc)) + RTPrintf("Could not save machine settings! rc=%Rhrc\n", rc); + + /* + * It is always important to close the open session when it becomes not + * necessary any more. + */ + session->UnlockMachine(); + + com::SafeIfaceArray aMedia; + rc = machine->Unregister((CleanupMode_T)CleanupMode_DetachAllReturnHardDisksOnly, + ComSafeArrayAsOutParam(aMedia)); + if (NS_FAILED(rc)) + RTPrintf("Unregistering the machine failed! rc=%Rhrc\n", rc); + else + { + ComPtr pProgress; + rc = machine->DeleteConfig(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()); + if (NS_FAILED(rc)) + RTPrintf("Deleting of machine failed! rc=%Rhrc\n", rc); + else + { + rc = pProgress->WaitForCompletion(-1); + PRInt32 resultCode; + pProgress->GetResultCode(&resultCode); + if (NS_FAILED(rc) || NS_FAILED(resultCode)) + RTPrintf("Failed to delete the machine! rc=%Rhrc\n", + NS_FAILED(rc) ? rc : resultCode); + } + } +} + +// main +/////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) +{ + /* + * Check that PRUnichar is equal in size to what compiler composes L"" + * strings from; otherwise NS_LITERAL_STRING macros won't work correctly + * and we will get a meaningless SIGSEGV. This, of course, must be checked + * at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks + * compile-time assert macros and I'm not going to add them now. + */ + if (sizeof(PRUnichar) != sizeof(wchar_t)) + { + RTPrintf("Error: sizeof(PRUnichar) {%lu} != sizeof(wchar_t) {%lu}!\n" + "Probably, you forgot the -fshort-wchar compiler option.\n", + (unsigned long) sizeof(PRUnichar), + (unsigned long) sizeof(wchar_t)); + return -1; + } + + nsresult rc; + + /* + * This is the standard XPCOM init procedure. + * What we do is just follow the required steps to get an instance + * of our main interface, which is IVirtualBox. + * + * Note that we scope all nsCOMPtr variables in order to have all XPCOM + * objects automatically released before we call NS_ShutdownXPCOM at the + * end. This is an XPCOM requirement. + */ + { + nsCOMPtr serviceManager; + rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull); + if (NS_FAILED(rc)) + { + RTPrintf("Error: XPCOM could not be initialized! rc=%Rhrc\n", rc); + return -1; + } + +#if 0 + /* + * Register our components. This step is only necessary if this executable + * implements XPCOM components itself which is not the case for this + * simple example. + */ + nsCOMPtr registrar = do_QueryInterface(serviceManager); + if (!registrar) + { + RTPrintf("Error: could not query nsIComponentRegistrar interface!\n"); + return -1; + } + registrar->AutoRegister(nsnull); +#endif + + /* + * Make sure the main event queue is created. This event queue is + * responsible for dispatching incoming XPCOM IPC messages. The main + * thread should run this event queue's loop during lengthy non-XPCOM + * operations to ensure messages from the VirtualBox server and other + * XPCOM IPC clients are processed. This use case doesn't perform such + * operations so it doesn't run the event loop. + */ + nsCOMPtr eventQ; + rc = NS_GetMainEventQ(getter_AddRefs (eventQ)); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not get main event queue! rc=%Rhrc\n", rc); + return -1; + } + + /* + * Now XPCOM is ready and we can start to do real work. + * IVirtualBox is the root interface of VirtualBox and will be + * retrieved from the XPCOM component manager. We use the + * XPCOM provided smart pointer nsCOMPtr for all objects because + * that's very convenient and removes the need deal with reference + * counting and freeing. + */ + nsCOMPtr manager; + rc = NS_GetComponentManager (getter_AddRefs (manager)); + if (NS_FAILED(rc)) + { + RTPrintf("Error: could not get component manager! rc=%Rhrc\n", rc); + return -1; + } + + nsCOMPtr virtualBox; + rc = manager->CreateInstanceByContractID (NS_VIRTUALBOX_CONTRACTID, + nsnull, + NS_GET_IID(IVirtualBox), + getter_AddRefs(virtualBox)); + if (NS_FAILED(rc)) + { + RTPrintf("Error, could not instantiate VirtualBox object! rc=%Rhrc\n", rc); + return -1; + } + RTPrintf("VirtualBox object created\n"); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + + listVMs(virtualBox); + + createVM(virtualBox); + + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /* this is enough to free the IVirtualBox instance -- smart pointers rule! */ + virtualBox = nsnull; + + /* + * Process events that might have queued up in the XPCOM event + * queue. If we don't process them, the server might hang. + */ + eventQ->ProcessPendingEvents(); + } + + /* + * Perform the standard XPCOM shutdown procedure. + */ + NS_ShutdownXPCOM(nsnull); + RTPrintf("Done!\n"); + return 0; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +//// Helpers +////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Helper function to convert an nsID into a human readable string + * + * @returns result string, allocated. Has to be freed using free() + * @param guid Pointer to nsID that will be converted. + */ +char *nsIDToString(nsID *guid) +{ + char *res = (char*)malloc(39); + + if (res != NULL) + { + RTStrPrintf(res, 39, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->m0, (PRUint32)guid->m1, (PRUint32)guid->m2, + (PRUint32)guid->m3[0], (PRUint32)guid->m3[1], (PRUint32)guid->m3[2], + (PRUint32)guid->m3[3], (PRUint32)guid->m3[4], (PRUint32)guid->m3[5], + (PRUint32)guid->m3[6], (PRUint32)guid->m3[7]); + } + return res; +} + +/** + * Helper function to print XPCOM exception information set on the current + * thread after a failed XPCOM method call. This function will also print + * extended VirtualBox error info if it is available. + */ +void printErrorInfo() +{ + nsresult rc; + + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr em; + rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr ex; + rc = em->GetCurrentException (getter_AddRefs (ex)); + if (NS_SUCCEEDED(rc) && ex) + { + nsCOMPtr info; + info = do_QueryInterface(ex, &rc); + if (NS_SUCCEEDED(rc) && info) + { + /* got extended error info */ + RTPrintf ("Extended error info (IVirtualBoxErrorInfo):\n"); + PRInt32 resultCode = NS_OK; + info->GetResultCode (&resultCode); + RTPrintf (" resultCode=%08X\n", resultCode); + nsXPIDLString component; + info->GetComponent (getter_Copies (component)); + RTPrintf (" component=%s\n", NS_ConvertUTF16toUTF8(component).get()); + nsXPIDLString text; + info->GetText (getter_Copies (text)); + RTPrintf (" text=%s\n", NS_ConvertUTF16toUTF8(text).get()); + } + else + { + /* got basic error info */ + RTPrintf ("Basic error info (nsIException):\n"); + nsresult resultCode = NS_OK; + ex->GetResult (&resultCode); + RTPrintf (" resultCode=%08X\n", resultCode); + nsXPIDLCString message; + ex->GetMessage (getter_Copies (message)); + RTPrintf (" message=%s\n", message.get()); + } + + /* reset the exception to NULL to indicate we've processed it */ + em->SetCurrentException (NULL); + + rc = NS_OK; + } + } + } +} diff --git a/src/VBox/Main/webservice/MANIFEST.MF.in b/src/VBox/Main/webservice/MANIFEST.MF.in index 89d7a5b2..3d04734c 100644 --- a/src/VBox/Main/webservice/MANIFEST.MF.in +++ b/src/VBox/Main/webservice/MANIFEST.MF.in @@ -22,7 +22,7 @@ Import-Package: javax.validation.constraints;version="1.0", javax.xml.ws.soap,javax.xml.ws.handler,javax.xml.ws.http, javax.xml.ws.wsaddressing,javax.xml.parsers,javax.xml.stream, javax.xml.transform,javax.xml.transform.dom, - javax.xml.transform.stream,org.w2c.dom,org.xml.sax,javax.xml.bind, + javax.xml.transform.stream,org.w3c.dom,org.xml.sax,javax.xml.bind, javax.xml.bind.annotation,javax.xml.bind.attachment, javax.xml.bind.helpers,javax.xml.bind.util, org.virtualbox@VBOX_API_SUFFIX@;version="@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@" diff --git a/src/VBox/Main/webservice/Makefile.kmk b/src/VBox/Main/webservice/Makefile.kmk index 17e50bcf..abc15123 100644 --- a/src/VBox/Main/webservice/Makefile.kmk +++ b/src/VBox/Main/webservice/Makefile.kmk @@ -6,7 +6,7 @@ # # -# Copyright (C) 2007-2012 Oracle Corporation +# Copyright (C) 2007-2013 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -151,6 +151,9 @@ BLDDIRS += $(VBOXWEB_OUT_DIR) # The webservice location VBOX_PATH_WEBSERVICE := $(PATH_SUB_CURRENT) +# The IDL subdirectory (contains some XSLT files) +VBOX_PATH_IDL := $(abspath $(PATH_SUB_CURRENT)/../idl) + # If this is set, all webservice files are considered out-of-date every time # this makefile is touched. Otherwise, set this to empty. RECOMPILE_ON_MAKEFILE_CURRENT := $(MAKEFILE_CURRENT) @@ -167,8 +170,8 @@ VBOXWEB_IDL_SRC_STRIPPED := $(VBOX_XIDL_FILE) # platform-specific XIDL file generated from $(VBOXWEB_IDL_SRC_STRIPPED): VBOXWEB_IDL_SRC := $(VBOXWEB_OUT_DIR)/VirtualBox.xidl -VBOXWEB_WSDL = $(VBOX_PATH_SDK)/bindings/webservice/vboxweb.wsdl -VBOXWEBSERVICE_WSDL = $(VBOX_PATH_SDK)/bindings/webservice/vboxwebService.wsdl +VBOXWEB_WSDL = $(VBOXWEB_OUT_DIR)/vboxweb.wsdl +VBOXWEBSERVICE_WSDL = $(VBOXWEB_OUT_DIR)/vboxwebService.wsdl VBOXWEB_TYPEMAP := $(VBOXWEB_OUT_DIR)/typemap.dat @@ -249,6 +252,8 @@ ifdef VBOX_GSOAP_INSTALLED $(VBOXWEB_OUT_DIR)/soapC-18.cpp \ $(VBOXWEB_OUT_DIR)/soapC-19.cpp \ $(VBOXWEB_OUT_DIR)/soapC-20.cpp + vboxsoap_CXXFLAGS += \ + $(VBOX_GCC_Wno-vla) endif vboxsoap_CLEAN := $(vboxsoap_SOURCES) # lazy bird vboxsoap_SOURCES += \ @@ -331,6 +336,7 @@ VBOX_JWSDOC_JAR = $(VBoxJWs-inst-jar_0_OUTDIR)/vboxjws-doc.jar VBOX_JWSSRC_JAR = $(VBoxJWs-inst-jar_0_OUTDIR)/vboxjws-src.jar VBOX_JWS_TARGET := $(PATH_TARGET)/vboxjws-gen VBOX_JWS_GEN = $(VBOX_JWS_TARGET)/jwsgen +VBOX_JWS_GEN_RAWSRC = $(VBOX_JWS_GEN)/merged.file VBOX_JWS_JDEST := $(VBOX_JWS_TARGET)/jdest VBOX_JWSDOC_JDEST := $(VBOX_JWS_TARGET)/jdest-doc VBOX_GLUE_XSLT_DIR := $(PATH_ROOT)/src/VBox/Main/glue @@ -362,27 +368,58 @@ VBoxJWs-inst-jar_CLEAN = \ $(VBOX_JWSDOC_JDEST)/*/*/*/*.html \ ) VBoxJWs-inst-jar_BLDDIRS += $(VBOX_JWS_GEN)/java +VBoxJWs-inst-jar_GENERATEDSOURCES = $(addprefix $(VBoxJWs-inst-jar_BLDDIRS)/,$(VBoxJWS_VBOX_JWSGLUEFILES)) + +VBoxJWSGlue_KMK = $(PATH_OUT)/vboxjwsglue.kmk +include $(VBoxJWSGlue_KMK) -$(VBOX_JWS_GEN)/jwsglue.list: \ +$(VBoxJWSGlue_KMK).ts +| $(VBoxJWSGlue_KMK): $(VBOXWEB_IDL_SRC_ORIG) $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl + $(call MSG_GENERATE,,$(VBoxJWSGlue_KMK)) + $(QUIET)$(RM) -f $@ + $(QUIET)$(MKDIR) -p $(@D) + $(QUIET)$(VBOX_XSLTPROC) \ + --stringparam filelistonly VBoxJWS_VBOX_JWSGLUEFILES \ + --stringparam G_vboxApiSuffix $(VBOX_API_SUFFIX) \ + --stringparam G_vboxGlueStyle jaxws \ + --stringparam G_vboxDirPrefix org/virtualbox$(VBOX_API_SUFFIX)/ \ + -o $@ $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< + $(QUIET)$(CP) --changed -fv $@ $(VBoxJWSGlue_KMK) + +$(VBOX_JWS_GEN_RAWSRC) \ ++| $(VBoxJWs-inst-jar_GENERATEDSOURCES): \ $(VBOXWEB_IDL_SRC_ORIG) \ $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl \ - $(VBOX_FILESPLIT) \ - $(VBOXWEBSERVICE_WSDL) \ - $(VBOXWEB_WSDL) \ - | $(VBOX_JWS_GEN)/java/ + $(VBOX_FILESPLIT) $(call MSG_L1,Generating JAX-WS Java glue files from XIDL) - $(QUIET)$(RM) -f $(wildcard $(VBOX_JWS_GEN)/java/*/*/*.java) $(wildcard $(VBOX_JWS_GEN)/java/*/*/*/*.java) + $(QUIET)$(RM) -f $(filter-out $(VBoxJWs-inst-jar_GENERATEDSOURCES),$(wildcard $(VBOX_JWS_GEN)/java/*/*/*.java)) + $(QUIET)$(MKDIR) -p $(@D) $(QUIET)$(VBOX_XSLTPROC) \ + --stringparam filelistonly "" \ --stringparam G_vboxApiSuffix $(VBOX_API_SUFFIX) \ --stringparam G_vboxGlueStyle jaxws \ --stringparam G_vboxDirPrefix org/virtualbox$(VBOX_API_SUFFIX)/ \ - -o $(VBOX_JWS_GEN)/merged.file $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< + -o $(VBOX_JWS_GEN_RAWSRC) $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< $(QUIET)$(MKDIR) -p $(VBOX_JWS_GEN)/java/org/virtualbox$(VBOX_API_SUFFIX) - $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JWS_GEN)/merged.file $(VBOX_JWS_GEN)/java - $(call MSG_GENERATE,,$@,JAX-WS for Java 1.6 bindings using $(VBOXWEBSERVICE_WSDL)) + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JWS_GEN_RAWSRC) $(VBOX_JWS_GEN)/java + +## @todo somehow also find out the authoritative list of files generated by +# wsimport (before running it), then we could rely on proper dependencies +# instead of creating jwsglue.list. Would allow avoiding a lot of unnecessary +# compilation with incremental builds, when almost nothing changed in the IDL +# file. Currently everything is recompiled if only one file is changed. +$(VBOX_JWS_GEN)/jwsglue.list.ts +| $(VBOX_JWS_GEN)/jwsglue.list: \ + $(VBOXWEB_IDL_SRC) \ + $(VBOX_FILESPLIT) \ + $(VBOXWEBSERVICE_WSDL) \ + $(VBOXWEB_WSDL) \ + $(VBoxJWs-inst-jar_GENERATEDSOURCES) \ + | $(VBOX_JWS_GEN)/java/ + $(QUIET)$(RM) -f $(wildcard $(VBOX_JWS_GEN)/java/*/*/*/*.java) + $(call MSG_GENERATE,,$(VBOX_JWS_GEN)/jwsglue.list,JAX-WS for Java 1.6 bindings using $(VBOXWEBSERVICE_WSDL)) $(VBOX_WSIMPORT) -Xnocompile -p $(VBOX_JAVA_PACKAGE).jaxws -d $(VBOX_JWS_GEN)/java $(VBOXWEBSERVICE_WSDL) - $(QUIET)echo $(VBOX_JWS_GEN)/java/*/*/*.java > $@ + $(QUIET)echo $(VBoxJWs-inst-jar_GENERATEDSOURCES) > $@ $(QUIET)echo $(VBOX_JWS_GEN)/java/*/*/*/*.java >> $@ + $(QUIET)$(CP) --changed -fv $@ $(VBOX_JWS_GEN)/jwsglue.list $$(VBOX_JWS_JAR): $(VBOX_JWS_GEN)/jwsglue.list $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL) $(VBOX_JWS_GEN)/MANIFEST.MF | $$(dir $$@) $(call MSG_TOOL,javac,$(notdir $@),jwsgen.list,) @@ -483,7 +520,7 @@ $$(VBOX_JWSSRC_JAR): $$(VBOX_JWS_JAR) | $$(dir $$@) endif # VBOX_GSOAP_INSTALLED -ifdef VBOX_ONLY_SDK +if defined(VBOX_ONLY_SDK) && "$(KBUILD_TARGET)" != "win" # # Globals relevant to the SDK. # @@ -495,12 +532,6 @@ ifdef VBOX_ONLY_SDK VBOXWEB_JAXWSSAMPLE = $(VBOXWEB_SAMPLES_JAXWS_DIR)/clienttest.java VBOXWEB_METRICSAMPLE = $(VBOXWEB_SAMPLES_JAXWS_DIR)/metrictest.java - VBOXWEB_GLUE_JAVA_TMP = $(VBOXWEB_OUT_DIR)/glue-jaxws.java.tmp - VBOXWEB_PATH_SDK_GLUE_JAVA = $(VBOX_PATH_SDK)/bindings/webservice/java/jax-ws/src - VBOXWEB_JAVALIB = $(VBOX_PATH_SDK)/bindings/webservice/java/jax-ws/lib - VBOXWEB_JAVA15_JAR = $(VBOXWEB_JAVALIB)/vboxws_java15.jar - VBOXWEB_JAVA16_JAR = $(VBOXWEB_JAVALIB)/vboxws_java16.jar - define find_java_files $(shell find $(1) -name \*.java) endef @@ -533,12 +564,14 @@ ifdef VBOX_ONLY_SDK samples/python/Makefile.glue=>python/lib/Makefile \ $(PATH_ROOT)/COPYING.LIB=>java/jax-ws/COPYING.LIB -endif # VBOX_ONLY_SDK + INSTALLS += vboxwebinst_wsdl + vboxwebinst_wsdl_INST = $(INST_SDK)bindings/webservice/ + vboxwebinst_wsdl_MODE = a+r,u+w + vboxwebinst_wsdl_SOURCES = \ + $(VBOXWEB_WSDL)=>vboxweb.wsdl \ + $(VBOXWEBSERVICE_WSDL)=>vboxwebService.wsdl -## @todo VBOXWEB_WSDL and VBOXWEBSERVICE_WSDL should be an install target. -VBOXWEB_OTHERS += \ - $(VBOXWEB_WSDL) \ - $(VBOXWEBSERVICE_WSDL) +endif # VBOX_ONLY_SDK # # Update the OTHERS and OTHER_CLEAN lists with VBOXWEB_OTHERS and some more stuff. @@ -549,6 +582,8 @@ VBOXWEB_OTHERS += \ OTHERS += $(VBOXWEB_OTHERS) OTHER_CLEAN += \ $(VBOXWEB_OTHERS) \ + $(VBOXWEB_WSDL) \ + $(VBOXWEBSERVICE_WSDL) \ $(VBOXWEB_TYPEMAP) \ $(VBOXWEB_IDL_SRC) @@ -559,16 +594,14 @@ $(VBOXWEB_IDL_SRC): $(VBOXWEB_IDL_SRC_STRIPPED) $(VBOX_PATH_WEBSERVICE)/platform $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/platform-xidl.xsl $< # generate WSDL from main XIDL file -$(VBOXWEB_WSDL): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) ## @todo | $$(dir $$@) +$(VBOXWEB_WSDL): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-wsdl.xsl) $(QUIET)$(RM) -f -- $@ - $(QUIET)$(MKDIR) -p $(@D) $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-wsdl.xsl $< -$(VBOXWEBSERVICE_WSDL): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl-service.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) ## @todo | $$(dir $$@) +$(VBOXWEBSERVICE_WSDL): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl-service.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-wsdl-service.xsl) $(QUIET)$(RM) -f -- $@ - $(QUIET)$(MKDIR) -p $(@D) $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-wsdl-service.xsl $< ifdef VBOX_ONLY_SDK @@ -584,7 +617,7 @@ $(VBOXWEB_WS_PYTHON): $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL) $(QUIET)$(RM) -f -- $@ $(QUIET)$(MKDIR) -p $(@D) # Try both w/o and with --file option - $(QUIET)$(REDIRECT) -C $(@D) -- bash -c "$(VBOX_WSDL2PY) -b $(VBOXWEBSERVICE_WSDL) || $(VBOX_WSDL2PY) -b --file $(VBOXWEBSERVICE_WSDL)" + $(QUIET)$(REDIRECT) -C $(@D) -- $(SHELL) -c "$(VBOX_WSDL2PY) -b $(VBOXWEBSERVICE_WSDL) || $(VBOX_WSDL2PY) -b --file $(VBOXWEBSERVICE_WSDL)" $(QUIET)$(APPEND) $@ '' $(VBOXWEB_WS_PERL): $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL) @@ -605,19 +638,19 @@ $(VBOXWEB_WS_PHP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-php.xsl endif # VBOX_ONLY_SDK # generate typemap.dat (used by wsdl2h) from main XIDL file -$(VBOXWEB_TYPEMAP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-typemap.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOXWEB_TYPEMAP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-typemap.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-typemap.xsl) $(QUIET)$(RM) -f -- $@ $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-typemap.xsl $< # generate gsoap pseudo-C header file from that WSDL; once via XSLT... -$(VBOXWEB_GSOAPH_FROM_XSLT): $(VBOXWEB_WSDL) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl2gsoapH.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOXWEB_GSOAPH_FROM_XSLT): $(VBOXWEB_WSDL) $(VBOX_PATH_WEBSERVICE)/websrv-wsdl2gsoapH.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_WSDL) using websrv-wsdl2gsoapH.xsl) $(QUIET)$(RM) -f -- $@ $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-wsdl2gsoapH.xsl $< VBOX_NSMAP = $(VBOXWEB_OUT_DIR)/vboxwebsrv.nsmap -$(VBOX_NSMAP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-nsmap.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOX_NSMAP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-nsmap.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-nsmap.xsl) $(QUIET)$(RM) -f -- $@ $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-nsmap.xsl $< @@ -710,14 +743,14 @@ endif # VBOX_GSOAP_INSTALLED # generate method maps in server: map wsdl operations to com/xpcom method calls -$(VBOXWEB_OUT_DIR)/methodmaps.cpp: $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-cpp.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOXWEB_OUT_DIR)/methodmaps.cpp: $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-cpp.xsl $(VBOX_PATH_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-cpp.xsl) $(QUIET)$(VBOX_XSLTPROC) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-cpp.xsl $< # generate C file which contains vboxweb.wsdl $$(VBOXWEB_OUT_DIR)/vboxweb-wsdl.c: $(VBOXWEB_WSDL) $(VBOX_BIN2C) $(call MSG_TOOL,bin2c,vboxweb-wsdl,$<,$@) - $(QUIET)$(VBOX_BIN2C) -export -ascii VBoxWebWSDL $< $@ + $(QUIET)$(VBOX_BIN2C) -ascii VBoxWebWSDL $< $@ ifdef VBOX_ONLY_SDK diff --git a/src/VBox/Main/webservice/platform-xidl.xsl b/src/VBox/Main/webservice/platform-xidl.xsl index 48dce42a..066a5fe9 100644 --- a/src/VBox/Main/webservice/platform-xidl.xsl +++ b/src/VBox/Main/webservice/platform-xidl.xsl @@ -8,7 +8,7 @@ is identical to the original except that all sections are resolved (for easier processing). - Copyright (C) 2006-2011 Oracle Corporation + Copyright (C) 2006-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile index fd8d7921..97cbb6ed 100644 --- a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile +++ b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2008 Oracle Corporation +# Copyright (C) 2008-2010 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue index c7aea553..2a9f95bc 100644 --- a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue +++ b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue @@ -1,5 +1,5 @@ # -# Copyright (C) 2008 Oracle Corporation +# Copyright (C) 2008-2010 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/samples/php/clienttest.php b/src/VBox/Main/webservice/samples/php/clienttest.php index 648662c4..3b6d8051 100644 --- a/src/VBox/Main/webservice/samples/php/clienttest.php +++ b/src/VBox/Main/webservice/samples/php/clienttest.php @@ -57,7 +57,7 @@ foreach ($machines as $machine) { $console = $session->console; $display = $console->display; - list($screenWidth, $screenHeight, $screenBpp) = $display->getScreenResolution(0 /* First screen */); + list($screenWidth, $screenHeight, $screenBpp, $screenX, $screenY) = $display->getScreenResolution(0 /* First screen */); $imageraw = $display->takeScreenShotToArray(0 /* First screen */, $screenWidth, $screenHeight); echo "Screenshot size: " . sizeof($imageraw) . "\n"; diff --git a/src/VBox/Main/webservice/samples/python/Makefile b/src/VBox/Main/webservice/samples/python/Makefile index 7aa5cb3b..5e8a15bb 100644 --- a/src/VBox/Main/webservice/samples/python/Makefile +++ b/src/VBox/Main/webservice/samples/python/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2008 Oracle Corporation +# Copyright (C) 2008-2010 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/samples/python/Makefile.glue b/src/VBox/Main/webservice/samples/python/Makefile.glue index 8465ca7b..102d5fb4 100644 --- a/src/VBox/Main/webservice/samples/python/Makefile.glue +++ b/src/VBox/Main/webservice/samples/python/Makefile.glue @@ -1,5 +1,5 @@ # -# Copyright (C) 2008 Oracle Corporation +# Copyright (C) 2008-2010 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/samples/python/clienttest.py b/src/VBox/Main/webservice/samples/python/clienttest.py index 50e5d103..bcb2b815 100755 --- a/src/VBox/Main/webservice/samples/python/clienttest.py +++ b/src/VBox/Main/webservice/samples/python/clienttest.py @@ -37,6 +37,7 @@ def enumToString(constants, enum, elem): def main(argv): from vboxapi import VirtualBoxManager + # This is a VirtualBox COM/XPCOM API client, no data needed. wrapper = VirtualBoxManager(None, None) # Get the VirtualBox manager @@ -50,12 +51,27 @@ def main(argv): vboxConstants = wrapper.constants # Enumerate all defined machines - for mach in vbox.machines: + for mach in wrapper.getArray(vbox, 'machines'): try: - - # Print some basic information - print "Machine name: %s [%s]" %(mach.name,mach.id) + # Be prepared for failures - the VM can be inaccessible + vmname = '' + try: + vmname = mach.name + except Exception, e: + None + vmid = ''; + try: + vmid = mach.id + except Exception, e: + None + + # Print some basic VM information even if there were errors + print "Machine name: %s [%s]" %(vmname,vmid) + if vmname == '' or vmid == '': + continue + + # Print some basic VM information print " State: %s" %(enumToString(vboxConstants, "MachineState", mach.state)) print " Session state: %s" %(enumToString(vboxConstants, "SessionState", mach.sessionState)) @@ -82,10 +98,10 @@ def main(argv): # Get the VM's display object display = console.display - # Get the VM's current display resolution + bit depth + # Get the VM's current display resolution + bit depth + position screenNum = 0 # From first screen - (screenX, screenY, screenBPP) = display.getScreenResolution(screenNum) - print " Display (%d): %dx%d, %d BPP" %(screenNum, screenX, screenY, screenBPP) + (screenW, screenH, screenBPP, screenX, screenY) = display.getScreenResolution(screenNum) + print " Display (%d): %dx%d, %d BPP at %d,%d" %(screenNum, screenW, screenH, screenBPP, screenX, screenY) # We're done -- don't forget to unlock the machine! session.unlockMachine() diff --git a/src/VBox/Main/webservice/split-soapC.cpp b/src/VBox/Main/webservice/split-soapC.cpp index 10f5ee1b..d491235b 100644 --- a/src/VBox/Main/webservice/split-soapC.cpp +++ b/src/VBox/Main/webservice/split-soapC.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Main/webservice/vboxweb.cpp b/src/VBox/Main/webservice/vboxweb.cpp index 33394f21..5debb965 100644 --- a/src/VBox/Main/webservice/vboxweb.cpp +++ b/src/VBox/Main/webservice/vboxweb.cpp @@ -5,7 +5,7 @@ * (plus static gSOAP server code) to implement the actual webservice * server, to which clients can connect. * - * Copyright (C) 2007-2012 Oracle Corporation + * Copyright (C) 2007-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -25,8 +25,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -72,8 +72,8 @@ RT_C_DECLS_BEGIN // declarations for the generated WSDL text -extern DECLIMPORT(const unsigned char) g_abVBoxWebWSDL[]; -extern DECLIMPORT(const unsigned) g_cbVBoxWebWSDL; +extern const unsigned char g_abVBoxWebWSDL[]; +extern const unsigned g_cbVBoxWebWSDL; RT_C_DECLS_END @@ -450,9 +450,9 @@ public: * first call or when all existing threads are busy. * @param s Socket from soap_accept() which has work to do. */ - uint32_t add(int s) + size_t add(SOAP_SOCKET s) { - uint32_t cItems; + size_t cItems; util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS); // if no threads have yet been created, or if all threads are busy, @@ -492,7 +492,7 @@ public: * @param cThreads out: total no. of SOAP threads running * @return */ - int get(size_t &cIdleThreads, size_t &cThreads) + SOAP_SOCKET get(size_t &cIdleThreads, size_t &cThreads) { while (1) { @@ -502,7 +502,7 @@ public: util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS); if (m_llSocketsQ.size()) { - int socket = m_llSocketsQ.front(); + SOAP_SOCKET socket = m_llSocketsQ.front(); m_llSocketsQ.pop_front(); cIdleThreads = --m_cIdleThreads; cThreads = m_llAllThreads.size(); @@ -542,7 +542,7 @@ public: // A std::list abused as a queue; this contains the actual jobs to do, // each int being a socket from soap_accept() - std::list m_llSocketsQ; + std::list m_llSocketsQ; }; /** @@ -731,7 +731,7 @@ struct CRYPTO_dynlock_value static unsigned long CRYPTO_id_function() { - return RTThreadNativeSelf(); + return (unsigned long)RTThreadNativeSelf(); } static void CRYPTO_locking_function(int mode, int n, const char * /*file*/, int /*line*/) @@ -855,7 +855,7 @@ void doQueuesLoop() soap.bind_flags |= SO_REUSEADDR; // avoid EADDRINUSE on bind() - int m, s; // master and slave sockets + SOAP_SOCKET m, s; // master and slave sockets m = soap_bind(&soap, g_pcszBindToHost ? g_pcszBindToHost : "localhost", // safe default host g_uBindToPort, // port @@ -1231,7 +1231,7 @@ int main(int argc, char *argv[]) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot start watchdog thread: %Rrc", rc); } - com::EventQueue *pQ = com::EventQueue::getMainEventQueue(); + com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue(); for (;;) { // we have to process main event queue @@ -1436,60 +1436,85 @@ std::string Base64EncodeByteArray(ComSafeArrayIn(BYTE, aData)) return aStr.c_str(); } -#define DECODE_STR_MAX 0x100000 -void Base64DecodeByteArray(struct soap *soap, std::string& aStr, ComSafeArrayOut(BYTE, aData)) + +#define DECODE_STR_MAX _1M +void Base64DecodeByteArray(struct soap *soap, const std::string& aStr, ComSafeArrayOut(BYTE, aData), const WSDLT_ID &idThis, const char *pszMethodName, IUnknown *pObj, const com::Guid &iid) { const char* pszStr = aStr.c_str(); ssize_t cbOut = RTBase64DecodedSize(pszStr, NULL); - if(cbOut > DECODE_STR_MAX) + if (cbOut > DECODE_STR_MAX) { WebLog("Decode string too long.\n"); - RaiseSoapRuntimeFault(soap, VERR_BUFFER_OVERFLOW, (ComPtr)NULL); + RaiseSoapRuntimeFault(soap, idThis, pszMethodName, E_INVALIDARG, pObj, iid); } com::SafeArray result(cbOut); int rc = RTBase64Decode(pszStr, result.raw(), cbOut, NULL, NULL); if (FAILED(rc)) { - WebLog("String Decoding Failed. ERROR: 0x%lX\n", rc); - RaiseSoapRuntimeFault(soap, rc, (ComPtr)NULL); + WebLog("String Decoding Failed. Error code: %Rrc\n", rc); + RaiseSoapRuntimeFault(soap, idThis, pszMethodName, E_INVALIDARG, pObj, iid); } result.detachTo(ComSafeArrayOutArg(aData)); } /** - * Raises a SOAP runtime fault. Implementation for the RaiseSoapRuntimeFault template - * function in vboxweb.h. + * Raises a SOAP runtime fault. * + * @param soap + * @param idThis + * @param pcszMethodName + * @param apirc * @param pObj + * @param iid */ -void RaiseSoapRuntimeFault2(struct soap *soap, - HRESULT apirc, - IUnknown *pObj, - const com::Guid &iid) +void RaiseSoapRuntimeFault(struct soap *soap, + const WSDLT_ID &idThis, + const char *pcszMethodName, + HRESULT apirc, + IUnknown *pObj, + const com::Guid &iid) { com::ErrorInfo info(pObj, iid.ref()); WEBDEBUG((" error, raising SOAP exception\n")); - WebLog("API return code: 0x%08X (%Rhrc)\n", apirc, apirc); - WebLog("COM error info result code: 0x%lX\n", info.getResultCode()); - WebLog("COM error info text: %ls\n", info.getText().raw()); + WebLog("API method name: %s\n", pcszMethodName); + WebLog("API return code: %#10lx (%Rhrc)\n", apirc, apirc); + if (info.isFullAvailable() || info.isBasicAvailable()) + { + const com::ErrorInfo *pInfo = &info; + do + { + WebLog("COM error info result code: %#10lx (%Rhrc)\n", pInfo->getResultCode(), pInfo->getResultCode()); + WebLog("COM error info text: %ls\n", pInfo->getText().raw()); - // allocated our own soap fault struct - _vbox__RuntimeFault *ex = soap_new__vbox__RuntimeFault(soap, 1); - // some old vbox methods return errors without setting an error in the error info, - // so use the error info code if it's set and the HRESULT from the method otherwise - if (S_OK == (ex->resultCode = info.getResultCode())) - ex->resultCode = apirc; - ex->text = ConvertComString(info.getText()); - ex->component = ConvertComString(info.getComponent()); - ex->interfaceID = ConvertComString(info.getInterfaceID()); + pInfo = pInfo->getNext(); + } + while (pInfo); + } // compose descriptive message - com::Utf8StrFmt str("VirtualBox error: %s (0x%lX)", ex->text.c_str(), ex->resultCode); + com::Utf8Str str = com::Utf8StrFmt("VirtualBox error: rc=%#lx", apirc); + if (info.isFullAvailable() || info.isBasicAvailable()) + { + const com::ErrorInfo *pInfo = &info; + do + { + str += com::Utf8StrFmt(" %ls (%#lx)", pInfo->getText().raw(), pInfo->getResultCode()); + pInfo = pInfo->getNext(); + } + while (pInfo); + } + + // allocate our own soap fault struct + _vbox__RuntimeFault *ex = soap_new__vbox__RuntimeFault(soap, 1); + ComPtr pVirtualBoxErrorInfo; + info.getVirtualBoxErrorInfo(pVirtualBoxErrorInfo); + ex->resultCode = apirc; + ex->returnval = createOrFindRefFromComPtr(idThis, "IVirtualBoxErrorInfo", pVirtualBoxErrorInfo); RaiseSoapFault(soap, str.c_str(), @@ -1680,7 +1705,11 @@ int WebServiceSession::authenticate(const char *pcszUsername, RTLDRMOD hlibAuth = 0; do { - rc = RTLdrLoad(filename.c_str(), &hlibAuth); + if (RTPathHavePath(filename.c_str())) + rc = RTLdrLoad(filename.c_str(), &hlibAuth); + else + rc = RTLdrLoadAppPriv(filename.c_str(), &hlibAuth); + if (RT_FAILURE(rc)) { WEBDEBUG(("%s() Failed to load external authentication library. Error code: %Rrc\n", __FUNCTION__, rc)); @@ -1765,7 +1794,7 @@ int WebServiceSession::authenticate(const char *pcszUsername, if (g_fVerbose) { ISession *p = session; - WEBDEBUG((" * %s: created session object with comptr 0x%lX, MOR = %s\n", __FUNCTION__, p, _pISession->getWSDLID().c_str())); + WEBDEBUG((" * %s: created session object with comptr %#p, MOR = %s\n", __FUNCTION__, p, _pISession->getWSDLID().c_str())); } } while (0); } @@ -1793,12 +1822,12 @@ ManagedObjectRef* WebServiceSession::findRefFromPtr(const IUnknown *pObject) Assert(g_pSessionsLockHandle->isWriteLockOnCurrentThread()); uintptr_t ulp = (uintptr_t)pObject; - // WEBDEBUG((" %s: looking up 0x%lX\n", __FUNCTION__, ulp)); + // WEBDEBUG((" %s: looking up %#lx\n", __FUNCTION__, ulp)); ManagedObjectsMapByPtr::iterator it = _pp->_mapManagedObjectsByPtr.find(ulp); if (it != _pp->_mapManagedObjectsByPtr.end()) { ManagedObjectRef *pRef = it->second; - WEBDEBUG((" %s: found existing ref %s (%s) for COM obj 0x%lX\n", __FUNCTION__, pRef->getWSDLID().c_str(), pRef->getInterfaceName(), ulp)); + WEBDEBUG((" %s: found existing ref %s (%s) for COM obj %#lx\n", __FUNCTION__, pRef->getWSDLID().c_str(), pRef->getInterfaceName(), ulp)); return pRef; } @@ -1933,7 +1962,7 @@ ManagedObjectRef::ManagedObjectRef(WebServiceSession &session, session.touch(); - WEBDEBUG((" * %s: MOR created for %s*=0x%lX (IUnknown*=0x%lX; COM refcount now %RI32/%RI32), new ID is %llX; now %lld objects total\n", + WEBDEBUG((" * %s: MOR created for %s*=%#p (IUnknown*=%#p; COM refcount now %RI32/%RI32), new ID is %llX; now %lld objects total\n", __FUNCTION__, pcszInterface, pobjInterface, @@ -2082,7 +2111,7 @@ int __vbox__IManagedObjectRef_USCOREgetInterfaceName( } while (0); - WEBDEBUG(("-- leaving %s, rc: 0x%lX\n", __FUNCTION__, rc)); + WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc)); if (FAILED(rc)) return SOAP_FAULT; return SOAP_OK; @@ -2126,7 +2155,7 @@ int __vbox__IManagedObjectRef_USCORErelease( delete pRef; } while (0); - WEBDEBUG(("-- leaving %s, rc: 0x%lX\n", __FUNCTION__, rc)); + WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc)); if (FAILED(rc)) return SOAP_FAULT; return SOAP_OK; @@ -2214,7 +2243,7 @@ int __vbox__IWebsessionManager_USCORElogon( rc = E_FAIL; } while (0); - WEBDEBUG(("-- leaving %s, rc: 0x%lX\n", __FUNCTION__, rc)); + WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc)); if (FAILED(rc)) return SOAP_FAULT; return SOAP_OK; @@ -2243,7 +2272,7 @@ int __vbox__IWebsessionManager_USCOREgetSessionObject( } while (0); - WEBDEBUG(("-- leaving %s, rc: 0x%lX\n", __FUNCTION__, rc)); + WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc)); if (FAILED(rc)) return SOAP_FAULT; return SOAP_OK; @@ -2280,7 +2309,7 @@ int __vbox__IWebsessionManager_USCORElogoff( } } while (0); - WEBDEBUG(("-- leaving %s, rc: 0x%lX\n", __FUNCTION__, rc)); + WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc)); if (FAILED(rc)) return SOAP_FAULT; return SOAP_OK; diff --git a/src/VBox/Main/webservice/vboxweb.h b/src/VBox/Main/webservice/vboxweb.h index 0309c393..7cc2f55a 100644 --- a/src/VBox/Main/webservice/vboxweb.h +++ b/src/VBox/Main/webservice/vboxweb.h @@ -2,7 +2,7 @@ * vboxweb.h: * header file for "real" web server code. * - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -71,20 +71,7 @@ extern const WSDLT_ID g_EmptyWSDLID; void RaiseSoapInvalidObjectFault(struct soap *soap, WSDLT_ID obj); -void RaiseSoapRuntimeFault2(struct soap *soap, HRESULT apirc, IUnknown *pObj, const com::Guid &iid); - -/** - * Template function called everywhere from methodmaps.cpp which calls - * RaiseSoapRuntimeFault2() with the correct COM interface ID. - * @param soap - * @param apirc - * @param pObj - */ -template -void RaiseSoapRuntimeFault(struct soap *soap, HRESULT apirc, const ComPtr &pObj) -{ - RaiseSoapRuntimeFault2(soap, apirc, pObj, COM_IIDOF(T)); -} +void RaiseSoapRuntimeFault(struct soap *soap, const WSDLT_ID &idThis, const char *pcszMethodName, HRESULT apirc, IUnknown *pObj, const com::Guid &iid); /**************************************************************************** * @@ -98,7 +85,7 @@ std::string ConvertComString(const com::Guid &bstr); std::string Base64EncodeByteArray(ComSafeArrayIn(BYTE, aData)); -void Base64DecodeByteArray(struct soap *soap, std::string& aStr, ComSafeArrayOut(BYTE, aData)); +void Base64DecodeByteArray(struct soap *soap, const std::string& aStr, ComSafeArrayOut(BYTE, aData), const WSDLT_ID &idThis, const char *pszMethodName, IUnknown *pObj, const com::Guid &iid); /**************************************************************************** * * managed object reference classes diff --git a/src/VBox/Main/webservice/websrv-cpp.xsl b/src/VBox/Main/webservice/websrv-cpp.xsl index 1700e5af..32372e77 100644 --- a/src/VBox/Main/webservice/websrv-cpp.xsl +++ b/src/VBox/Main/webservice/websrv-cpp.xsl @@ -11,7 +11,7 @@ See webservice/Makefile.kmk for an overview of all the things generated for the webservice. - Copyright (C) 2007-2012 Oracle Corporation + Copyright (C) 2007-2014 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -39,7 +39,7 @@ - + @@ -65,7 +65,6 @@ #include #include #include -#include #include #include @@ -86,7 +85,7 @@ const char *g_pcszDoneCallingComMethod = " done calling COM method\n"; const char *g_pcszConvertComOutputBack = " convert COM output \"%s\" back to caller format\n"; const char *g_pcszDoneConvertingComOutputBack = " done converting COM output \"%s\" back to caller format\n"; const char *g_pcszEntering = "-- entering %s\n"; -const char *g_pcszLeaving = "-- leaving %s, rc: 0x%lX (%d)\n"; +const char *g_pcszLeaving = "-- leaving %s, rc: %#lx (%d)\n"; // generated string constants for all interface names const char *g_pcszIUnknown = "IUnknown"; @@ -273,17 +272,19 @@ const char *g_pcszIUnknown = "IUnknown"; - - - - - - - - - - - + + + + + + + + + + + + + @@ -360,7 +361,7 @@ const char *g_pcszIUnknown = "IUnknown"; - + @@ -533,7 +534,10 @@ const char *g_pcszIUnknown = "IUnknown"; so we can then pass them to the actual COM method call. --> + + + @@ -546,7 +550,7 @@ const char *g_pcszIUnknown = "IUnknown"; - + @@ -596,6 +600,10 @@ const char *g_pcszIUnknown = "IUnknown"; + + + + @@ -778,7 +786,8 @@ const char *g_pcszIUnknown = "IUnknown"; emits the actual method call with the arguments. --> - + + @@ -786,14 +795,10 @@ const char *g_pcszIUnknown = "IUnknown"; - - - - - + - + @@ -856,7 +861,7 @@ const char *g_pcszIUnknown = "IUnknown"; { - + break; @@ -984,7 +989,7 @@ const char *g_pcszIUnknown = "IUnknown"; - + @@ -1067,6 +1072,7 @@ const char *g_pcszIUnknown = "IUnknown"; + @@ -1102,13 +1108,17 @@ const char *g_pcszIUnknown = "IUnknown"; + + + + @@ -1272,7 +1282,10 @@ const char *g_pcszIUnknown = "IUnknown"; - + + + + @@ -1321,6 +1334,9 @@ const char *g_pcszIUnknown = "IUnknown"; or (param[@mod='ptr'])" > + + + @@ -1377,7 +1393,14 @@ const char *g_pcszIUnknown = "IUnknown"; + + + + + + + @@ -1404,6 +1427,7 @@ const char *g_pcszIUnknown = "IUnknown"; + diff --git a/src/VBox/Main/webservice/websrv-nsmap.xsl b/src/VBox/Main/webservice/websrv-nsmap.xsl index d9524ea0..05b8e168 100644 --- a/src/VBox/Main/webservice/websrv-nsmap.xsl +++ b/src/VBox/Main/webservice/websrv-nsmap.xsl @@ -9,7 +9,7 @@ See webservice/Makefile.kmk for an overview of all the things generated for the webservice. - Copyright (C) 2006-2010 Oracle Corporation + Copyright (C) 2006-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -35,7 +35,7 @@ - + @@ -200,6 +207,7 @@ + @@ -207,23 +215,25 @@ + } - + /** -* Generated VBoxWebService Managed Object Collection -*/ -class Collection extends VBox_ManagedObjectCollection { - protected $_interfaceName = ""; + * Generated VBoxWebService Managed Object Collection + */ +class Collection extends VBox_ManagedObjectCollection +{ + protected $_interfaceName = ""; } @@ -231,21 +241,20 @@ class Collection extends VBox_ManagedObjectColle /** -* Generated VBoxWebService Struct -*/ -class extends VBox_Struct { - - protected $; - - public function __construct($connection, $values) { - $this->connection = $connection; - - $this-> = $values->; - - } + * Generated VBoxWebService Struct + */ +class extends VBox_Struct +{ + protected $; + + public function __construct($connection, $values) + { + $this->connection = $connection; + $this-> = $values->; + } - - public function () { + public function () + { return @@ -253,36 +262,33 @@ class extends VBox_Struct { ; } - - -} +} /** -* Generated VBoxWebService Struct Collection -*/ -class Collection extends VBox_StructCollection { - protected $_interfaceName = ""; + * Generated VBoxWebService Struct Collection + */ +class Collection extends VBox_StructCollection +{ + protected $_interfaceName = ""; } - - $request = new stdClass(); - - $request->_this = $this->handle; - - - $request-> = $arg_; - - $response = $this->connection->__soapCall('_', array((array)$request)); - - return - array( - + + $request = new stdClass(); + + $request->_this = $this->handle; + + $request-> = $arg_; + + $response = $this->connection->__soapCall('_', array((array)$request)); + return + array( + @@ -310,26 +316,27 @@ class Collection extends VBox_StructCollection { - - public function ( - - - , - - - ) { - - } + + public function ( + + + , + + + ) { + + } /** -* Generated VBoxWebService ENUM -*/ -class extends VBox_Enum { - public $NameMap = array( => '', ); - public $ValueMap = array('' => , ); + * Generated VBoxWebService ENUM + */ +class extends VBox_Enum +{ + public $NameMap = array( => '', ); + public $ValueMap = array('' => , ); } @@ -337,22 +344,23 @@ class extends VBox_Enum { /** -* Generated VBoxWebService Enum Collection -*/ -class Collection extends VBox_EnumCollection { - protected $_interfaceName = ""; + * Generated VBoxWebService Enum Collection + */ +class Collection extends VBox_EnumCollection +{ + protected $_interfaceName = ""; } - const = ; + const = ; <?php /* - * Copyright (C) 2008-2010 Oracle Corporation + * Copyright (C) 2008-2014 Oracle Corporation * * This file is part of a free software library; you can redistribute * it and/or modify it under the terms of the GNU Lesser General @@ -407,44 +415,50 @@ class VBox_ManagedObject throw new Exception("Attribute does not exist"); } - public function getHandle() - { - return $this->handle; - } - - public function cast($class) - { - if (is_subclass_of($class, 'VBox_ManagedObject')) - { - return new $class($this->connection, $this->handle); - } - throw new Exception('Cannot cast VBox_ManagedObject to non-child class VBox_ManagedObject'); - } - - public function releaseRemote() - { - try - { - $request = new stdClass(); - $request->_this = $this->handle; - $this->connection->__soapCall('IManagedObjectRef_release', array((array)$request)); - } catch (Exception $ex) {} - } + public function getHandle() + { + return $this->handle; + } + + public function cast($class) + { + if (is_subclass_of($class, 'VBox_ManagedObject')) + { + return new $class($this->connection, $this->handle); + } + throw new Exception('Cannot cast VBox_ManagedObject to non-child class VBox_ManagedObject'); + } + + public function releaseRemote() + { + try + { + $request = new stdClass(); + $request->_this = $this->handle; + $this->connection->__soapCall('IManagedObjectRef_release', array((array)$request)); + } + catch (Exception $ex) + { + } + } } -abstract class VBox_Collection implements ArrayAccess, Iterator, Countable { +abstract class VBox_Collection implements ArrayAccess, Iterator, Countable +{ protected $_connection; protected $_values; protected $_objects; protected $_interfaceName; - public function __construct($soap, array $values = array()) { + public function __construct($soap, array $values = array()) + { $this->_connection = $soap; $this->_values = $values; $this->_soapToObject(); } - protected function _soapToObject() { + protected function _soapToObject() + { $this->_objects = array(); foreach($this->_values as $value) { @@ -453,7 +467,8 @@ abstract class VBox_Collection implements ArrayAccess, Iterator, Countable { } /** ArrayAccess Functions **/ - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value) + { if ($value instanceof $this->_interfaceName) { if ($offset) @@ -471,60 +486,72 @@ abstract class VBox_Collection implements ArrayAccess, Iterator, Countable { } } - public function offsetExists($offset) { + public function offsetExists($offset) + { return isset($this->_objects[$offset]); } - public function offsetUnset($offset) { + public function offsetUnset($offset) + { unset($this->_objects[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset) + { return isset($this->_objects[$offset]) ? $this->_objects[$offset] : null; } /** Iterator Functions **/ - public function rewind() { + public function rewind() + { reset($this->_objects); } - public function current() { + public function current() + { return current($this->_objects); } - public function key() { + public function key() + { return key($this->_objects); } - public function next() { + public function next() + { return next($this->_objects); } - public function valid() { + public function valid() + { return ($this->current() !== false); } /** Countable Functions **/ - public function count() { + public function count() + { return count($this->_objects); } } -class VBox_ManagedObjectCollection extends VBox_Collection { +class VBox_ManagedObjectCollection extends VBox_Collection +{ protected $_interfaceName = 'VBox_ManagedObject'; // Result is undefined if this is called AFTER any call to VBox_Collection::offsetSet or VBox_Collection::offsetUnset - public function setInterfaceName($interface) { - if (!is_subclass_of($interface, 'VBox_ManagedObject')) - { - throw new Exception('Cannot set collection interface to non-child class of VBox_ManagedObject'); - } - $this->_interfaceName = $interface; - $this->_soapToObject(); + public function setInterfaceName($interface) + { + if (!is_subclass_of($interface, 'VBox_ManagedObject')) + { + throw new Exception('Cannot set collection interface to non-child class of VBox_ManagedObject'); + } + $this->_interfaceName = $interface; + $this->_soapToObject(); } } -abstract class VBox_Struct { +abstract class VBox_Struct +{ protected $connection; public function __get($attr) @@ -537,7 +564,8 @@ abstract class VBox_Struct { } } -abstract class VBox_StructCollection extends VBox_Collection { +abstract class VBox_StructCollection extends VBox_Collection +{ public function __construct($soap, array $values = array()) { @@ -549,33 +577,36 @@ abstract class VBox_StructCollection extends VBox_Collection { } } -abstract class VBox_Enum { - protected $_handle; - - public function __construct($connection, $handle) - { - if (is_string($handle)) - $this->_handle = $this->ValueMap[$handle]; - else - $this->_handle = $handle; - } - - public function __toString() - { - return (string)$this->NameMap[$this->_handle]; - } +abstract class VBox_Enum +{ + protected $_handle; + + public function __construct($connection, $handle) + { + if (is_string($handle)) + $this->_handle = $this->ValueMap[$handle]; + else + $this->_handle = $handle; + } + + public function __toString() + { + return (string)$this->NameMap[$this->_handle]; + } } -abstract class VBox_EnumCollection extends VBox_Collection { +abstract class VBox_EnumCollection extends VBox_Collection +{ } /** -* VirtualBox COM result codes -*/ -class VirtualBox_COM_result_codes { + * VirtualBox COM result codes + */ +class VirtualBox_COM_result_codes +{ @@ -587,7 +618,7 @@ class VirtualBox_COM_result_codes { - + diff --git a/src/VBox/Main/webservice/websrv-python.xsl b/src/VBox/Main/webservice/websrv-python.xsl index d1dcff79..01984595 100644 --- a/src/VBox/Main/webservice/websrv-python.xsl +++ b/src/VBox/Main/webservice/websrv-python.xsl @@ -9,7 +9,7 @@ VirtualBox.xidl. This Python file represents our web service API. Depends on WSDL file for actual SOAP bindings. - Copyright (C) 2008-2010 Oracle Corporation + Copyright (C) 2008-2014 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -27,7 +27,7 @@ encoding="utf-8" indent="no"/> - + @@ -51,7 +51,6 @@ UnsignedInt Octet IUnknown - IUnknown @@ -148,7 +147,7 @@ class : - + @@ -468,7 +467,7 @@ class : -# Copyright (C) 2008-2011 Oracle Corporation +# Copyright (C) 2008-2014 Oracle Corporation # # This file is part of a free software library; you can redistribute # it and/or modify it under the terms of the GNU Lesser General diff --git a/src/VBox/Main/webservice/websrv-shared.inc.xsl b/src/VBox/Main/webservice/websrv-shared.inc.xsl deleted file mode 100644 index b31eb72c..00000000 --- a/src/VBox/Main/webservice/websrv-shared.inc.xsl +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - _USCORE - - - - - - diff --git a/src/VBox/Main/webservice/websrv-typemap.xsl b/src/VBox/Main/webservice/websrv-typemap.xsl index 97efefa1..714c42b8 100644 --- a/src/VBox/Main/webservice/websrv-typemap.xsl +++ b/src/VBox/Main/webservice/websrv-typemap.xsl @@ -8,7 +8,7 @@ See webservice/Makefile.kmk for an overview of all the things generated for the webservice. - Copyright (C) 2006-2010 Oracle Corporation + Copyright (C) 2006-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -34,7 +34,7 @@ - + diff --git a/src/VBox/Main/webservice/websrv-wsdl.xsl b/src/VBox/Main/webservice/websrv-wsdl.xsl index 88ac6dc7..5508cd1f 100644 --- a/src/VBox/Main/webservice/websrv-wsdl.xsl +++ b/src/VBox/Main/webservice/websrv-wsdl.xsl @@ -9,7 +9,7 @@ See webservice/Makefile.kmk for an overview of all the things generated for the webservice. - Copyright (C) 2006-2010 Oracle Corporation + Copyright (C) 2006-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -93,6 +93,7 @@ targetNamespace="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:vbox="http://www.virtualbox.org/" xmlns:exsl="http://exslt.org/common" @@ -117,7 +118,7 @@ - + @@ -146,7 +147,7 @@ - + @@ -162,7 +163,7 @@ - + @@ -185,9 +186,6 @@ - - - @@ -460,7 +458,7 @@ - + @@ -469,10 +467,10 @@ - + - + - + @@ -495,10 +493,10 @@ - + - + - + - + @@ -566,7 +564,7 @@ - + @@ -577,7 +575,7 @@ - + @@ -589,10 +587,10 @@ vbox: - + - + @@ -604,11 +602,11 @@ vbox: - + - + @@ -620,29 +618,29 @@ vbox: - + - - + + - + - - + + - + - + - + + + + @@ -735,6 +736,9 @@ or (param[@mod='ptr'])" > + + + @@ -742,7 +746,7 @@ - + @@ -751,7 +755,7 @@ - + @@ -776,7 +780,10 @@ - + + + + @@ -810,6 +817,9 @@ or (param[@mod='ptr'])" > + + + @@ -836,7 +846,10 @@ - + + + + @@ -869,6 +882,9 @@ or (param[@mod='ptr'])" > + + + @@ -956,10 +972,9 @@ and emit complexTypes for all method arguments and return values. --> - - http://schemas.xmlsoap.org/wsdl/ @@ -969,7 +984,7 @@ * ****************************************************** - + @@ -1024,40 +1039,6 @@ - - - ****************************************************** - * collections as arrays - ****************************************************** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1086,6 +1067,9 @@ + + + @@ -1135,6 +1119,9 @@ or (param[@mod='ptr'])" > + + + @@ -1182,9 +1169,11 @@ - - - + + + + + @@ -1193,14 +1182,14 @@ - + - - - - - - + + + + + + ****************************************************** @@ -1241,7 +1230,7 @@ ****************************************************** - + @@ -1261,7 +1250,7 @@ - + ****************************************************** @@ -1271,7 +1260,7 @@ ****************************************************** - + @@ -1297,9 +1286,9 @@ - + - + diff --git a/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl b/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl index d40ba83c..bdbce0e6 100644 --- a/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl +++ b/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl @@ -9,7 +9,7 @@ See webservice/Makefile.kmk for an overview of all the things generated for the webservice. - Copyright (C) 2006-2010 Oracle Corporation + Copyright (C) 2006-2013 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -43,7 +43,7 @@ - + @@ -81,7 +81,7 @@ ****************************************************************************/ // forward declarations - class _vbox__InvalidObjectFault; +class _vbox__InvalidObjectFault; class _vbox__RuntimeFault; struct SOAP_ENV__Detail diff --git a/src/VBox/Main/webservice/webtest.cpp b/src/VBox/Main/webservice/webtest.cpp index 89c8064a..78834c50 100644 --- a/src/VBox/Main/webservice/webtest.cpp +++ b/src/VBox/Main/webservice/webtest.cpp @@ -3,7 +3,7 @@ * demo webservice client in C++. This mimics some of the * functionality of VBoxManage for testing purposes. * - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,6 +57,8 @@ static void usage(int exitcode) " - IPerformanceCollector:\n" " - webtest setupmetrics : IPerformanceCollector::setupMetrics()\n" " - webtest querymetricsdata : IPerformanceCollector::QueryMetricsData()\n" + " - IVirtualBoxErrorInfo:\n" + " - webtest errorinfo : various IVirtualBoxErrorInfo getters\n" " - All managed object references:\n" " - webtest getif : report interface of object.\n" " - webtest release : IUnknown::Release().\n"; @@ -75,7 +77,7 @@ int main(int argc, char* argv[]) const char *pcszArgEndpoint = "http://localhost:18083/"; int ap; - for (ap = 1; ap <= argc; ap++) + for (ap = 1; ap < argc; ap++) { if (argv[ap][0] == '-') { @@ -84,7 +86,7 @@ int main(int argc, char* argv[]) else if (!strcmp(argv[ap], "-c")) { ap++; - if (ap > argc) + if (ap >= argc) usage(1); pcszArgEndpoint = argv[ap]; fSSL = !strncmp(pcszArgEndpoint, "https://", 8); @@ -452,6 +454,47 @@ int main(int argc, char* argv[]) } } } + else if (!strcmp(pcszMode, "errorinfo")) + { + if (argc < 2 + ap) + std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n"; + else + { + _vbox__IVirtualBoxErrorInfo_USCOREgetResultCode req; + req._USCOREthis = argv[ap + 1]; + _vbox__IVirtualBoxErrorInfo_USCOREgetResultCodeResponse resp; + if (!(soaprc = soap_call___vbox__IVirtualBoxErrorInfo_USCOREgetResultCode(&soap, + pcszArgEndpoint, + NULL, + &req, + &resp))) + { + std::cout << "ErrorInfo ResultCode: " << std::hex << resp.returnval << "\n"; + + _vbox__IVirtualBoxErrorInfo_USCOREgetText req2; + req2._USCOREthis = argv[ap + 1]; + _vbox__IVirtualBoxErrorInfo_USCOREgetTextResponse resp2; + if (!(soaprc = soap_call___vbox__IVirtualBoxErrorInfo_USCOREgetText(&soap, + pcszArgEndpoint, + NULL, + &req2, + &resp2))) + { + std::cout << "ErrorInfo Text: " << resp2.returnval << "\n"; + + _vbox__IVirtualBoxErrorInfo_USCOREgetNext req3; + req3._USCOREthis = argv[ap + 1]; + _vbox__IVirtualBoxErrorInfo_USCOREgetNextResponse resp3; + if (!(soaprc = soap_call___vbox__IVirtualBoxErrorInfo_USCOREgetNext(&soap, + pcszArgEndpoint, + NULL, + &req3, + &resp3))) + std::cout << "Next ErrorInfo: " << resp3.returnval << "\n"; + } + } + } + } else if (!strcmp(pcszMode, "release")) { if (argc < 2 + ap) @@ -478,22 +521,18 @@ int main(int argc, char* argv[]) && (soap.fault->detail) ) { + // generic fault message whether the fault is known or not + std::cerr << "Generic fault message:\n"; + soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream + if (soap.fault->detail->vbox__InvalidObjectFault) { - std::cout << "Bad object ID: " << soap.fault->detail->vbox__InvalidObjectFault->badObjectID << "\n"; + std::cerr << "Bad object ID: " << soap.fault->detail->vbox__InvalidObjectFault->badObjectID << "\n"; } else if (soap.fault->detail->vbox__RuntimeFault) { - std::cout << "Result code: 0x" << std::hex << soap.fault->detail->vbox__RuntimeFault->resultCode << "\n"; - std::cout << "Text: " << std::hex << soap.fault->detail->vbox__RuntimeFault->text << "\n"; - std::cout << "Component: " << std::hex << soap.fault->detail->vbox__RuntimeFault->component << "\n"; - std::cout << "Interface ID: " << std::hex << soap.fault->detail->vbox__RuntimeFault->interfaceID << "\n"; - } - else - { - // generic fault - std::cerr << "Generic fault message:\n"; - soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream + std::cerr << "Result code: 0x" << std::hex << soap.fault->detail->vbox__RuntimeFault->resultCode << "\n"; + std::cerr << "ErrorInfo: " << soap.fault->detail->vbox__RuntimeFault->returnval << "\n"; } } else diff --git a/src/VBox/Main/xml/SchemaDefs.xsl b/src/VBox/Main/xml/SchemaDefs.xsl index 3d91dea8..ea5ba45b 100644 --- a/src/VBox/Main/xml/SchemaDefs.xsl +++ b/src/VBox/Main/xml/SchemaDefs.xsl @@ -8,7 +8,7 @@ * This template depends on XML Schema structure (type names and constraints) * and should be reviewed on every Schema change. - Copyright (C) 2006-2011 Oracle Corporation + Copyright (C) 2006-2012 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; @@ -168,7 +168,7 @@ namespace SchemaDefs diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp index 8cb1e126..3520c9c7 100644 --- a/src/VBox/Main/xml/Settings.cpp +++ b/src/VBox/Main/xml/Settings.cpp @@ -54,7 +54,7 @@ */ /* - * Copyright (C) 2007-2012 Oracle Corporation + * Copyright (C) 2007-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -327,7 +327,9 @@ ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename) m->sv = SettingsVersion_v1_12; else if (ulMinor == 13) m->sv = SettingsVersion_v1_13; - else if (ulMinor > 13) + else if (ulMinor == 14) + m->sv = SettingsVersion_v1_14; + else if (ulMinor > 14) m->sv = SettingsVersion_Future; } else if (ulMajor > 1) @@ -382,7 +384,9 @@ void ConfigFileBase::parseUUID(Guid &guid, const Utf8Str &strUUID) const { guid = strUUID.c_str(); - if (guid.isEmpty()) + if (guid.isZero()) + throw ConfigFileError(this, NULL, N_("UUID \"%s\" has zero format"), strUUID.c_str()); + else if (!guid.isValid()) throw ConfigFileError(this, NULL, N_("UUID \"%s\" has invalid format"), strUUID.c_str()); } @@ -488,9 +492,8 @@ void ConfigFileBase::readExtraData(const xml::ElementNode &elmExtraData, { // Utf8Str strName, strValue; - if ( ((pelmExtraDataItem->getAttributeValue("name", strName))) - && ((pelmExtraDataItem->getAttributeValue("value", strValue))) - ) + if ( pelmExtraDataItem->getAttributeValue("name", strName) + && pelmExtraDataItem->getAttributeValue("value", strValue) ) map[strName] = strValue; else throw ConfigFileError(this, pelmExtraDataItem, N_("Required ExtraDataItem/@name or @value attribute is missing")); @@ -516,9 +519,8 @@ void ConfigFileBase::readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilte USBDeviceFilter flt; flt.action = USBDeviceFilterAction_Ignore; Utf8Str strAction; - if ( (pelmLevel4Child->getAttributeValue("name", flt.strName)) - && (pelmLevel4Child->getAttributeValue("active", flt.fActive)) - ) + if ( pelmLevel4Child->getAttributeValue("name", flt.strName) + && pelmLevel4Child->getAttributeValue("active", flt.fActive)) { if (!pelmLevel4Child->getAttributeValue("vendorId", flt.strVendorId)) pelmLevel4Child->getAttributeValue("vendorid", flt.strVendorId); // used before 1.3 @@ -571,7 +573,7 @@ void ConfigFileBase::readMedium(MediaType t, // settings::Medium med; Utf8Str strUUID; - if (!(elmMedium.getAttributeValue("uuid", strUUID))) + if (!elmMedium.getAttributeValue("uuid", strUUID)) throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName()); parseUUID(med.uuid, strUUID); @@ -664,14 +666,14 @@ void ConfigFileBase::readMedium(MediaType t, } if (med.strFormat.isEmpty()) // not set with 1.4 format above, or 1.4 Custom format? - if (!(elmMedium.getAttributeValue("format", med.strFormat))) + if (!elmMedium.getAttributeValue("format", med.strFormat)) throw ConfigFileError(this, &elmMedium, N_("Required %s/@format attribute is missing"), elmMedium.getName()); - if (!(elmMedium.getAttributeValue("autoReset", med.fAutoReset))) + if (!elmMedium.getAttributeValue("autoReset", med.fAutoReset)) med.fAutoReset = false; Utf8Str strType; - if ((elmMedium.getAttributeValue("type", strType))) + if (elmMedium.getAttributeValue("type", strType)) { // pre-1.4 used lower case, so make this case-insensitive strType.toUpper(); @@ -696,13 +698,13 @@ void ConfigFileBase::readMedium(MediaType t, if (m->sv < SettingsVersion_v1_4) { // DVD and floppy images before 1.4 had "src" attribute instead of "location" - if (!(elmMedium.getAttributeValue("src", med.strLocation))) + if (!elmMedium.getAttributeValue("src", med.strLocation)) throw ConfigFileError(this, &elmMedium, N_("Required %s/@src attribute is missing"), elmMedium.getName()); fNeedsLocation = false; } - if (!(elmMedium.getAttributeValue("format", med.strFormat))) + if (!elmMedium.getAttributeValue("format", med.strFormat)) { // DVD and floppy images before 1.11 had no format attribute. assign the default. med.strFormat = "RAW"; @@ -716,7 +718,7 @@ void ConfigFileBase::readMedium(MediaType t, if (fNeedsLocation) // current files and 1.4 CustomHardDisk elements must have a location attribute - if (!(elmMedium.getAttributeValue("location", med.strLocation))) + if (!elmMedium.getAttributeValue("location", med.strLocation)) throw ConfigFileError(this, &elmMedium, N_("Required %s/@location attribute is missing"), elmMedium.getName()); elmMedium.getAttributeValue("Description", med.strDescription); // optional @@ -740,9 +742,8 @@ void ConfigFileBase::readMedium(MediaType t, else if (pelmHDChild->nameEquals("Property")) { Utf8Str strPropName, strPropValue; - if ( (pelmHDChild->getAttributeValue("name", strPropName)) - && (pelmHDChild->getAttributeValue("value", strPropValue)) - ) + if ( pelmHDChild->getAttributeValue("name", strPropName) + && pelmHDChild->getAttributeValue("value", strPropValue) ) med.properties[strPropName] = strPropValue; else throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing")); @@ -806,6 +807,47 @@ void ConfigFileBase::readMediaRegistry(const xml::ElementNode &elmMediaRegistry, } } +/** + * This is common version for reading NAT port forward rule in per-_machine's_adapter_ and + * per-network approaches. + * Note: this function doesn't in fill given list from xml::ElementNodesList, because there is conflicting + * declaration in ovmfreader.h. + */ +void ConfigFileBase::readNATForwardRuleList(const xml::ElementNode &elmParent, NATRuleList &llRules) +{ + xml::ElementNodesList plstRules; + elmParent.getChildElements(plstRules, "Forwarding"); + for (xml::ElementNodesList::iterator pf = plstRules.begin(); pf != plstRules.end(); ++pf) + { + NATRule rule; + uint32_t port = 0; + (*pf)->getAttributeValue("name", rule.strName); + (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto); + (*pf)->getAttributeValue("hostip", rule.strHostIP); + (*pf)->getAttributeValue("hostport", port); + rule.u16HostPort = port; + (*pf)->getAttributeValue("guestip", rule.strGuestIP); + (*pf)->getAttributeValue("guestport", port); + rule.u16GuestPort = port; + llRules.push_back(rule); + } +} + +void ConfigFileBase::readNATLoopbacks(const xml::ElementNode &elmParent, NATLoopbackOffsetList &llLoopbacks) +{ + xml::ElementNodesList plstLoopbacks; + elmParent.getChildElements(plstLoopbacks, "Loopback4"); + for (xml::ElementNodesList::iterator lo = plstLoopbacks.begin(); + lo != plstLoopbacks.end(); ++lo) + { + NATHostLoopbackOffset loopback; + (*lo)->getAttributeValue("address", loopback.strLoopbackHostAddress); + (*lo)->getAttributeValue("offset", (uint32_t&)loopback.u32Offset); + llLoopbacks.push_back(loopback); + } +} + + /** * Adds a "version" attribute to the given XML element with the * VirtualBox settings version (e.g. "1.10-linux"). Used by @@ -842,11 +884,15 @@ void ConfigFileBase::setVersionAttribute(xml::ElementNode &elm) pcszVersion = "1.13"; break; + case SettingsVersion_v1_14: + pcszVersion = "1.14"; + break; + case SettingsVersion_Future: // can be set if this code runs on XML files that were created by a future version of VBox; // in that case, downgrade to current version when writing since we can't write future versions... - pcszVersion = "1.13"; - m->sv = SettingsVersion_v1_13; + pcszVersion = "1.14"; + m->sv = SettingsVersion_v1_14; break; default: @@ -1131,6 +1177,45 @@ void ConfigFileBase::buildMediaRegistry(xml::ElementNode &elmParent, } } +/** + * Serialize NAT port-forwarding rules in parent container. + * Note: it's responsibility of caller to create parent of the list tag. + * because this method used for serializing per-_mahine's_adapter_ and per-network approaches. + */ +void ConfigFileBase::buildNATForwardRuleList(xml::ElementNode &elmParent, const NATRuleList &natRuleList) +{ + for (NATRuleList::const_iterator r = natRuleList.begin(); + r != natRuleList.end(); ++r) + { + xml::ElementNode *pelmPF; + pelmPF = elmParent.createChild("Forwarding"); + if ((*r).strName.length()) + pelmPF->setAttribute("name", (*r).strName); + pelmPF->setAttribute("proto", (*r).proto); + if ((*r).strHostIP.length()) + pelmPF->setAttribute("hostip", (*r).strHostIP); + if ((*r).u16HostPort) + pelmPF->setAttribute("hostport", (*r).u16HostPort); + if ((*r).strGuestIP.length()) + pelmPF->setAttribute("guestip", (*r).strGuestIP); + if ((*r).u16GuestPort) + pelmPF->setAttribute("guestport", (*r).u16GuestPort); + } +} + + +void ConfigFileBase::buildNATLoopbacks(xml::ElementNode &elmParent, const NATLoopbackOffsetList &natLoopbackOffsetList) +{ + for (NATLoopbackOffsetList::const_iterator lo = natLoopbackOffsetList.begin(); + lo != natLoopbackOffsetList.end(); ++lo) + { + xml::ElementNode *pelmLo; + pelmLo = elmParent.createChild("Loopback4"); + pelmLo->setAttribute("address", (*lo).strLoopbackHostAddress); + pelmLo->setAttribute("offset", (*lo).u32Offset); + } +} + /** * Cleans up memory allocated by the internal XML parser. To be called by * descendant classes when they're done analyzing the DOM tree to discard it. @@ -1213,9 +1298,8 @@ void MainConfigFile::readMachineRegistry(const xml::ElementNode &elmMachineRegis { MachineRegistryEntry mre; Utf8Str strUUID; - if ( ((pelmChild1->getAttributeValue("uuid", strUUID))) - && ((pelmChild1->getAttributeValue("src", mre.strSettingsFile))) - ) + if ( pelmChild1->getAttributeValue("uuid", strUUID) + && pelmChild1->getAttributeValue("src", mre.strSettingsFile) ) { parseUUID(mre.uuid, strUUID); llMachines.push_back(mre); @@ -1239,20 +1323,104 @@ void MainConfigFile::readDHCPServers(const xml::ElementNode &elmDHCPServers) if (pelmServer->nameEquals("DHCPServer")) { DHCPServer srv; - if ( (pelmServer->getAttributeValue("networkName", srv.strNetworkName)) - && (pelmServer->getAttributeValue("IPAddress", srv.strIPAddress)) - && (pelmServer->getAttributeValue("networkMask", srv.strIPNetworkMask)) - && (pelmServer->getAttributeValue("lowerIP", srv.strIPLower)) - && (pelmServer->getAttributeValue("upperIP", srv.strIPUpper)) - && (pelmServer->getAttributeValue("enabled", srv.fEnabled)) - ) + if ( pelmServer->getAttributeValue("networkName", srv.strNetworkName) + && pelmServer->getAttributeValue("IPAddress", srv.strIPAddress) + && pelmServer->getAttributeValue("networkMask", srv.GlobalDhcpOptions[DhcpOpt_SubnetMask]) + && pelmServer->getAttributeValue("lowerIP", srv.strIPLower) + && pelmServer->getAttributeValue("upperIP", srv.strIPUpper) + && pelmServer->getAttributeValue("enabled", srv.fEnabled) ) + { + xml::NodesLoop nlOptions(*pelmServer, "Options"); + const xml::ElementNode *options; + /* XXX: Options are in 1:1 relation to DHCPServer */ + + while ((options = nlOptions.forAllNodes())) + { + readDhcpOptions(srv.GlobalDhcpOptions, *options); + } /* end of forall("Options") */ + xml::NodesLoop nlConfig(*pelmServer, "Config"); + const xml::ElementNode *cfg; + while ((cfg = nlConfig.forAllNodes())) + { + com::Utf8Str strVmName; + uint32_t u32Slot; + cfg->getAttributeValue("vm-name", strVmName); + cfg->getAttributeValue("slot", u32Slot); + readDhcpOptions(srv.VmSlot2OptionsM[VmNameSlotKey(strVmName, u32Slot)], *cfg); + } llDhcpServers.push_back(srv); + } else throw ConfigFileError(this, pelmServer, N_("Required DHCPServer/@networkName, @IPAddress, @networkMask, @lowerIP, @upperIP or @enabled attribute is missing")); } } } +void MainConfigFile::readDhcpOptions(DhcpOptionMap& map, + const xml::ElementNode& options) +{ + xml::NodesLoop nl2(options, "Option"); + const xml::ElementNode *opt; + while ((opt = nl2.forAllNodes())) + { + DhcpOpt_T OptName; + com::Utf8Str OptValue; + opt->getAttributeValue("name", (uint32_t&)OptName); + + if (OptName == DhcpOpt_SubnetMask) + continue; + + opt->getAttributeValue("value", OptValue); + + map.insert(std::map::value_type(OptName, OptValue)); + } /* end of forall("Option") */ + +} + +/** + * Reads in the chunk. + * @param elmNATNetworks + */ +void MainConfigFile::readNATNetworks(const xml::ElementNode &elmNATNetworks) +{ + xml::NodesLoop nl1(elmNATNetworks); + const xml::ElementNode *pelmNet; + while ((pelmNet = nl1.forAllNodes())) + { + if (pelmNet->nameEquals("NATNetwork")) + { + NATNetwork net; + if ( pelmNet->getAttributeValue("networkName", net.strNetworkName) + && pelmNet->getAttributeValue("enabled", net.fEnabled) + && pelmNet->getAttributeValue("network", net.strNetwork) + && pelmNet->getAttributeValue("ipv6", net.fIPv6) + && pelmNet->getAttributeValue("ipv6prefix", net.strIPv6Prefix) + && pelmNet->getAttributeValue("advertiseDefaultIPv6Route", net.fAdvertiseDefaultIPv6Route) + && pelmNet->getAttributeValue("needDhcp", net.fNeedDhcpServer) ) + { + pelmNet->getAttributeValue("loopback6", net.u32HostLoopback6Offset); + const xml::ElementNode *pelmMappings; + if ((pelmMappings = pelmNet->findChildElement("Mappings"))) + readNATLoopbacks(*pelmMappings, net.llHostLoopbackOffsetList); + + const xml::ElementNode *pelmPortForwardRules4; + if ((pelmPortForwardRules4 = pelmNet->findChildElement("PortForwarding4"))) + readNATForwardRuleList(*pelmPortForwardRules4, + net.llPortForwardRules4); + + const xml::ElementNode *pelmPortForwardRules6; + if ((pelmPortForwardRules6 = pelmNet->findChildElement("PortForwarding6"))) + readNATForwardRuleList(*pelmPortForwardRules6, + net.llPortForwardRules6); + + llNATNetworks.push_back(net); + } + else + throw ConfigFileError(this, pelmNet, N_("Required NATNetwork/@networkName, @gateway, @network,@advertiseDefaultIpv6Route , @needDhcp or @enabled attribute is missing")); + } + } +} + /** * Constructor. * @@ -1286,6 +1454,7 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) if (pelmGlobalChild->nameEquals("SystemProperties")) { pelmGlobalChild->getAttributeValue("defaultMachineFolder", systemProperties.strDefaultMachineFolder); + pelmGlobalChild->getAttributeValue("LoggingLevel", systemProperties.strLoggingLevel); pelmGlobalChild->getAttributeValue("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat); if (!pelmGlobalChild->getAttributeValue("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary)) // pre-1.11 used @remoteDisplayAuthLibrary instead @@ -1294,6 +1463,8 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) pelmGlobalChild->getAttributeValue("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack); pelmGlobalChild->getAttributeValue("LogHistoryCount", systemProperties.ulLogHistoryCount); pelmGlobalChild->getAttributeValue("autostartDatabasePath", systemProperties.strAutostartDatabasePath); + pelmGlobalChild->getAttributeValue("defaultFrontend", systemProperties.strDefaultFrontend); + pelmGlobalChild->getAttributeValue("exclusiveHwVirt", systemProperties.fExclusiveHwVirt); } else if (pelmGlobalChild->nameEquals("ExtraData")) readExtraData(*pelmGlobalChild, mapExtraDataItems); @@ -1313,6 +1484,8 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) { if (pelmLevel4Child->nameEquals("DHCPServers")) readDHCPServers(*pelmLevel4Child); + if (pelmLevel4Child->nameEquals("NATNetworks")) + readNATNetworks(*pelmLevel4Child); } } else if (pelmGlobalChild->nameEquals("USBDeviceFilters")) @@ -1341,7 +1514,7 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) "HostInterfaceNetworking-vboxnet0"; #endif srv.strIPAddress = "192.168.56.100"; - srv.strIPNetworkMask = "255.255.255.0"; + srv.GlobalDhcpOptions[DhcpOpt_SubnetMask] = "255.255.255.0"; srv.strIPLower = "192.168.56.101"; srv.strIPUpper = "192.168.56.254"; srv.fEnabled = true; @@ -1349,12 +1522,25 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) } } +void MainConfigFile::bumpSettingsVersionIfNeeded() +{ + if (m->sv < SettingsVersion_v1_14) + { + // VirtualBox 4.3 adds NAT networks. + if ( !llNATNetworks.empty()) + m->sv = SettingsVersion_v1_14; + } +} + + /** * Called from the IVirtualBox interface to write out VirtualBox.xml. This * builds an XML DOM tree and writes it out to disk. */ void MainConfigFile::write(const com::Utf8Str strFilename) { + bumpSettingsVersionIfNeeded(); + m->strFilename = strFilename; createStubDocument(); @@ -1384,17 +1570,110 @@ void MainConfigFile::write(const com::Utf8Str strFilename) { const DHCPServer &d = *it; xml::ElementNode *pelmThis = pelmDHCPServers->createChild("DHCPServer"); + DhcpOptConstIterator itOpt; + itOpt = d.GlobalDhcpOptions.find(DhcpOpt_SubnetMask); + pelmThis->setAttribute("networkName", d.strNetworkName); pelmThis->setAttribute("IPAddress", d.strIPAddress); - pelmThis->setAttribute("networkMask", d.strIPNetworkMask); + if (itOpt != d.GlobalDhcpOptions.end()) + pelmThis->setAttribute("networkMask", itOpt->second); pelmThis->setAttribute("lowerIP", d.strIPLower); pelmThis->setAttribute("upperIP", d.strIPUpper); pelmThis->setAttribute("enabled", (d.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here + /* We assume that if there're only 1 element it means that */ + int cOpt = d.GlobalDhcpOptions.size(); + /* We don't want duplicate validation check of networkMask here*/ + if ( ( itOpt == d.GlobalDhcpOptions.end() + && cOpt > 0) + || cOpt > 1) + { + xml::ElementNode *pelmOptions = pelmThis->createChild("Options"); + for (itOpt = d.GlobalDhcpOptions.begin(); + itOpt != d.GlobalDhcpOptions.end(); + ++itOpt) + { + if (itOpt->first == DhcpOpt_SubnetMask) + continue; + + xml::ElementNode *pelmOpt = pelmOptions->createChild("Option"); + + if (!pelmOpt) + break; + + pelmOpt->setAttribute("name", itOpt->first); + pelmOpt->setAttribute("value", itOpt->second); + } + } /* end of if */ + + if (d.VmSlot2OptionsM.size() > 0) + { + VmSlot2OptionsConstIterator itVmSlot; + DhcpOptConstIterator itOpt1; + for(itVmSlot = d.VmSlot2OptionsM.begin(); + itVmSlot != d.VmSlot2OptionsM.end(); + ++itVmSlot) + { + xml::ElementNode *pelmCfg = pelmThis->createChild("Config"); + pelmCfg->setAttribute("vm-name", itVmSlot->first.VmName); + pelmCfg->setAttribute("slot", itVmSlot->first.Slot); + + for (itOpt1 = itVmSlot->second.begin(); + itOpt1 != itVmSlot->second.end(); + ++itOpt1) + { + xml::ElementNode *pelmOpt = pelmCfg->createChild("Option"); + pelmOpt->setAttribute("name", itOpt1->first); + pelmOpt->setAttribute("value", itOpt1->second); + } + } + } /* and of if */ + + } + + xml::ElementNode *pelmNATNetworks; + /* don't create entry if no NAT networks are registered. */ + if (!llNATNetworks.empty()) + { + pelmNATNetworks = pelmNetserviceRegistry->createChild("NATNetworks"); + for (NATNetworksList::const_iterator it = llNATNetworks.begin(); + it != llNATNetworks.end(); + ++it) + { + const NATNetwork &n = *it; + xml::ElementNode *pelmThis = pelmNATNetworks->createChild("NATNetwork"); + pelmThis->setAttribute("networkName", n.strNetworkName); + pelmThis->setAttribute("network", n.strNetwork); + pelmThis->setAttribute("ipv6", n.fIPv6 ? 1 : 0); + pelmThis->setAttribute("ipv6prefix", n.strIPv6Prefix); + pelmThis->setAttribute("advertiseDefaultIPv6Route", (n.fAdvertiseDefaultIPv6Route)? 1 : 0); + pelmThis->setAttribute("needDhcp", (n.fNeedDhcpServer) ? 1 : 0); + pelmThis->setAttribute("enabled", (n.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here + if (n.llPortForwardRules4.size()) + { + xml::ElementNode *pelmPf4 = pelmThis->createChild("PortForwarding4"); + buildNATForwardRuleList(*pelmPf4, n.llPortForwardRules4); + } + if (n.llPortForwardRules6.size()) + { + xml::ElementNode *pelmPf6 = pelmThis->createChild("PortForwarding6"); + buildNATForwardRuleList(*pelmPf6, n.llPortForwardRules6); + } + + if (n.llHostLoopbackOffsetList.size()) + { + xml::ElementNode *pelmMappings = pelmThis->createChild("Mappings"); + buildNATLoopbacks(*pelmMappings, n.llHostLoopbackOffsetList); + + } + } } + xml::ElementNode *pelmSysProps = pelmGlobal->createChild("SystemProperties"); if (systemProperties.strDefaultMachineFolder.length()) pelmSysProps->setAttribute("defaultMachineFolder", systemProperties.strDefaultMachineFolder); + if (systemProperties.strLoggingLevel.length()) + pelmSysProps->setAttribute("LoggingLevel", systemProperties.strLoggingLevel); if (systemProperties.strDefaultHardDiskFormat.length()) pelmSysProps->setAttribute("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat); if (systemProperties.strVRDEAuthLibrary.length()) @@ -1406,6 +1685,9 @@ void MainConfigFile::write(const com::Utf8Str strFilename) pelmSysProps->setAttribute("LogHistoryCount", systemProperties.ulLogHistoryCount); if (systemProperties.strAutostartDatabasePath.length()) pelmSysProps->setAttribute("autostartDatabasePath", systemProperties.strAutostartDatabasePath); + if (systemProperties.strDefaultFrontend.length()) + pelmSysProps->setAttribute("defaultFrontend", systemProperties.strDefaultFrontend); + pelmSysProps->setAttribute("exclusiveHwVirt", systemProperties.fExclusiveHwVirt); buildUSBDeviceFilters(*pelmGlobal->createChild("USBDeviceFilters"), host.llUSBDeviceFilters, @@ -1474,9 +1756,22 @@ bool BIOSSettings::operator==(const BIOSSettings &d) const bool USBController::operator==(const USBController &u) const { return ( (this == &u) - || ( (fEnabled == u.fEnabled) - && (fEnabledEHCI == u.fEnabledEHCI) - && (llDeviceFilters == u.llDeviceFilters) + || ( (strName == u.strName) + && (enmType == u.enmType) + ) + ); +} + +/** + * Comparison operator. This gets called from MachineConfigFile::operator==, + * which in turn gets called from Machine::saveSettings to figure out whether + * machine settings have really changed and thus need to be written out to disk. + */ +bool USB::operator==(const USB &u) const +{ + return ( (this == &u) + || ( (llUSBControllers == u.llUSBControllers) + && (llDeviceFilters == u.llDeviceFilters) ) ); } @@ -1579,37 +1874,34 @@ bool GuestProperty::operator==(const GuestProperty &g) const ); } -// use a define for the platform-dependent default value of -// hwvirt exclusivity, since we'll need to check that value -// in bumpSettingsVersionIfNeeded() -#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) - #define HWVIRTEXCLUSIVEDEFAULT false -#else - #define HWVIRTEXCLUSIVEDEFAULT true -#endif - Hardware::Hardware() : strVersion("1"), fHardwareVirt(true), - fHardwareVirtExclusive(HWVIRTEXCLUSIVEDEFAULT), fNestedPaging(true), fVPID(true), + fUnrestrictedExecution(true), fHardwareVirtForce(false), fSyntheticCpu(false), + fTripleFaultReset(false), fPAE(false), + enmLongMode(HC_ARCH_BITS == 64 ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled), cCPUs(1), fCpuHotPlug(false), fHPETEnabled(false), ulCpuExecutionCap(100), ulMemorySizeMB((uint32_t)-1), + graphicsControllerType(GraphicsControllerType_VBoxVGA), ulVRAMSizeMB(8), cMonitors(1), fAccelerate3D(false), fAccelerate2DVideo(false), - ulVideoCaptureHorzRes(640), - ulVideoCaptureVertRes(480), + ulVideoCaptureHorzRes(1024), + ulVideoCaptureVertRes(768), + ulVideoCaptureRate(512), + ulVideoCaptureFPS(25), fVideoCaptureEnabled(false), - strVideoCaptureFile("Test.webm"), + u64VideoCaptureScreens(UINT64_C(0xffffffffffffffff)), + strVideoCaptureFile(""), firmwareType(FirmwareType_BIOS), pointingHIDType(PointingHIDType_PS2Mouse), keyboardHIDType(KeyboardHIDType_PS2Keyboard), @@ -1655,13 +1947,15 @@ bool Hardware::operator==(const Hardware& h) const || ( (strVersion == h.strVersion) && (uuid == h.uuid) && (fHardwareVirt == h.fHardwareVirt) - && (fHardwareVirtExclusive == h.fHardwareVirtExclusive) && (fNestedPaging == h.fNestedPaging) && (fLargePages == h.fLargePages) && (fVPID == h.fVPID) + && (fUnrestrictedExecution == h.fUnrestrictedExecution) && (fHardwareVirtForce == h.fHardwareVirtForce) && (fSyntheticCpu == h.fSyntheticCpu) && (fPAE == h.fPAE) + && (enmLongMode == h.enmLongMode) + && (fTripleFaultReset == h.fTripleFaultReset) && (cCPUs == h.cCPUs) && (fCpuHotPlug == h.fCpuHotPlug) && (ulCpuExecutionCap == h.ulCpuExecutionCap) @@ -1670,14 +1964,18 @@ bool Hardware::operator==(const Hardware& h) const && (llCpuIdLeafs == h.llCpuIdLeafs) && (ulMemorySizeMB == h.ulMemorySizeMB) && (mapBootOrder == h.mapBootOrder) + && (graphicsControllerType == h.graphicsControllerType) && (ulVRAMSizeMB == h.ulVRAMSizeMB) && (cMonitors == h.cMonitors) && (fAccelerate3D == h.fAccelerate3D) && (fAccelerate2DVideo == h.fAccelerate2DVideo) && (fVideoCaptureEnabled == h.fVideoCaptureEnabled) + && (u64VideoCaptureScreens == h.u64VideoCaptureScreens) && (strVideoCaptureFile == h.strVideoCaptureFile) && (ulVideoCaptureHorzRes == h.ulVideoCaptureHorzRes) && (ulVideoCaptureVertRes == h.ulVideoCaptureVertRes) + && (ulVideoCaptureRate == h.ulVideoCaptureRate) + && (ulVideoCaptureFPS == h.ulVideoCaptureFPS) && (firmwareType == h.firmwareType) && (pointingHIDType == h.pointingHIDType) && (keyboardHIDType == h.keyboardHIDType) @@ -1685,7 +1983,7 @@ bool Hardware::operator==(const Hardware& h) const && (fEmulatedUSBCardReader == h.fEmulatedUSBCardReader) && (vrdeSettings == h.vrdeSettings) && (biosSettings == h.biosSettings) - && (usbController == h.usbController) + && (usbSettings == h.usbSettings) && (llNetworkAdapters == h.llNetworkAdapters) && (llSerialPorts == h.llSerialPorts) && (llParallelPorts == h.llParallelPorts) @@ -1699,6 +1997,7 @@ bool Hardware::operator==(const Hardware& h) const && (strNotificationPatterns == h.strNotificationPatterns) && (ioSettings == h.ioSettings) && (pciAttachments == h.pciAttachments) + && (strDefaultFrontend == h.strDefaultFrontend) ) ); } @@ -1716,6 +2015,7 @@ bool AttachedDevice::operator==(const AttachedDevice &a) const && (fTempEject == a.fTempEject) && (fNonRotational == a.fNonRotational) && (fDiscard == a.fDiscard) + && (fHotPluggable == a.fHotPluggable) && (lPort == a.lPort) && (lDevice == a.lDevice) && (uuid == a.uuid) @@ -2069,25 +2369,11 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode, pelmTFTP->getAttributeValue("boot-file", nic.nat.strTFTPBootFile); pelmTFTP->getAttributeValue("next-server", nic.nat.strTFTPNextServer); } - xml::ElementNodesList plstNatPF; - elmMode.getChildElements(plstNatPF, "Forwarding"); - for (xml::ElementNodesList::iterator pf = plstNatPF.begin(); pf != plstNatPF.end(); ++pf) - { - NATRule rule; - uint32_t port = 0; - (*pf)->getAttributeValue("name", rule.strName); - (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto); - (*pf)->getAttributeValue("hostip", rule.strHostIP); - (*pf)->getAttributeValue("hostport", port); - rule.u16HostPort = port; - (*pf)->getAttributeValue("guestip", rule.strGuestIP); - (*pf)->getAttributeValue("guestport", port); - rule.u16GuestPort = port; - nic.nat.llRules.push_back(rule); - } + + readNATForwardRuleList(elmMode, nic.nat.llRules); } - else if ( (elmMode.nameEquals("HostInterface")) - || (elmMode.nameEquals("BridgedInterface"))) + else if ( elmMode.nameEquals("HostInterface") + || elmMode.nameEquals("BridgedInterface")) { enmAttachmentType = NetworkAttachmentType_Bridged; @@ -2121,15 +2407,21 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode, if (pelmModeChild->nameEquals("Property")) { Utf8Str strPropName, strPropValue; - if ( (pelmModeChild->getAttributeValue("name", strPropName)) - && (pelmModeChild->getAttributeValue("value", strPropValue)) - ) + if ( pelmModeChild->getAttributeValue("name", strPropName) + && pelmModeChild->getAttributeValue("value", strPropValue) ) nic.genericProperties[strPropName] = strPropValue; else throw ConfigFileError(this, pelmModeChild, N_("Required GenericInterface/Property/@name or @value attribute is missing")); } } } + else if (elmMode.nameEquals("NATNetwork")) + { + enmAttachmentType = NetworkAttachmentType_NATNetwork; + + if (!elmMode.getAttributeValue("name", nic.strNATNetworkName)) // required network name + throw ConfigFileError(this, &elmMode, N_("Required NATNetwork/@name element is missing")); + } else if (elmMode.nameEquals("VDE")) { enmAttachmentType = NetworkAttachmentType_Generic; @@ -2391,7 +2683,6 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtEx"))) { pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirt); - pelmCPUChild->getAttributeValue("exclusive", hw.fHardwareVirtExclusive); // settings version 1.9 } if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExNestedPaging"))) pelmCPUChild->getAttributeValue("enabled", hw.fNestedPaging); @@ -2399,6 +2690,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, pelmCPUChild->getAttributeValue("enabled", hw.fLargePages); if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExVPID"))) pelmCPUChild->getAttributeValue("enabled", hw.fVPID); + if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExUX"))) + pelmCPUChild->getAttributeValue("enabled", hw.fUnrestrictedExecution); if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtForce"))) pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirtForce); @@ -2411,8 +2704,19 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, else pelmCPUChild->getAttributeValue("enabled", hw.fPAE); + bool fLongMode; + if ( (pelmCPUChild = pelmHwChild->findChildElement("LongMode")) + && pelmCPUChild->getAttributeValue("enabled", fLongMode) ) + hw.enmLongMode = fLongMode ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled; + else + hw.enmLongMode = Hardware::LongMode_Legacy; + if ((pelmCPUChild = pelmHwChild->findChildElement("SyntheticCpu"))) pelmCPUChild->getAttributeValue("enabled", hw.fSyntheticCpu); + + if ((pelmCPUChild = pelmHwChild->findChildElement("TripleFaultReset"))) + pelmCPUChild->getAttributeValue("enabled", hw.fTripleFaultReset); + if ((pelmCPUChild = pelmHwChild->findChildElement("CpuIdTree"))) readCpuIdTree(*pelmCPUChild, hw.llCpuIdLeafs); } @@ -2478,6 +2782,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, hw.pointingHIDType = PointingHIDType_PS2Mouse; else if (strHIDType == "ComboMouse") hw.pointingHIDType = PointingHIDType_ComboMouse; + else if (strHIDType == "USBMultiTouch") + hw.pointingHIDType = PointingHIDType_USBMultiTouch; else throw ConfigFileError(this, pelmHwChild, @@ -2553,6 +2859,23 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, } else if (pelmHwChild->nameEquals("Display")) { + Utf8Str strGraphicsControllerType; + if (!pelmHwChild->getAttributeValue("controller", strGraphicsControllerType)) + hw.graphicsControllerType = GraphicsControllerType_VBoxVGA; + else + { + strGraphicsControllerType.toUpper(); + GraphicsControllerType_T type; + if (strGraphicsControllerType == "VBOXVGA") + type = GraphicsControllerType_VBoxVGA; + else if (strGraphicsControllerType == "VMSVGA") + type = GraphicsControllerType_VMSVGA; + else if (strGraphicsControllerType == "NONE") + type = GraphicsControllerType_Null; + else + throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in Display/@controller attribute"), strGraphicsControllerType.c_str()); + hw.graphicsControllerType = type; + } pelmHwChild->getAttributeValue("VRAMSize", hw.ulVRAMSizeMB); if (!pelmHwChild->getAttributeValue("monitorCount", hw.cMonitors)) pelmHwChild->getAttributeValue("MonitorCount", hw.cMonitors); // pre-v1.5 variant @@ -2560,14 +2883,16 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, pelmHwChild->getAttributeValue("Accelerate3D", hw.fAccelerate3D); // pre-v1.5 variant pelmHwChild->getAttributeValue("accelerate2DVideo", hw.fAccelerate2DVideo); } - else if (pelmHwChild->nameEquals("VideoRecording")) + else if (pelmHwChild->nameEquals("VideoCapture")) { - pelmHwChild->getAttributeValue("enabled", hw.fVideoCaptureEnabled); - pelmHwChild->getAttributeValue("file", hw.strVideoCaptureFile); - pelmHwChild->getAttributeValue("horzRes", hw.ulVideoCaptureHorzRes); - pelmHwChild->getAttributeValue("vertRes", hw.ulVideoCaptureVertRes); + pelmHwChild->getAttributeValue("enabled", hw.fVideoCaptureEnabled); + pelmHwChild->getAttributeValue("screens", hw.u64VideoCaptureScreens); + pelmHwChild->getAttributeValuePath("file", hw.strVideoCaptureFile); + pelmHwChild->getAttributeValue("horzRes", hw.ulVideoCaptureHorzRes); + pelmHwChild->getAttributeValue("vertRes", hw.ulVideoCaptureVertRes); + pelmHwChild->getAttributeValue("rate", hw.ulVideoCaptureRate); + pelmHwChild->getAttributeValue("fps", hw.ulVideoCaptureFPS); } - else if (pelmHwChild->nameEquals("RemoteDisplay")) { pelmHwChild->getAttributeValue("enabled", hw.vrdeSettings.fEnabled); @@ -2631,9 +2956,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, { /* */ Utf8Str strName, strValue; - if ( ((pelmProperty->getAttributeValue("name", strName))) - && ((pelmProperty->getAttributeValue("value", strValue))) - ) + if ( pelmProperty->getAttributeValue("name", strName) + && pelmProperty->getAttributeValue("value", strValue)) hw.vrdeSettings.mapProperties[strName] = strValue; else throw ConfigFileError(this, pelmProperty, N_("Required VRDE Property/@name or @value attribute is missing")); @@ -2679,7 +3003,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, // legacy BIOS/IDEController (pre 1.7) if ( (m->sv < SettingsVersion_v1_7) - && ((pelmBIOSChild = pelmHwChild->findChildElement("IDEController"))) + && (pelmBIOSChild = pelmHwChild->findChildElement("IDEController")) ) { StorageController sctl; @@ -2702,22 +3026,75 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, strg.llStorageControllers.push_back(sctl); } } - else if (pelmHwChild->nameEquals("USBController")) + else if ( (m->sv <= SettingsVersion_v1_14) + && pelmHwChild->nameEquals("USBController")) { - pelmHwChild->getAttributeValue("enabled", hw.usbController.fEnabled); - pelmHwChild->getAttributeValue("enabledEhci", hw.usbController.fEnabledEHCI); + bool fEnabled = false; + + pelmHwChild->getAttributeValue("enabled", fEnabled); + if (fEnabled) + { + /* Create OHCI controller with default name. */ + USBController ctrl; + + ctrl.strName = "OHCI"; + ctrl.enmType = USBControllerType_OHCI; + hw.usbSettings.llUSBControllers.push_back(ctrl); + } + + pelmHwChild->getAttributeValue("enabledEhci", fEnabled); + if (fEnabled) + { + /* Create OHCI controller with default name. */ + USBController ctrl; + + ctrl.strName = "EHCI"; + ctrl.enmType = USBControllerType_EHCI; + hw.usbSettings.llUSBControllers.push_back(ctrl); + } readUSBDeviceFilters(*pelmHwChild, - hw.usbController.llDeviceFilters); + hw.usbSettings.llDeviceFilters); } - else if ( (m->sv < SettingsVersion_v1_7) - && (pelmHwChild->nameEquals("SATAController")) - ) + else if (pelmHwChild->nameEquals("USB")) + { + const xml::ElementNode *pelmUSBChild; + + if ((pelmUSBChild = pelmHwChild->findChildElement("Controllers"))) + { + xml::NodesLoop nl2(*pelmUSBChild, "Controller"); + const xml::ElementNode *pelmCtrl; + + while ((pelmCtrl = nl2.forAllNodes())) + { + USBController ctrl; + com::Utf8Str strCtrlType; + + pelmCtrl->getAttributeValue("name", ctrl.strName); + + if (pelmCtrl->getAttributeValue("type", strCtrlType)) + { + if (strCtrlType == "OHCI") + ctrl.enmType = USBControllerType_OHCI; + else if (strCtrlType == "EHCI") + ctrl.enmType = USBControllerType_EHCI; + else + throw ConfigFileError(this, pelmCtrl, N_("Invalid value '%s' for Controller/@type attribute"), strCtrlType.c_str()); + } + + hw.usbSettings.llUSBControllers.push_back(ctrl); + } + } + + if ((pelmUSBChild = pelmHwChild->findChildElement("DeviceFilters"))) + readUSBDeviceFilters(*pelmUSBChild, hw.usbSettings.llDeviceFilters); + } + else if ( m->sv < SettingsVersion_v1_7 + && pelmHwChild->nameEquals("SATAController")) { bool f; - if ( (pelmHwChild->getAttributeValue("enabled", f)) - && (f) - ) + if ( pelmHwChild->getAttributeValue("enabled", f) + && f) { StorageController sctl; sctl.strName = "SATA Controller"; @@ -2734,15 +3111,15 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, else if (pelmHwChild->nameEquals("RTC")) { Utf8Str strLocalOrUTC; - machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC) - && strLocalOrUTC == "UTC"; + machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC) + && strLocalOrUTC == "UTC"; } - else if ( (pelmHwChild->nameEquals("UART")) - || (pelmHwChild->nameEquals("Uart")) // used before 1.3 + else if ( pelmHwChild->nameEquals("UART") + || pelmHwChild->nameEquals("Uart") // used before 1.3 ) readSerialPorts(*pelmHwChild, hw.llSerialPorts); - else if ( (pelmHwChild->nameEquals("LPT")) - || (pelmHwChild->nameEquals("Lpt")) // used before 1.3 + else if ( pelmHwChild->nameEquals("LPT") + || pelmHwChild->nameEquals("Lpt") // used before 1.3 ) readParallelPorts(*pelmHwChild, hw.llParallelPorts); else if (pelmHwChild->nameEquals("AudioAdapter")) @@ -2844,7 +3221,9 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, hw.ioSettings.llBandwidthGroups.push_back(gr); } } - } else if (pelmHwChild->nameEquals("HostPci")) { + } + else if (pelmHwChild->nameEquals("HostPci")) + { const xml::ElementNode *pelmDevices; if ((pelmDevices = pelmHwChild->findChildElement("Devices"))) @@ -2877,6 +3256,15 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, pelmCardReader->getAttributeValue("enabled", hw.fEmulatedUSBCardReader); } } + else if (pelmHwChild->nameEquals("Frontend")) + { + const xml::ElementNode *pelmDefault; + + if ((pelmDefault = pelmHwChild->findChildElement("Default"))) + { + pelmDefault->getAttributeValue("type", hw.strDefaultFrontend); + } + } } if (hw.ulMemorySizeMB == (uint32_t)-1) @@ -3099,6 +3487,7 @@ void MachineConfigFile::readStorageControllers(const xml::ElementNode &elmStorag if (!pelmAttached->getAttributeValue("device", att.lDevice)) throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/@device attribute is missing")); + pelmAttached->getAttributeValue("hotpluggable", att.fHotPluggable); pelmAttached->getAttributeValue("bandwidthGroup", att.strBwGroup); sctl.llAttachedDevices.push_back(att); } @@ -3140,9 +3529,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar const xml::ElementNode *pDriveChild; Utf8Str strTmp; - if ( ((pDriveChild = pelmHwChild->findChildElement("Image"))) - && (pDriveChild->getAttributeValue("uuid", strTmp)) - ) + if ( (pDriveChild = pelmHwChild->findChildElement("Image")) != NULL + && pDriveChild->getAttributeValue("uuid", strTmp)) parseUUID(att.uuid, strTmp); else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive"))) pDriveChild->getAttributeValue("src", att.strHostDriveSrc); @@ -3170,9 +3558,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar else if (pelmHwChild->nameEquals("FloppyDrive")) { bool fEnabled; - if ( (pelmHwChild->getAttributeValue("enabled", fEnabled)) - && (fEnabled) - ) + if ( pelmHwChild->getAttributeValue("enabled", fEnabled) + && fEnabled) { // create a new floppy controller and attach a floppy "attached device" StorageController sctl; @@ -3188,9 +3575,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar const xml::ElementNode *pDriveChild; Utf8Str strTmp; - if ( ((pDriveChild = pelmHwChild->findChildElement("Image"))) - && (pDriveChild->getAttributeValue("uuid", strTmp)) - ) + if ( (pDriveChild = pelmHwChild->findChildElement("Image")) + && pDriveChild->getAttributeValue("uuid", strTmp) ) parseUUID(att.uuid, strTmp); else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive"))) pDriveChild->getAttributeValue("src", att.strHostDriveSrc); @@ -3296,17 +3682,26 @@ void MachineConfigFile::readGroups(const xml::ElementNode *pElmGroups, StringsLi * contain a list of child snapshots; such lists are maintained in the * Snapshot structure. * + * @param curSnapshotUuid + * @param depth * @param elmSnapshot * @param snap + * @returns true if curSnapshotUuid is in this snapshot subtree, otherwise false */ -void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot, +bool MachineConfigFile::readSnapshot(const Guid &curSnapshotUuid, + uint32_t depth, + const xml::ElementNode &elmSnapshot, Snapshot &snap) { + if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX) + throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), depth); + Utf8Str strTemp; if (!elmSnapshot.getAttributeValue("uuid", strTemp)) throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@uuid attribute is missing")); parseUUID(snap.uuid, strTemp); + bool foundCurrentSnapshot = (snap.uuid == curSnapshotUuid); if (!elmSnapshot.getAttributeValue("name", snap.strName)) throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@name attribute is missing")); @@ -3332,13 +3727,11 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot, { if (pelmSnapshotChild->nameEquals("Description")) snap.strDescription = pelmSnapshotChild->getValue(); - else if ( (m->sv < SettingsVersion_v1_7) - && (pelmSnapshotChild->nameEquals("HardDiskAttachments")) - ) + else if ( m->sv < SettingsVersion_v1_7 + && pelmSnapshotChild->nameEquals("HardDiskAttachments")) readHardDiskAttachments_pre1_7(*pelmSnapshotChild, snap.storage); - else if ( (m->sv >= SettingsVersion_v1_7) - && (pelmSnapshotChild->nameEquals("StorageControllers")) - ) + else if ( m->sv >= SettingsVersion_v1_7 + && pelmSnapshotChild->nameEquals("StorageControllers")) readStorageControllers(*pelmSnapshotChild, snap.storage); else if (pelmSnapshotChild->nameEquals("Snapshots")) { @@ -3348,9 +3741,15 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot, { if (pelmChildSnapshot->nameEquals("Snapshot")) { - Snapshot child; - readSnapshot(*pelmChildSnapshot, child); - snap.llChildSnapshots.push_back(child); + // Use the heap to reduce the stack footprint. Each + // recursion needs over 1K, and there can be VMs with + // deeply nested snapshots. The stack can be quite + // small, especially with XPCOM. + Snapshot *child = new Snapshot(); + bool found = readSnapshot(curSnapshotUuid, depth + 1, *pelmChildSnapshot, *child); + foundCurrentSnapshot = foundCurrentSnapshot || found; + snap.llChildSnapshots.push_back(*child); + delete child; } } } @@ -3364,6 +3763,8 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot, readDebugging(elmSnapshot.findChildElement("Debugging"), &snap.debugging); readAutostart(elmSnapshot.findChildElement("Autostart"), &snap.autostart); // note: Groups exist only for Machine, not for Snapshot + + return foundCurrentSnapshot; } const struct { @@ -3430,9 +3831,8 @@ void MachineConfigFile::convertOldOSType_pre1_5(Utf8Str &str) void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) { Utf8Str strUUID; - if ( (elmMachine.getAttributeValue("uuid", strUUID)) - && (elmMachine.getAttributeValue("name", machineUserData.strName)) - ) + if ( elmMachine.getAttributeValue("uuid", strUUID) + && elmMachine.getAttributeValue("name", machineUserData.strName)) { parseUUID(uuid, strUUID); @@ -3441,7 +3841,6 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) Utf8Str str; elmMachine.getAttributeValue("Description", machineUserData.strDescription); - elmMachine.getAttributeValue("OSType", machineUserData.strOsType); if (m->sv < SettingsVersion_v1_5) convertOldOSType_pre1_5(machineUserData.strOsType); @@ -3461,6 +3860,8 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) if (elmMachine.getAttributeValue("aborted", fAborted)) fAborted = true; + elmMachine.getAttributeValue("icon", machineUserData.ovIcon); + // parse Hardware before the other elements because other things depend on it const xml::ElementNode *pelmHardware; if (!(pelmHardware = elmMachine.findChildElement("Hardware"))) @@ -3484,9 +3885,14 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) readStorageControllers(*pelmMachineChild, storageMachine); else if (pelmMachineChild->nameEquals("Snapshot")) { + if (uuidCurrentSnapshot.isZero()) + throw ConfigFileError(this, &elmMachine, N_("Snapshots present but required Machine/@currentSnapshot attribute is missing")); + bool foundCurrentSnapshot = false; Snapshot snap; // this will recurse into child snapshots, if necessary - readSnapshot(*pelmMachineChild, snap); + foundCurrentSnapshot = readSnapshot(uuidCurrentSnapshot, 1, *pelmMachineChild, snap); + if (!foundCurrentSnapshot) + throw ConfigFileError(this, &elmMachine, N_("Snapshots present but none matches the UUID in the Machine/@currentSnapshot attribute")); llFirstSnapshot.push_back(snap); } else if (pelmMachineChild->nameEquals("Description")) @@ -3544,8 +3950,10 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if (m->sv >= SettingsVersion_v1_4) pelmHardware->setAttribute("version", hw.strVersion); - if ( (m->sv >= SettingsVersion_v1_9) - && (!hw.uuid.isEmpty()) + + if ((m->sv >= SettingsVersion_v1_9) + && !hw.uuid.isZero() + && hw.uuid.isValid() ) pelmHardware->setAttribute("uuid", hw.uuid.toStringCurly()); @@ -3553,15 +3961,18 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, xml::ElementNode *pelmHwVirtEx = pelmCPU->createChild("HardwareVirtEx"); pelmHwVirtEx->setAttribute("enabled", hw.fHardwareVirt); - if (m->sv >= SettingsVersion_v1_9) - pelmHwVirtEx->setAttribute("exclusive", hw.fHardwareVirtExclusive); pelmCPU->createChild("HardwareVirtExNestedPaging")->setAttribute("enabled", hw.fNestedPaging); pelmCPU->createChild("HardwareVirtExVPID")->setAttribute("enabled", hw.fVPID); + pelmCPU->createChild("HardwareVirtExUX")->setAttribute("enabled", hw.fUnrestrictedExecution); pelmCPU->createChild("PAE")->setAttribute("enabled", hw.fPAE); + if (m->sv >= SettingsVersion_v1_14 && hw.enmLongMode != Hardware::LongMode_Legacy) + pelmCPU->createChild("LongMode")->setAttribute("enabled", hw.enmLongMode == Hardware::LongMode_Enabled); if (hw.fSyntheticCpu) pelmCPU->createChild("SyntheticCpu")->setAttribute("enabled", hw.fSyntheticCpu); + if (hw.fTripleFaultReset) + pelmCPU->createChild("TripleFaultReset")->setAttribute("enabled", hw.fTripleFaultReset); pelmCPU->setAttribute("count", hw.cCPUs); if (hw.ulCpuExecutionCap != 100) pelmCPU->setAttribute("executionCap", hw.ulCpuExecutionCap); @@ -3642,12 +4053,13 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, switch (hw.pointingHIDType) { - case PointingHIDType_USBMouse: pcszHID = "USBMouse"; break; - case PointingHIDType_USBTablet: pcszHID = "USBTablet"; break; - case PointingHIDType_PS2Mouse: pcszHID = "PS2Mouse"; break; - case PointingHIDType_ComboMouse: pcszHID = "ComboMouse"; break; - case PointingHIDType_None: pcszHID = "None"; break; - default: Assert(false); pcszHID = "PS2Mouse"; break; + case PointingHIDType_USBMouse: pcszHID = "USBMouse"; break; + case PointingHIDType_USBTablet: pcszHID = "USBTablet"; break; + case PointingHIDType_PS2Mouse: pcszHID = "PS2Mouse"; break; + case PointingHIDType_ComboMouse: pcszHID = "ComboMouse"; break; + case PointingHIDType_USBMultiTouch: pcszHID = "USBMultiTouch";break; + case PointingHIDType_None: pcszHID = "None"; break; + default: Assert(false); pcszHID = "PS2Mouse"; break; } pelmHID->setAttribute("Pointing", pcszHID); @@ -3709,20 +4121,35 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, } xml::ElementNode *pelmDisplay = pelmHardware->createChild("Display"); + if (hw.graphicsControllerType != GraphicsControllerType_VBoxVGA) + { + const char *pcszGraphics; + switch (hw.graphicsControllerType) + { + case GraphicsControllerType_VBoxVGA: pcszGraphics = "VBoxVGA"; break; + case GraphicsControllerType_VMSVGA: pcszGraphics = "VMSVGA"; break; + default: /*case GraphicsControllerType_Null:*/ pcszGraphics = "None"; break; + } + pelmDisplay->setAttribute("controller", pcszGraphics); + } pelmDisplay->setAttribute("VRAMSize", hw.ulVRAMSizeMB); pelmDisplay->setAttribute("monitorCount", hw.cMonitors); pelmDisplay->setAttribute("accelerate3D", hw.fAccelerate3D); if (m->sv >= SettingsVersion_v1_8) pelmDisplay->setAttribute("accelerate2DVideo", hw.fAccelerate2DVideo); - xml::ElementNode *pelmVideoCapture = pelmHardware->createChild("VideoRecording"); + xml::ElementNode *pelmVideoCapture = pelmHardware->createChild("VideoCapture"); - if (m->sv >= SettingsVersion_v1_12) + if (m->sv >= SettingsVersion_v1_14) { - pelmVideoCapture->setAttribute("enabled", hw.fVideoCaptureEnabled); - pelmVideoCapture->setAttribute("file", hw.strVideoCaptureFile); - pelmVideoCapture->setAttribute("horzRes", hw.ulVideoCaptureHorzRes); - pelmVideoCapture->setAttribute("vertRes", hw.ulVideoCaptureVertRes); + pelmVideoCapture->setAttribute("enabled", hw.fVideoCaptureEnabled); + pelmVideoCapture->setAttribute("screens", hw.u64VideoCaptureScreens); + if (!hw.strVideoCaptureFile.isEmpty()) + pelmVideoCapture->setAttributePath("file", hw.strVideoCaptureFile); + pelmVideoCapture->setAttribute("horzRes", hw.ulVideoCaptureHorzRes); + pelmVideoCapture->setAttribute("vertRes", hw.ulVideoCaptureVertRes); + pelmVideoCapture->setAttribute("rate", hw.ulVideoCaptureRate); + pelmVideoCapture->setAttribute("fps", hw.ulVideoCaptureFPS); } xml::ElementNode *pelmVRDE = pelmHardware->createChild("RemoteDisplay"); @@ -3861,7 +4288,8 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmDVD->setAttribute("passthrough", att.fPassThrough); if (att.fTempEject) pelmDVD->setAttribute("tempeject", att.fTempEject); - if (!att.uuid.isEmpty()) + + if (!att.uuid.isZero() && att.uuid.isValid()) pelmDVD->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly()); else if (att.strHostDriveSrc.length()) pelmDVD->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc); @@ -3877,7 +4305,8 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, { const AttachedDevice &att = sctl.llAttachedDevices.front(); pelmFloppy->setAttribute("enabled", true); - if (!att.uuid.isEmpty()) + + if (!att.uuid.isZero() && att.uuid.isValid()) pelmFloppy->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly()); else if (att.strHostDriveSrc.length()) pelmFloppy->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc); @@ -3893,13 +4322,68 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, throw ConfigFileError(this, NULL, N_("Internal error: cannot save more than one floppy drive with old settings format")); } - xml::ElementNode *pelmUSB = pelmHardware->createChild("USBController"); - pelmUSB->setAttribute("enabled", hw.usbController.fEnabled); - pelmUSB->setAttribute("enabledEhci", hw.usbController.fEnabledEHCI); + if (m->sv < SettingsVersion_v1_14) + { + bool fOhciEnabled = false; + bool fEhciEnabled = false; + xml::ElementNode *pelmUSB = pelmHardware->createChild("USBController"); + + for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin(); + it != hardwareMachine.usbSettings.llUSBControllers.end(); + ++it) + { + const USBController &ctrl = *it; + + switch (ctrl.enmType) + { + case USBControllerType_OHCI: + fOhciEnabled = true; + break; + case USBControllerType_EHCI: + fEhciEnabled = true; + break; + default: + AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType)); + } + } + + pelmUSB->setAttribute("enabled", fOhciEnabled); + pelmUSB->setAttribute("enabledEhci", fEhciEnabled); + + buildUSBDeviceFilters(*pelmUSB, hw.usbSettings.llDeviceFilters, false /* fHostMode */); + } + else + { + xml::ElementNode *pelmUSB = pelmHardware->createChild("USB"); + xml::ElementNode *pelmCtrls = pelmUSB->createChild("Controllers"); + + for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin(); + it != hardwareMachine.usbSettings.llUSBControllers.end(); + ++it) + { + const USBController &ctrl = *it; + com::Utf8Str strType; + xml::ElementNode *pelmCtrl = pelmCtrls->createChild("Controller"); - buildUSBDeviceFilters(*pelmUSB, - hw.usbController.llDeviceFilters, - false); // fHostMode + switch (ctrl.enmType) + { + case USBControllerType_OHCI: + strType = "OHCI"; + break; + case USBControllerType_EHCI: + strType = "EHCI"; + break; + default: + AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType)); + } + + pelmCtrl->setAttribute("name", ctrl.strName); + pelmCtrl->setAttribute("type", strType); + } + + xml::ElementNode *pelmFilters = pelmUSB->createChild("DeviceFilters"); + buildUSBDeviceFilters(*pelmFilters, hw.usbSettings.llDeviceFilters, false /* fHostMode */); + } xml::ElementNode *pelmNetwork = pelmHardware->createChild("Network"); for (NetworkAdaptersList::const_iterator it = hw.llNetworkAdapters.begin(); @@ -3986,11 +4470,13 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if (nic.mode != NetworkAttachmentType_Bridged) buildNetworkXML(NetworkAttachmentType_Bridged, *pelmDisabledNode, false, nic); if (nic.mode != NetworkAttachmentType_Internal) - buildNetworkXML(NetworkAttachmentType_HostOnly, *pelmDisabledNode, false, nic); + buildNetworkXML(NetworkAttachmentType_Internal, *pelmDisabledNode, false, nic); if (nic.mode != NetworkAttachmentType_HostOnly) buildNetworkXML(NetworkAttachmentType_HostOnly, *pelmDisabledNode, false, nic); if (nic.mode != NetworkAttachmentType_Generic) buildNetworkXML(NetworkAttachmentType_Generic, *pelmDisabledNode, false, nic); + if (nic.mode != NetworkAttachmentType_NATNetwork) + buildNetworkXML(NetworkAttachmentType_NATNetwork, *pelmDisabledNode, false, nic); buildNetworkXML(nic.mode, *pelmAdapter, true, nic); } } @@ -4181,11 +4667,19 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if (m->sv >= SettingsVersion_v1_12) { xml::ElementNode *pelmEmulatedUSB = pelmHardware->createChild("EmulatedUSB"); - xml::ElementNode *pelmCardReader = pelmEmulatedUSB->createChild("CardReader"); + xml::ElementNode *pelmCardReader = pelmEmulatedUSB->createChild("CardReader"); pelmCardReader->setAttribute("enabled", hw.fEmulatedUSBCardReader); } + if ( m->sv >= SettingsVersion_v1_14 + && !hw.strDefaultFrontend.isEmpty()) + { + xml::ElementNode *pelmFrontend = pelmHardware->createChild("Frontend"); + xml::ElementNode *pelmDefault = pelmFrontend->createChild("Default"); + pelmDefault->setAttribute("type", hw.strDefaultFrontend); + } + xml::ElementNode *pelmGuest = pelmHardware->createChild("Guest"); pelmGuest->setAttribute("memoryBalloonSize", hw.ulMemoryBalloonSize); @@ -4263,23 +4757,7 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode, if (nic.nat.strTFTPNextServer.length()) pelmTFTP->setAttribute("next-server", nic.nat.strTFTPNextServer); } - for (NATRuleList::const_iterator rule = nic.nat.llRules.begin(); - rule != nic.nat.llRules.end(); ++rule) - { - xml::ElementNode *pelmPF; - pelmPF = pelmNAT->createChild("Forwarding"); - if ((*rule).strName.length()) - pelmPF->setAttribute("name", (*rule).strName); - pelmPF->setAttribute("proto", (*rule).proto); - if ((*rule).strHostIP.length()) - pelmPF->setAttribute("hostip", (*rule).strHostIP); - if ((*rule).u16HostPort) - pelmPF->setAttribute("hostport", (*rule).u16HostPort); - if ((*rule).strGuestIP.length()) - pelmPF->setAttribute("guestip", (*rule).strGuestIP); - if ((*rule).u16GuestPort) - pelmPF->setAttribute("guestport", (*rule).u16GuestPort); - } + buildNATForwardRuleList(*pelmNAT, nic.nat.llRules); break; case NetworkAttachmentType_Bridged: @@ -4313,6 +4791,11 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode, } break; + case NetworkAttachmentType_NATNetwork: + if (fEnabled || !nic.strNATNetworkName.isEmpty()) + elmParent.createChild("NATNetwork")->setAttribute("name", nic.strNATNetworkName); + break; + default: /*case NetworkAttachmentType_Null:*/ break; } @@ -4348,7 +4831,7 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, if ( (m->sv < SettingsVersion_v1_9) && (sc.controllerType == StorageControllerType_I82078) ) - // floppy controller already got written into / in writeHardware() + // floppy controller already got written into / in buildHardwareXML() // for pre-1.9 settings continue; @@ -4443,6 +4926,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, pelmDevice->setAttribute("type", pcszType); + if (att.fHotPluggable) + pelmDevice->setAttribute("hotpluggable", att.fHotPluggable); + pelmDevice->setAttribute("port", att.lPort); pelmDevice->setAttribute("device", att.lDevice); @@ -4450,8 +4936,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, pelmDevice->setAttribute("bandwidthGroup", att.strBwGroup); // attached image, if any - if ( !att.uuid.isEmpty() - && ( att.deviceType == DeviceType_HardDisk + if (!att.uuid.isZero() + && att.uuid.isValid() + && (att.deviceType == DeviceType_HardDisk || !fSkipRemovableMedia ) ) @@ -4547,12 +5034,18 @@ void MachineConfigFile::buildGroupsXML(xml::ElementNode *pElmParent, const Strin * Writes a single snapshot into the DOM tree. Initially this gets called from MachineConfigFile::write() * for the root snapshot of a machine, if present; elmParent then points to the node under the * node to which must be added. This may then recurse for child snapshots. + * + * @param depth * @param elmParent * @param snap */ -void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, +void MachineConfigFile::buildSnapshotXML(uint32_t depth, + xml::ElementNode &elmParent, const Snapshot &snap) { + if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX) + throw ConfigFileError(this, NULL, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX); + xml::ElementNode *pelmSnapshot = elmParent.createChild("Snapshot"); pelmSnapshot->setAttribute("uuid", snap.uuid.toStringCurly()); @@ -4584,7 +5077,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, ++it) { const Snapshot &child = *it; - buildSnapshotXML(*pelmChildren, child); + buildSnapshotXML(depth + 1, *pelmChildren, child); } } } @@ -4613,7 +5106,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, * that, if snapshots are present. Otherwise all snapshots are suppressed * (when called from OVF). * - * -- BuildMachineXML_WriteVboxVersionAttribute: If set, add a settingsVersion + * -- BuildMachineXML_WriteVBoxVersionAttribute: If set, add a settingsVersion * attribute to the machine tag with the vbox settings version. This is for * the OVF export case in which we don't have the settings version set in * the root element. @@ -4637,7 +5130,7 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, uint32_t fl, std::list *pllElementsWithUuidAttributes) { - if (fl & BuildMachineXML_WriteVboxVersionAttribute) + if (fl & BuildMachineXML_WriteVBoxVersionAttribute) // add settings version attribute to machine element setVersionAttribute(elmMachine); @@ -4654,8 +5147,10 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, && !(fl & BuildMachineXML_SuppressSavedState) ) elmMachine.setAttributePath("stateFile", strStateFile); - if ( (fl & BuildMachineXML_IncludeSnapshots) - && !uuidCurrentSnapshot.isEmpty()) + + if ((fl & BuildMachineXML_IncludeSnapshots) + && !uuidCurrentSnapshot.isZero() + && uuidCurrentSnapshot.isValid()) elmMachine.setAttribute("currentSnapshot", uuidCurrentSnapshot.toStringCurly()); if (machineUserData.strSnapshotFolder.length()) @@ -4665,6 +5160,10 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, elmMachine.setAttribute("lastStateChange", makeString(timeLastStateChange)); if (fAborted) elmMachine.setAttribute("aborted", fAborted); + // Please keep the icon last so that one doesn't have to check if there + // is anything in the line after this very long attribute in the XML. + if (machineUserData.ovIcon.length()) + elmMachine.setAttribute("icon", machineUserData.ovIcon); if ( m->sv >= SettingsVersion_v1_9 && ( machineUserData.fTeleporterEnabled || machineUserData.uTeleporterPort @@ -4717,7 +5216,7 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, if ( (fl & BuildMachineXML_IncludeSnapshots) && llFirstSnapshot.size()) - buildSnapshotXML(elmMachine, llFirstSnapshot.front()); + buildSnapshotXML(1, elmMachine, llFirstSnapshot.front()); buildHardwareXML(elmMachine, hardwareMachine, storageMachine); buildStorageControllersXML(elmMachine, @@ -4842,6 +5341,69 @@ AudioDriverType_T MachineConfigFile::getHostDefaultAudioDriver() */ void MachineConfigFile::bumpSettingsVersionIfNeeded() { + if (m->sv < SettingsVersion_v1_14) + { + // VirtualBox 4.3 adds default frontend setting, graphics controller + // setting, explicit long mode setting, video capturing and NAT networking. + if ( !hardwareMachine.strDefaultFrontend.isEmpty() + || hardwareMachine.graphicsControllerType != GraphicsControllerType_VBoxVGA + || hardwareMachine.enmLongMode != Hardware::LongMode_Legacy + || machineUserData.ovIcon.length() > 0 + || hardwareMachine.fVideoCaptureEnabled) + { + m->sv = SettingsVersion_v1_14; + return; + } + NetworkAdaptersList::const_iterator netit; + for (netit = hardwareMachine.llNetworkAdapters.begin(); + netit != hardwareMachine.llNetworkAdapters.end(); + ++netit) + { + if (netit->mode == NetworkAttachmentType_NATNetwork) + { + m->sv = SettingsVersion_v1_14; + break; + } + } + } + + if (m->sv < SettingsVersion_v1_14) + { + unsigned cOhciCtrls = 0; + unsigned cEhciCtrls = 0; + bool fNonStdName = false; + + for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin(); + it != hardwareMachine.usbSettings.llUSBControllers.end(); + ++it) + { + const USBController &ctrl = *it; + + switch (ctrl.enmType) + { + case USBControllerType_OHCI: + cOhciCtrls++; + if (ctrl.strName != "OHCI") + fNonStdName = true; + break; + case USBControllerType_EHCI: + cEhciCtrls++; + if (ctrl.strName != "EHCI") + fNonStdName = true; + break; + default: + AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType)); + } + + /* Skip checking other controllers if the settings bump is necessary. */ + if (cOhciCtrls > 1 || cEhciCtrls > 1 || fNonStdName) + { + m->sv = SettingsVersion_v1_14; + break; + } + } + } + if (m->sv < SettingsVersion_v1_13) { // VirtualBox 4.2 adds tracing, autostart, UUID in directory and groups. @@ -4872,15 +5434,9 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded() if (m->sv < SettingsVersion_v1_12) { - // 4.1: Emulated USB devices. - if (hardwareMachine.fEmulatedUSBCardReader) - m->sv = SettingsVersion_v1_12; - } - - if (m->sv < SettingsVersion_v1_12) - { - // VirtualBox 4.1 adds PCI passthrough. - if (hardwareMachine.pciAttachments.size()) + // VirtualBox 4.1 adds PCI passthrough and emulated USB Smart Card reader + if ( hardwareMachine.pciAttachments.size() + || hardwareMachine.fEmulatedUSBCardReader) m->sv = SettingsVersion_v1_12; } @@ -5168,12 +5724,11 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded() // all the following require settings version 1.9 if ( (m->sv < SettingsVersion_v1_9) && ( (hardwareMachine.firmwareType >= FirmwareType_EFI) - || (hardwareMachine.fHardwareVirtExclusive != HWVIRTEXCLUSIVEDEFAULT) || machineUserData.fTeleporterEnabled || machineUserData.uTeleporterPort || !machineUserData.strTeleporterAddress.isEmpty() || !machineUserData.strTeleporterPassword.isEmpty() - || !hardwareMachine.uuid.isEmpty() + || (!hardwareMachine.uuid.isZero() && hardwareMachine.uuid.isValid()) ) ) m->sv = SettingsVersion_v1_9; @@ -5212,7 +5767,7 @@ void MachineConfigFile::write(const com::Utf8Str &strFilename) buildMachineXML(*pelmMachine, MachineConfigFile::BuildMachineXML_IncludeSnapshots | MachineConfigFile::BuildMachineXML_MediaRegistry, - // but not BuildMachineXML_WriteVboxVersionAttribute + // but not BuildMachineXML_WriteVBoxVersionAttribute NULL); /* pllElementsWithUuidAttributes */ // now go write the XML diff --git a/src/VBox/Main/xml/SettingsConverter.xsl b/src/VBox/Main/xml/SettingsConverter.xsl deleted file mode 100644 index 9a31a4cc..00000000 --- a/src/VBox/Main/xml/SettingsConverter.xsl +++ /dev/null @@ -1,1043 +0,0 @@ - - - - - - - - - - - - - - Automatically converted from version '' - - - - - - - - - - - - - -Cannot convert an unknown XML file with the root node ''! - - - - - - -Cannot convert settings from version ''. -The source version is not supported. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - immutable - immutable - normal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - IDE - - - IDE - - - -Value '' of 'HardDiskAttachment::bus' attribute is invalid. - - - - - 0 - - - - 0 - - - 1 - - - -Value '' of 'HardDiskAttachment::device' attribute is invalid. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Null - OSS - ALSA - Pulse - CoreAudio - WinMM - DirectSound - SolAudio - MMPM - - -Value '' of 'AudioAdapter::driver' attribute is invalid. - - - - - - - - - - - - - - - - - - - - - - Null - Guest - External - - -Value '' of 'RemoteDisplay::authType' attribute is invalid. - - - - - - - - - - - - - Disabled - MenuOnly - MessageAndMenu - - -Value '' of 'BootMenu::mode' attribute is invalid. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VDI - VMDK - VHD - iSCSI - - - - - -Sub-element '' of 'HardDisk' element is invalid. - - - - - - - - - - - - - - - - - - - - iscsi:// - - - - @ - - - - - - - - - - - - - - - -Required attribute 'server' or 'target' is missing from ISCSIHardDisk element! - - - - - - - - - - TargetAddress - - - - - - - - TargetAddress - - - - - - - - - TargetName - - - - - - - - InitiatorUsername - - - - - - - - InitiatorSecret - - - - - - - - LUN - - - - - - - - - - - - - - Normal - Immutable - Writethrough - - -Value '' of 'HardDisk::type' attribute is invalid. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - Other - DOS - Windows31 - Windows95 - Windows98 - WindowsMe - WindowsNT4 - Windows2000 - WindowsXP - Windows2003 - WindowsVista - Windows2008 - OS2Warp3 - OS2Warp4 - OS2Warp45 - OS2eCS - Linux22 - Linux24 - Linux26 - ArchLinux - Debian - OpenSUSE - Fedora - Gentoo - Mandriva - RedHat - Ubuntu - Xandros - FreeBSD - OpenBSD - NetBSD - Netware - Solaris - OpenSolaris - L4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PIIX3 - - - - - - 2 - - - - - - - AHCI - - - - - - - - - - - - - - - - - - - - - - - - - - HardDisk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-common.xsd b/src/VBox/Main/xml/VirtualBox-settings-common.xsd deleted file mode 100644 index ffc3866b..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-common.xsd +++ /dev/null @@ -1,963 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (common definitions). - Copyright (c) 2004-2012 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd b/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd deleted file mode 100644 index d874c9c9..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (freebsd). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-linux.xsd b/src/VBox/Main/xml/VirtualBox-settings-linux.xsd deleted file mode 100644 index 461521eb..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-linux.xsd +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (linux). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd b/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd deleted file mode 100644 index 1d2efa76..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (macosx). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-os2.xsd b/src/VBox/Main/xml/VirtualBox-settings-os2.xsd deleted file mode 100644 index 771a9738..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-os2.xsd +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - Oracle VM VirtualBox Settings Schema (os2). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd b/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd deleted file mode 100644 index 6e504e5a..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (solaris). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings-windows.xsd b/src/VBox/Main/xml/VirtualBox-settings-windows.xsd deleted file mode 100644 index 8bdae19e..00000000 --- a/src/VBox/Main/xml/VirtualBox-settings-windows.xsd +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - Oracle VM VirtualBox Settings Schema (windows). - Copyright (c) 2004-2010 Oracle Corporation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/VBox/Main/xml/VirtualBox-settings.xsd b/src/VBox/Main/xml/VirtualBox-settings.xsd new file mode 100644 index 00000000..dc393df0 --- /dev/null +++ b/src/VBox/Main/xml/VirtualBox-settings.xsd @@ -0,0 +1,1309 @@ + + + + + + + + Oracle VM VirtualBox Settings Schema (common definitions). + Copyright (c) 2004-2013 Oracle Corporation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VBox/Main/xml/ovfreader.cpp b/src/VBox/Main/xml/ovfreader.cpp index eb685fd3..3762083b 100644 --- a/src/VBox/Main/xml/ovfreader.cpp +++ b/src/VBox/Main/xml/ovfreader.cpp @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -64,11 +64,38 @@ OVFReader::OVFReader(const RTCString &path) void OVFReader::parse() { const xml::ElementNode *pRootElem = m_doc.getRootElement(); - if ( !pRootElem - || strcmp(pRootElem->getName(), "Envelope") - ) + const xml::AttributeNode *pTypeAttr; + const char *pcszTypeAttr = ""; + RTCString pcszNamespaceURI; + + if (!pRootElem || strcmp(pRootElem->getName(), "Envelope")) throw OVFLogicError(N_("Root element in OVF file must be \"Envelope\".")); + pcszNamespaceURI = pRootElem->getNamespaceURI(); + if(pcszNamespaceURI.isEmpty()) + { + throw OVFLogicError(N_("Error reading namespace URI in 'Envelope' element, line %d"), pRootElem->getLineNumber()); + } + + if (strncmp(ovf::OVF20_URI_string, pcszNamespaceURI.c_str(), pcszNamespaceURI.length()) == 0) + { + m_envelopeData.setOVFVersion(ovf::OVFVersion_2_0); + } + else if (strncmp(OVF10_URI_string, pcszNamespaceURI.c_str(), pcszNamespaceURI.length()) == 0) + { + m_envelopeData.setOVFVersion(ovf::OVFVersion_1_0); + } + else + { + m_envelopeData.setOVFVersion(ovf::OVFVersion_0_9); + } + + if ((pTypeAttr = pRootElem->findAttribute("lang", "xml"))) + { + pcszTypeAttr = pTypeAttr->getValue(); + m_envelopeData.lang = pcszTypeAttr; + } + // OVF has the following rough layout: /* -- .... files referenced from other parts of the file, such as VMDK images @@ -105,56 +132,52 @@ void OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem, while ((pElem = loopChildren.forAllNodes())) { const char *pcszElemName = pElem->getName(); - const char *pcszTypeAttr = ""; - const xml::AttributeNode *pTypeAttr; - if ( ((pTypeAttr = pElem->findAttribute("xsi:type"))) - || ((pTypeAttr = pElem->findAttribute("type"))) - ) - pcszTypeAttr = pTypeAttr->getValue(); + const xml::AttributeNode *pTypeAttr = pElem->findAttribute("type"); + const char *pcszTypeAttr = pTypeAttr ? pTypeAttr->getValue() : ""; - if ( (!strcmp(pcszElemName, "DiskSection")) - || ( (!strcmp(pcszElemName, "Section")) - && (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type")) + if ( !strcmp(pcszElemName, "DiskSection") + || ( !strcmp(pcszElemName, "Section") + && !strcmp(pcszTypeAttr, "ovf:DiskSection_Type") ) ) { HandleDiskSection(pReferencesElem, pElem); } - else if ( (!strcmp(pcszElemName, "NetworkSection")) - || ( (!strcmp(pcszElemName, "Section")) - && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type")) + else if ( !strcmp(pcszElemName, "NetworkSection") + || ( !strcmp(pcszElemName, "Section") + && !strcmp(pcszTypeAttr, "ovf:NetworkSection_Type") ) ) { HandleNetworkSection(pElem); } - else if ( (!strcmp(pcszElemName, "DeploymentOptionSection"))) + else if ( !strcmp(pcszElemName, "DeploymentOptionSection")) { // TODO } - else if ( (!strcmp(pcszElemName, "Info"))) + else if ( !strcmp(pcszElemName, "Info")) { // child of VirtualSystemCollection -- TODO } - else if ( (!strcmp(pcszElemName, "ResourceAllocationSection"))) + else if ( !strcmp(pcszElemName, "ResourceAllocationSection")) { // child of VirtualSystemCollection -- TODO } - else if ( (!strcmp(pcszElemName, "StartupSection"))) + else if ( !strcmp(pcszElemName, "StartupSection")) { // child of VirtualSystemCollection -- TODO } - else if ( (!strcmp(pcszElemName, "VirtualSystem")) - || ( (!strcmp(pcszElemName, "Content")) - && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type")) + else if ( !strcmp(pcszElemName, "VirtualSystem") + || ( !strcmp(pcszElemName, "Content") + && !strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type") ) ) { HandleVirtualSystemContent(pElem); } - else if ( (!strcmp(pcszElemName, "VirtualSystemCollection")) - || ( (!strcmp(pcszElemName, "Content")) - && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type")) + else if ( !strcmp(pcszElemName, "VirtualSystemCollection") + || ( !strcmp(pcszElemName, "Content") + && !strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type") ) ) { @@ -187,23 +210,23 @@ void OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem, const char *pcszBad = NULL; const char *pcszDiskId; const char *pcszFormat; - if (!(pelmDisk->getAttributeValue("diskId", pcszDiskId))) + if (!pelmDisk->getAttributeValue("diskId", pcszDiskId)) pcszBad = "diskId"; - else if (!(pelmDisk->getAttributeValue("format", pcszFormat))) + else if (!pelmDisk->getAttributeValue("format", pcszFormat)) pcszBad = "format"; - else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity))) + else if (!pelmDisk->getAttributeValue("capacity", d.iCapacity)) pcszBad = "capacity"; else { d.strDiskId = pcszDiskId; d.strFormat = pcszFormat; - if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize))) + if (!pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)) // optional d.iPopulatedSize = -1; // optional vbox:uuid attribute (if OVF was exported by VirtualBox != 3.2) - pelmDisk->getAttributeValue("vbox:uuid", d.uuidVbox); + pelmDisk->getAttributeValue("uuid", d.uuidVBox, "vbox"); const char *pcszFileRef; if (pelmDisk->getAttributeValue("fileRef", pcszFileRef)) // optional @@ -211,15 +234,16 @@ void OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem, // look up corresponding /References/File nodes (list built above) const xml::ElementNode *pFileElem; if ( pReferencesElem - && ((pFileElem = pReferencesElem->findChildElementFromId(pcszFileRef))) + && (pFileElem = pReferencesElem->findChildElementFromId(pcszFileRef)) != NULL ) { + // copy remaining values from file node then const char *pcszBadInFile = NULL; const char *pcszHref; - if (!(pFileElem->getAttributeValue("href", pcszHref))) + if (!pFileElem->getAttributeValue("href", pcszHref)) pcszBadInFile = "href"; - else if (!(pFileElem->getAttributeValue("size", d.iSize))) + else if (!pFileElem->getAttributeValue("size", d.iSize)) d.iSize = -1; // optional d.strHref = pcszHref; @@ -253,11 +277,11 @@ void OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem, // suggest a size in megabytes to help callers with progress reports d.ulSuggestedSizeMB = 0; if (d.iCapacity != -1) - d.ulSuggestedSizeMB = d.iCapacity / _1M; + d.ulSuggestedSizeMB = (uint32_t)(d.iCapacity / _1M); else if (d.iPopulatedSize != -1) - d.ulSuggestedSizeMB = d.iPopulatedSize / _1M; + d.ulSuggestedSizeMB = (uint32_t)(d.iPopulatedSize / _1M); else if (d.iSize != -1) - d.ulSuggestedSizeMB = d.iSize / _1M; + d.ulSuggestedSizeMB = (uint32_t)(d.iSize / _1M); if (d.ulSuggestedSizeMB == 0) d.ulSuggestedSizeMB = 10000; // assume 10 GB, this is for the progress bar only anyway @@ -306,7 +330,7 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy // peek under the node whether we have a node; // that case case, the caller can completely ignore the OVF but only load the VBox machine XML - vsys.pelmVboxMachine = pelmVirtualSystem->findChildElement("vbox", "Machine"); + vsys.pelmVBoxMachine = pelmVirtualSystem->findChildElementNS("vbox", "Machine"); // now look for real OVF const xml::AttributeNode *pIdAttr = pelmVirtualSystem->findAttribute("id"); @@ -321,10 +345,8 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy const char *pcszTypeAttr = ""; if (!strcmp(pcszElemName, "Section")) // OVF 0.9 used "Section" element always with a varying "type" attribute { - const xml::AttributeNode *pTypeAttr; - if ( ((pTypeAttr = pelmThis->findAttribute("type"))) - || ((pTypeAttr = pelmThis->findAttribute("xsi:type"))) - ) + const xml::AttributeNode *pTypeAttr = pelmThis->findAttribute("type"); + if (pTypeAttr) pcszTypeAttr = pTypeAttr->getValue(); else throw OVFLogicError(N_("Error reading \"%s\": element \"Section\" has no \"type\" attribute, line %d"), @@ -332,8 +354,8 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy pelmThis->getLineNumber()); } - if ( (!strcmp(pcszElemName, "EulaSection")) - || (!strcmp(pcszTypeAttr, "ovf:EulaSection_Type")) + if ( !strcmp(pcszElemName, "EulaSection") + || !strcmp(pcszTypeAttr, "ovf:EulaSection_Type") ) { /* @@ -345,8 +367,8 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy if ((pelmLicense = pelmThis->findChildElement("License"))) vsys.strLicenseText = pelmLicense->getValue(); } - if ( (!strcmp(pcszElemName, "ProductSection")) - || (!strcmp(pcszTypeAttr, "ovf:ProductSection_Type")) + if ( !strcmp(pcszElemName, "ProductSection") + || !strcmp(pcszTypeAttr, "ovf:ProductSection_Type") ) { /*
@@ -373,8 +395,8 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy if ((pelmVendorUrl = pelmThis->findChildElement("VendorUrl"))) vsys.strVendorUrl = pelmVendorUrl->getValue(); } - else if ( (!strcmp(pcszElemName, "VirtualHardwareSection")) - || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type")) + else if ( !strcmp(pcszElemName, "VirtualHardwareSection") + || !strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type") ) { const xml::ElementNode *pelmSystem, *pelmVirtualSystemType; @@ -391,93 +413,80 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy vsys.strVirtualSystemType = pelmVirtualSystemType->getValue(); } - xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements - const xml::ElementNode *pelmItem; - while ((pelmItem = loopVirtualHardwareItems.forAllNodes())) { - VirtualHardwareItem i; + xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements + const xml::ElementNode *pelmItem; + while ((pelmItem = loopVirtualHardwareItems.forAllNodes())) + { + VirtualHardwareItem i; + + i.ulLineNumber = pelmItem->getLineNumber(); + i.fillItem(pelmItem); + try{ + i.checkConsistencyAndCompliance(); + } + catch (OVFLogicError &e) + { + throw OVFLogicError(N_("Error reading \"%s\": \"%s\""), + m_strPath.c_str(), + e.what()); + } - i.ulLineNumber = pelmItem->getLineNumber(); + // store! + vsys.mapHardwareItems[i.ulInstanceID] = i; + } + } - xml::NodesLoop loopItemChildren(*pelmItem); // all child elements - const xml::ElementNode *pelmItemChild; - while ((pelmItemChild = loopItemChildren.forAllNodes())) + { + xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "StorageItem");// all "StorageItem" child elements + const xml::ElementNode *pelmItem; + while ((pelmItem = loopVirtualHardwareItems.forAllNodes())) { - const char *pcszItemChildName = pelmItemChild->getName(); - if (!strcmp(pcszItemChildName, "Description")) - i.strDescription = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "Caption")) - i.strCaption = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "ElementName")) - i.strElementName = pelmItemChild->getValue(); - else if ( (!strcmp(pcszItemChildName, "InstanceID")) - || (!strcmp(pcszItemChildName, "InstanceId")) - ) - pelmItemChild->copyValue(i.ulInstanceID); - else if (!strcmp(pcszItemChildName, "HostResource")) - i.strHostResource = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "ResourceType")) + StorageItem i; + + i.ulLineNumber = pelmItem->getLineNumber(); + i.fillItem(pelmItem); + + try { - uint32_t ulType; - pelmItemChild->copyValue(ulType); - i.resourceType = (ResourceType_T)ulType; - i.fResourceRequired = true; - const char *pcszAttValue; - if (pelmItem->getAttributeValue("required", pcszAttValue)) - { - if (!strcmp(pcszAttValue, "false")) - i.fResourceRequired = false; - } + i.checkConsistencyAndCompliance(); } - else if (!strcmp(pcszItemChildName, "OtherResourceType")) - i.strOtherResourceType = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "ResourceSubType")) - i.strResourceSubType = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "AutomaticAllocation")) - i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false; - else if (!strcmp(pcszItemChildName, "AutomaticDeallocation")) - i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false; - else if (!strcmp(pcszItemChildName, "Parent")) - pelmItemChild->copyValue(i.ulParent); - else if (!strcmp(pcszItemChildName, "Connection")) - i.strConnection = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "Address")) + catch (OVFLogicError &e) { - i.strAddress = pelmItemChild->getValue(); - pelmItemChild->copyValue(i.lAddress); - } - else if (!strcmp(pcszItemChildName, "AddressOnParent")) - i.strAddressOnParent = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "AllocationUnits")) - i.strAllocationUnits = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "VirtualQuantity")) - pelmItemChild->copyValue(i.ullVirtualQuantity); - else if (!strcmp(pcszItemChildName, "Reservation")) - pelmItemChild->copyValue(i.ullReservation); - else if (!strcmp(pcszItemChildName, "Limit")) - pelmItemChild->copyValue(i.ullLimit); - else if (!strcmp(pcszItemChildName, "Weight")) - pelmItemChild->copyValue(i.ullWeight); - else if (!strcmp(pcszItemChildName, "ConsumerVisibility")) - i.strConsumerVisibility = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "MappingBehavior")) - i.strMappingBehavior = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "PoolID")) - i.strPoolID = pelmItemChild->getValue(); - else if (!strcmp(pcszItemChildName, "BusNumber")) // seen in some old OVF, but it's not listed in the OVF specs - pelmItemChild->copyValue(i.ulBusNumber); - else - throw OVFLogicError(N_("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"), + throw OVFLogicError(N_("Error reading \"%s\": \"%s\""), m_strPath.c_str(), - pcszItemChildName, - i.ulLineNumber); + e.what()); + } + + vsys.mapHardwareItems[i.ulInstanceID] = i; } + } + + { + xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "EthernetPortItem");// all "EthernetPortItem" child elements + const xml::ElementNode *pelmItem; + while ((pelmItem = loopVirtualHardwareItems.forAllNodes())) + { + EthernetPortItem i; + + i.ulLineNumber = pelmItem->getLineNumber(); + i.fillItem(pelmItem); + + try{ + i.checkConsistencyAndCompliance(); + } + catch (OVFLogicError &e) + { + throw OVFLogicError(N_("Error reading \"%s\": \"%s\""), + m_strPath.c_str(), + e.what()); + } - // store! - vsys.mapHardwareItems[i.ulInstanceID] = i; + vsys.mapHardwareItems[i.ulInstanceID] = i; + } } - HardDiskController *pPrimaryIDEController = NULL; // will be set once found + HardDiskController *pPrimaryIDEController = NULL;// will be set once found // now go thru all hardware items and handle them according to their type; // in this first loop we handle all items _except_ hard disk images, @@ -510,11 +519,11 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy break; case ResourceType_Memory: // 4 - if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit - || (i.strAllocationUnits == "MB") // found in MS docs - || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21 + if ( i.strAllocationUnits == "MegaBytes" // found in OVF created by OVF toolkit + || i.strAllocationUnits == "MB" // found in MS docs + || i.strAllocationUnits == "byte * 2^20" // suggested by OVF spec DSP0243 page 21 ) - vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024; + vsys.ullMemorySize = i.ullVirtualQuantity * _1M; else throw OVFLogicError(N_("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"), m_strPath.c_str(), @@ -721,6 +730,15 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy // do some analysis switch (i.resourceType) { + case ResourceType_CDDrive: // 15 + /* + cdrom1 + 7 + 15 + true + 5 + 0 + */ case ResourceType_HardDisk: // 17 { /* @@ -737,12 +755,11 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy // this is how the connection is specified in OVF ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent); if (it == vsys.mapControllers.end()) - throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"), + throw OVFLogicError(N_("Error reading \"%s\": Disk item with instance ID %d specifies invalid parent %d, line %d"), m_strPath.c_str(), i.ulInstanceID, i.ulParent, i.ulLineNumber); - //const HardDiskController &hdc = it->second; VirtualDisk vd; vd.idController = i.ulParent; @@ -756,14 +773,14 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy else if (i.strHostResource.startsWith("/disk/")) vd.strDiskId = i.strHostResource.substr(6); - if ( !(vd.strDiskId.length()) - || (m_mapDisks.find(vd.strDiskId) == m_mapDisks.end()) - ) - throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"), - m_strPath.c_str(), - i.ulInstanceID, - i.strHostResource.c_str(), - i.ulLineNumber); + //the error may be missed for CD, because CD can be empty + if ((vd.strDiskId.isEmpty() || (m_mapDisks.find(vd.strDiskId) == m_mapDisks.end())) + && i.resourceType == ResourceType_HardDisk) + throw OVFLogicError(N_("Error reading \"%s\": Disk item with instance ID %d specifies invalid host resource \"%s\", line %d"), + m_strPath.c_str(), + i.ulInstanceID, + i.strHostResource.c_str(), + i.ulLineNumber); vsys.mapVirtualDisks[vd.strDiskId] = vd; break; @@ -773,8 +790,8 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy } } } - else if ( (!strcmp(pcszElemName, "OperatingSystemSection")) - || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type")) + else if ( !strcmp(pcszElemName, "OperatingSystemSection") + || !strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type") ) { uint64_t cimos64; @@ -789,9 +806,9 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy vsys.strCimosDesc = pelmCIMOSDescription->getValue(); const xml::ElementNode *pelmVBoxOSType; - if ((pelmVBoxOSType = pelmThis->findChildElement("vbox", // namespace - "OSType"))) // element name - vsys.strTypeVbox = pelmVBoxOSType->getValue(); + if ((pelmVBoxOSType = pelmThis->findChildElementNS("vbox", // namespace + "OSType"))) // element name + vsys.strTypeVBox = pelmVBoxOSType->getValue(); } else if ( (!strcmp(pcszElemName, "AnnotationSection")) || (!strcmp(pcszTypeAttr, "ovf:AnnotationSection_Type")) @@ -807,6 +824,224 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy m_llVirtualSystems.push_back(vsys); } +void VirtualHardwareItem::fillItem(const xml::ElementNode *item) +{ + xml::NodesLoop loopItemChildren(*item);// all child elements + const xml::ElementNode *pelmItemChild; + while ((pelmItemChild = loopItemChildren.forAllNodes())) + { + const char *pcszItemChildName = pelmItemChild->getName(); + if (!strcmp(pcszItemChildName, "Description")) + strDescription = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "Caption")) + strCaption = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "ElementName")) + strElementName = pelmItemChild->getValue(); + else if ((!strcmp(pcszItemChildName, "InstanceID")) + ||(!strcmp(pcszItemChildName, "InstanceId")) + ) + pelmItemChild->copyValue(ulInstanceID); + else if (!strcmp(pcszItemChildName, "HostResource")) + strHostResource = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "ResourceType")) + { + uint32_t ulType; + pelmItemChild->copyValue(ulType); + resourceType = (ResourceType_T)ulType; + fResourceRequired = true; + const char *pcszAttValue; + if (item->getAttributeValue("required", pcszAttValue)) + { + if (!strcmp(pcszAttValue, "false")) + fResourceRequired = false; + } + } + else if (!strcmp(pcszItemChildName, "OtherResourceType")) + strOtherResourceType = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "ResourceSubType")) + strResourceSubType = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "AutomaticAllocation")) + fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false; + else if (!strcmp(pcszItemChildName, "AutomaticDeallocation")) + fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false; + else if (!strcmp(pcszItemChildName, "Parent")) + pelmItemChild->copyValue(ulParent); + else if (!strcmp(pcszItemChildName, "Connection")) + strConnection = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "Address")) + { + strAddress = pelmItemChild->getValue(); + pelmItemChild->copyValue(lAddress); + } + else if (!strcmp(pcszItemChildName, "AddressOnParent")) + strAddressOnParent = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "AllocationUnits")) + strAllocationUnits = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "VirtualQuantity")) + pelmItemChild->copyValue(ullVirtualQuantity); + else if (!strcmp(pcszItemChildName, "Reservation")) + pelmItemChild->copyValue(ullReservation); + else if (!strcmp(pcszItemChildName, "Limit")) + pelmItemChild->copyValue(ullLimit); + else if (!strcmp(pcszItemChildName, "Weight")) + pelmItemChild->copyValue(ullWeight); + else if (!strcmp(pcszItemChildName, "ConsumerVisibility")) + strConsumerVisibility = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "MappingBehavior")) + strMappingBehavior = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "PoolID")) + strPoolID = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "BusNumber")) + pelmItemChild->copyValue(ulBusNumber); +// else if (pelmItemChild->getPrefix() == NULL +// || strcmp(pelmItemChild->getPrefix(), "vmw")) +// throw OVFLogicError(N_("Unknown element \"%s\" under Item element, line %d"), +// pcszItemChildName, +// ulLineNumber); + } +} + +void VirtualHardwareItem::_checkConsistencyAndCompliance() RT_THROW(OVFLogicError) +{ + RTCString name = getItemName(); + if (ulInstanceID == 0) + throw OVFLogicError(N_("Element InstanceID is absent under %s element, line %d. " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); + if (resourceType == 0) + throw OVFLogicError(N_("Empty element ResourceType under %s element, line %d. " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); +} + +void StorageItem::fillItem(const xml::ElementNode *item) +{ + VirtualHardwareItem::fillItem(item); + + xml::NodesLoop loopItemChildren(*item);// all child elements + const xml::ElementNode *pelmItemChild; + while ((pelmItemChild = loopItemChildren.forAllNodes())) + { + const char *pcszItemChildName = pelmItemChild->getName(); + if (!strcmp(pcszItemChildName, "HostExtentName")) + strHostExtentName = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "OtherHostExtentNameFormat")) + strOtherHostExtentNameFormat = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "OtherHostExtentNameNamespace")) + strOtherHostExtentNameNamespace = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "VirtualQuantityUnits")) + strVirtualQuantityUnits = pelmItemChild->getValue(); + else if (!strcmp(pcszItemChildName, "Access")) + { + uint32_t temp; + pelmItemChild->copyValue(temp); + accessType = (StorageAccessType_T)temp; + } + else if (!strcmp(pcszItemChildName, "HostExtentNameFormat")) + { + } + else if (!strcmp(pcszItemChildName, "HostExtentNameNamespace")) + { + } + else if (!strcmp(pcszItemChildName, "HostExtentStartingAddress")) + { + } + else if (!strcmp(pcszItemChildName, "HostResourceBlockSize")) + { + int64_t temp; + pelmItemChild->copyValue(temp); + hostResourceBlockSize = temp; + } + else if (!strcmp(pcszItemChildName, "Limit")) + { + int64_t temp; + pelmItemChild->copyValue(temp); + limit = temp; + } + else if (!strcmp(pcszItemChildName, "Reservation")) + { + int64_t temp; + pelmItemChild->copyValue(temp); + reservation = temp; + } + else if (!strcmp(pcszItemChildName, "VirtualQuantity")) + { + int64_t temp; + pelmItemChild->copyValue(temp); + virtualQuantity = temp; + } + else if (!strcmp(pcszItemChildName, "VirtualResourceBlockSize")) + { + int64_t temp; + pelmItemChild->copyValue(temp); + virtualResourceBlockSize = temp; + } + } +} + + +void StorageItem::_checkConsistencyAndCompliance() RT_THROW(OVFLogicError) +{ + VirtualHardwareItem::_checkConsistencyAndCompliance(); + + RTCString name = getItemName(); + + if (accessType == StorageAccessType_Unknown) + { + //throw OVFLogicError(N_("Access type is unknown under %s element, line %d"), + // name.c_str(), ulLineNumber); + } + + if (hostResourceBlockSize <= 0 && reservation > 0) + { + throw OVFLogicError(N_("Element HostResourceBlockSize is absent under %s element, line %d. " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); + } + + if (virtualResourceBlockSize <= 0 && virtualQuantity > 0) + { + throw OVFLogicError(N_("Element VirtualResourceBlockSize is absent under %s element, line %d. " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); + } + + if (virtualQuantity > 0 && strVirtualQuantityUnits.isEmpty()) + { + throw OVFLogicError(N_("Element VirtualQuantityUnits is absent under %s element, line %d. " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); + } + + if (virtualResourceBlockSize <= 1 && + strVirtualQuantityUnits.compare(RTCString("count"), RTCString::CaseInsensitive) == 0 + ) + { + throw OVFLogicError(N_("Element VirtualQuantityUnits is set to \"count\" " + "while VirtualResourceBlockSize is set to 1. " + "under %s element, line %d. " + "It's needed to change on \"byte\". " + "see DMTF Schema Documentation %s"), + name.c_str(), ulLineNumber, DTMF_SPECS_URI); + } +} + +void EthernetPortItem::fillItem(const xml::ElementNode *item) +{ + VirtualHardwareItem::fillItem(item); + + xml::NodesLoop loopItemChildren(*item);// all child elements + const xml::ElementNode *pelmItemChild; + while ((pelmItemChild = loopItemChildren.forAllNodes())) + { + } +} + +void EthernetPortItem::_checkConsistencyAndCompliance() RT_THROW(OVFLogicError) +{ + VirtualHardwareItem::_checkConsistencyAndCompliance(); +} + //////////////////////////////////////////////////////////////////////////////// // // Errors -- cgit v1.2.1