summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/webservice
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/webservice')
-rw-r--r--src/VBox/Main/webservice/MANIFEST.MF.in28
-rw-r--r--src/VBox/Main/webservice/Makefile.kmk960
-rw-r--r--src/VBox/Main/webservice/Makefile.webtest94
-rw-r--r--src/VBox/Main/webservice/VBoxWebSrv.rc61
-rw-r--r--src/VBox/Main/webservice/platform-xidl.xsl96
-rw-r--r--src/VBox/Main/webservice/samples/java/axis/clienttest.java310
-rw-r--r--src/VBox/Main/webservice/samples/java/jax-ws/Makefile83
-rw-r--r--src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue72
-rw-r--r--src/VBox/Main/webservice/samples/java/jax-ws/clienttest.java339
-rw-r--r--src/VBox/Main/webservice/samples/java/jax-ws/metrictest.java231
-rwxr-xr-xsrc/VBox/Main/webservice/samples/perl/clienttest.pl232
-rw-r--r--src/VBox/Main/webservice/samples/php/clienttest.php108
-rw-r--r--src/VBox/Main/webservice/samples/python/Makefile39
-rw-r--r--src/VBox/Main/webservice/samples/python/Makefile.glue35
-rwxr-xr-xsrc/VBox/Main/webservice/samples/python/clienttest.py132
-rw-r--r--src/VBox/Main/webservice/soap-header-strip-inline.sed35
-rw-r--r--src/VBox/Main/webservice/soap-header-to-inline-source-file.sed38
-rw-r--r--src/VBox/Main/webservice/split-soapC.cpp236
-rw-r--r--src/VBox/Main/webservice/stdsoap2.sed31
-rw-r--r--src/VBox/Main/webservice/types.txt30
-rw-r--r--src/VBox/Main/webservice/vboxweb.cpp2518
-rw-r--r--src/VBox/Main/webservice/vboxweb.h376
-rw-r--r--src/VBox/Main/webservice/websrv-cpp.xsl1507
-rw-r--r--src/VBox/Main/webservice/websrv-nsmap.xsl148
-rw-r--r--src/VBox/Main/webservice/websrv-php.xsl647
-rw-r--r--src/VBox/Main/webservice/websrv-python.xsl923
-rw-r--r--src/VBox/Main/webservice/websrv-typemap.xsl165
-rw-r--r--src/VBox/Main/webservice/websrv-wsdl-service.xsl204
-rw-r--r--src/VBox/Main/webservice/websrv-wsdl.xsl1308
-rw-r--r--src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl308
-rw-r--r--src/VBox/Main/webservice/webtest.cpp572
31 files changed, 11866 insertions, 0 deletions
diff --git a/src/VBox/Main/webservice/MANIFEST.MF.in b/src/VBox/Main/webservice/MANIFEST.MF.in
new file mode 100644
index 00000000..3d04734c
--- /dev/null
+++ b/src/VBox/Main/webservice/MANIFEST.MF.in
@@ -0,0 +1,28 @@
+Manifest-Version: 1.0
+Bundle-Symbolicname: org.virtualbox@VBOX_API_SUFFIX@
+Bundle-Name: vboxjws
+Bundle-Vendor: VirtualBox
+Bundle-Version: @VBOX_VERSION_STRING@
+Bundle-License: http://glassfish.java.net/nonav/public/CDDL+GPL.html
+Bundle-ManifestVersion: 2
+Tool: vi+sed
+Export-Package: org.virtualbox@VBOX_API_SUFFIX@;uses="javax.jws.soap,
+ javax.xml,javax.xml.bind,javax.xml.bind.annotation,
+ javax.xml.bind.attachment,javax.xml.bind.helpers,javax.xml.bind.util,
+ javax,xml.namespace,javax.xml.parsers,javax.xml.stream,
+ javax.xml.transform,javax.xml.transform.dom,
+ javax.xml.transform.stream,javax.xml.ws,javax.xml.ws.handler,
+ javax.xml.ws.http,javax.xml.ws.soap,javax.xml.ws.spi,
+ javax.xml.ws.wsaddressing,org.w3c.dom,org.xml.sax";
+ version="@VBOX_VERSION_STRING@"
+Import-Package: javax.validation.constraints;version="1.0",
+ javax.jws,com.sun.xml.ws.developer,
+ com.sun.xml.ws,com.sun.xml.ws.api.message,javax.jws.soap,
+ javax.xml.namespace,javax.xml.ws,javax.xml.ws.spi,
+ 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.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
new file mode 100644
index 00000000..072d066e
--- /dev/null
+++ b/src/VBox/Main/webservice/Makefile.kmk
@@ -0,0 +1,960 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the VBox web service.
+#
+# Warning! This is a seriously complicated makefile!
+#
+
+#
+# Copyright (C) 2007-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+# Define VBOX_GSOAP_INSTALLED to something if you have gSOAP's
+# "wsdl2h" and "soapcpp2" executables on your PATH somewhere.
+
+#
+# Here's an overview how all this works. It's complicated. Essentially,
+# lots of files get generated automatically from our XML XIDL file that
+# describes the VirtualBox API (../idl/VirtualBox.xidl); as a result,
+# no manual coding is necessary when the API changes. All generated
+# web service code gets adjusted automatically.
+#
+# In more detail:
+#
+# 1) We use xsltproc and websrv-wsdl.xsl to generate a WSDL file from
+# our XML IDL file. WSDL (Web Service Description language) is an XML
+# industry standard that publicly describes a web service.
+# So, the WSDL generated here describes the VirtualBox web
+# service to third-party clients; for example, one can feed it to
+# Java or Perl or some other toolkit that understands WSDL and thus
+# easily write a short script that connects to the web service properly.
+# This WSDL file ends up in $(VBOXWEB_OUT_DIR)/vboxweb.wsdl.
+#
+# 2) We use xsltproc and websrv-wsdl2gsoapH.xsl to generate a so-called
+# "gSoap header file": $(VBOXWEB_OUT_DIR)/gsoapH_from_xslt.h from
+# the WSDL previously generated.
+# This file looks like a C header file, but really isn't meant
+# to be included by a C compiler. Instead, it just happens to be the
+# format that gSOAP uses to specify SOAP interfaces instead of WSDL.
+# (The reason for this appears to be that gSOAP predates WSDL and
+# thus needed some format to describe the syntax of a web service.)
+#
+# Note that gSOAP now also comes with its own WSDL-to-gsoap.h converter,
+# but the readme mentions some funny license restrictions, so instead we
+# have our own converter in XSLT.
+#
+# 3) We then feed that pseudo-header file to gSOAP's soapcpp2 compiler,
+# which generates a ton of files in $(VBOXWEB_OUT_DIR), most importantly:
+#
+# SOAP_CLIENT_H = $(VBOXWEB_OUT_DIR)/soapStub.h (header file for webservice clients)
+# SOAP_SERVER_H = $(VBOXWEB_OUT_DIR)/soapH.h (header file for webservice servers)
+#
+# These are "real" header files that one can use to program a) a webservice client
+# and b) a webservice server. Of course to build b) one will have to write method
+# implementations with useful code that does something. This is where more
+# code generation via XSLT comes in:
+#
+# 4) We use xsltproc to generate tons of C++ code directly from the XIDL that
+# maps each SOAP method to our COM methods. This large C++ file is
+# $(VBOXWEB_OUT_DIR)/methodmaps.cpp. The actual webservice executable (vboxwebsrv,
+# which acts as an HTTP server) is composed of this file, plus hard-coded
+# method implementations in vboxweb.cpp, plus gSOAP library code for the HTTP
+# server.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# Find the gSOAP toolkit.
+#
+# Note! We're not using the gSOAP toolkit correctly. The main issue is that
+# compiling soapcpp2.cpp instead of using the library. So, in order
+# to make this work with a locally installed gSOAP toolkit there are
+# some hoops to jump thru to say the least... Shipping soapcpp2.cpp/h
+# is out of the question without also including the two soap tools.
+#
+# Some observations on distros for OSE / configure:
+# The proposed gentoo ebuild screws up several things in the install phase
+# and thus fails to ship stdsoap2.cpp and relatives.
+#
+# debian (2.7.9l-0.2) stuffs stdsoap2.cpp and a handful of the import files
+# into /usr/include/gsoap.
+#
+# fedora (2.7.12-fc10.x86_64) uses the default install layout and does not
+# ship stdsoap2.cpp and friends.
+#
+ifeq ($(VBOX_GSOAP_INSTALLED),)
+ VBOX_GSOAP_INSTALLED = 1
+ VBOX_PATH_GSOAP := $(firstfile $(rversortfiles $(qwildcard ,$(KBUILD_DEVTOOLS)/common/gsoap/*)))
+ ifeq ($(VBOX_PATH_GSOAP),)
+ VBOX_PATH_GSOAP := $(firstfile $(rversortfiles $(qwildcard ,$(KBUILD_DEVTOOLS_HST)/gsoap/*)))
+ endif
+ if "$(VBOX_PATH_GSOAP)" == "" && defined(KBUILD_DEVTOOLS_HST)
+ VBOX_PATH_GSOAP := $(firstfile $(rversortfiles $(qwildcard ,$(KBUILD_DEVTOOLS_HST_ALT)/gsoap/*)))
+ endif
+ ifeq ($(VBOX_PATH_GSOAP),)
+ $(warning VBOX_PATH_GSOAP not found...)
+ VBOX_GSOAP_INSTALLED =
+ endif
+else
+ VBOX_PATH_GSOAP := $(VBOX_PATH_GSOAP)
+endif
+VBOX_PATH_GSOAP_BIN := $(strip $(VBOX_PATH_GSOAP_BIN))
+if "$(VBOX_PATH_GSOAP_BIN)" == ""
+ VBOX_PATH_GSOAP_BIN := $(VBOX_PATH_GSOAP)/bin
+ if "$(KBUILD_HOST)" == "darwin"
+ VBOX_PATH_GSOAP_BIN := $(VBOX_PATH_GSOAP_BIN)/macosx
+ else if "$(KBUILD_HOST)" == "win"
+ VBOX_PATH_GSOAP_BIN := $(VBOX_PATH_GSOAP_BIN)/win32
+ else
+ VBOX_PATH_GSOAP_BIN := $(VBOX_PATH_GSOAP_BIN)/$(KBUILD_HOST).x86
+ endif
+ if !exists($(VBOX_PATH_GSOAP_BIN))
+ VBOX_PATH_GSOAP_BIN := $(VBOX_PATH_GSOAP)/bin
+ endif
+endif
+VBOX_SOAPCPP2 := $(VBOX_PATH_GSOAP_BIN)/soapcpp2$(HOSTSUFF_EXE)
+VBOX_WSDL2H := $(VBOX_PATH_GSOAP_BIN)/wsdl2h$(HOSTSUFF_EXE)
+VBOX_STUBMAKER = $(firstword $(which stubmaker stubmaker.pl) stubmaker_not_found)
+# Keep in mind that Python ZSI only exists for Python 2.x, so this hardcodes
+# some things. If you want to build using Python 3.x only you need to disable
+# the creation of the Python webservice bindings anyway.
+if "$(KBUILD_HOST)" != "win"
+VBOX_WSDL2PY = $(firstword $(which wsdl2py) wsdl2py_not_found)
+else
+VBOX_WSDL2PY = $(firstword $(wildcard C:/Python27/Scripts/wsdl2py.exe) wsdl2py_not_found)
+endif
+
+VBOX_PATH_GSOAP_IMPORT := $(strip $(if $(VBOX_PATH_GSOAP_IMPORT),$(VBOX_PATH_GSOAP_IMPORT),$(VBOX_PATH_GSOAP)/import))
+VBOX_GSOAP_INCS := $(strip $(if $(VBOX_GSOAP_INCS),$(VBOX_GSOAP_INCS),$(VBOX_PATH_GSOAP) $(VBOX_PATH_GSOAP_IMPORT) ))
+# note: $(if $(defined FOO)) does not work here!
+VBOX_GSOAP_CXX_SOURCES := $(strip $(if-expr "$(origin VBOX_GSOAP_CXX_SOURCES)" != "undefined",$(VBOX_GSOAP_CXX_SOURCES),$(VBOX_PATH_GSOAP)/stdsoap2.cpp))
+VBOX_GSOAP_CXX_LIBS := $(strip $(if-expr "$(origin VBOX_GSOAP_CXX_LIBS)" != "undefined",$(VBOX_GSOAP_CXX_LIBS),))
+
+
+#
+# Globals
+#
+VBOXWEB_OUT_DIR := $(PATH_TARGET)/webservice
+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)
+
+PATH_TARGET_SOAPDEMOXML := $(VBOXWEB_OUT_DIR)/demo_soapxml
+PATH_TARGET_SOAPDEMOHEADERS := $(VBOXWEB_OUT_DIR)/demo_headers
+PATH_TARGET_SOAPDEMONSMAPS := $(VBOXWEB_OUT_DIR)/demo_namespacemaps
+PATH_TARGET_WEBTEST := $(VBOXWEB_OUT_DIR)/webtest
+
+# the original XIDL file (has to include documentation as we need it):
+VBOXWEB_IDL_SRC_ORIG := $(VBOX_XIDL_FILE_SRC)
+# the original XIDL file without documentation
+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 = $(VBOXWEB_OUT_DIR)/vboxweb.wsdl
+VBOXWEBSERVICE_WSDL = $(VBOXWEB_OUT_DIR)/vboxwebService.wsdl
+
+VBOXWEB_TYPEMAP := $(VBOXWEB_OUT_DIR)/typemap.dat
+
+VBOXWEB_GSOAPH_FROM_XSLT := $(VBOXWEB_OUT_DIR)/gsoapH_from_xslt.h
+ifdef VBOX_GSOAP_INSTALLED
+ VBOXWEB_GSOAPH_FROM_GSOAP := $(VBOXWEB_OUT_DIR)/gsoapH_from_gsoap.h
+else
+ VBOXWEB_GSOAPH_FROM_GSOAP :=
+endif
+VBOXWEB_SOAP_CLIENT_H := $(VBOXWEB_OUT_DIR)/soapStub.h
+VBOXWEB_SOAP_SERVER_H := $(VBOXWEB_OUT_DIR)/soapH.h
+
+
+ifdef VBOX_GSOAP_VERBOSE
+ VBOXWEB_XSLTPROC_VERBOSE = --stringparam G_argDebug '1'
+ VBOXWEB_WSDL_VERBOSE = -v
+else
+ VBOXWEB_SOAPCPP2_SKIP_FILES = -x
+endif
+
+
+## @todo VBOXWEB_GSOAPH_FROM_XSLT should probably be a indirect dep of something.
+VBOXWEB_OTHERS += \
+ $(VBOXWEB_GSOAPH_FROM_XSLT)
+
+
+# GCC 9.2 doesn't cope ver well with the split soapC.cpp files (internal error).
+# Seemingly, the issue goes away when we strip inline functions from soapH.h.
+ifdef VBOX_WITHOUT_NOINLINE_SOAPH
+ if !defined(VBOX_WITHOUT_SPLIT_SOAPC) && !defined(VBOX_WITH_SPLIT_SOAPC) && $(VBOX_GCC_VERSION_CXX) >= 90200
+ $(info Triggering VBOX_WITHOUT_SPLIT_SOAPC because of VBOX_GCC_VERSION_CXX=$(VBOX_GCC_VERSION_CXX) and VBOX_WITHOUT_NOINLINE_SOAPH)
+ VBOX_WITHOUT_SPLIT_SOAPC := 1
+ endif
+endif
+
+# disable -fvisibility=hidden as the SOAP stuff does not properly set the visibility attributes
+TEMPLATE_VBOXWEBR3EXE = Webservices without -fvisibility
+TEMPLATE_VBOXWEBR3EXE_EXTENDS = VBOXR3EXE
+TEMPLATE_VBOXWEBR3EXE_DEFS.win += WIN32_LEAN_AND_MEAN $(TEMPLATE_VBOXR3EXE_DEFS.win) # Makes the redefinition warnings go away.
+TEMPLATE_VBOXWEBR3EXE_CXXFLAGS = $(filter-out $(VBOX_GCC_fvisibility-hidden) $(VBOX_GCC_fvisibility-inlines-hidden),\
+ $(TEMPLATE_VBOXR3EXE_CXXFLAGS))
+ifn1of ($(KBUILD_TARGET), win)
+TEMPLATE_VBOXWEBR3EXE_CXXFLAGS += $(VBOX_GCC_Wno-misleading-indentation)
+endif
+if "$(VBOX_VCC_TOOL_STEM)" >= "VCC140"
+ # -wd4774: string(532): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal
+ # -wd4458: stdsoap2.h(2644): warning C4458: declaration of 'type' hides class member
+ # -wd5039: x509v3.h(883): warning C5039: 'OPENSSL_sk_set_cmp_func': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception.
+ # soapc-1.cpp(182) : warning C4883: 'soap_getelement': function size suppresses optimizations
+ TEMPLATE_VBOXWEBR3EXE_CXXFLAGS.win = $(TEMPLATE_VBOXR3EXE_CXXFLAGS.win) -wd4774 -wd4458 -wd4883 -wd5039
+endif
+
+ifdef VBOX_GSOAP_INSTALLED
+ ifndef VBOX_ONLY_SDK
+ #
+ # soapC and soapH-noinline file splitter.
+ #
+ BLDPROGS += split-soapC
+ split-soapC_TEMPLATE = VBoxBldProg
+ split-soapC_SOURCES = split-soapC.cpp
+
+ #
+ # vboxsoap - Library used by both the programs (save build time).
+ #
+ LIBRARIES += vboxsoap
+ vboxsoap_TEMPLATE = VBOXWEBR3EXE
+ ifndef VBOX_WITHOUT_PRECOMPILED_HEADERS
+ ifeq ($(KBUILD_TARGET),win)
+ vboxsoap_USES = vccprecomp
+ vboxsoap_PCH_HDR := $(VBOXWEB_SOAP_SERVER_H)
+ vboxsoap_CXXFLAGS += -Zm127
+ endif
+ endif
+ vboxsoap_CXXFLAGS += $(VBOX_C_CXX_FLAGS_NO_UNUSED_PARAMETERS)
+ vboxsoap_CXXFLAGS.win += -bigobj
+ vboxsoap_CXXFLAGS.win += -wd4702 # soapc-4.cpp(16) : warning C4702: unreachable code
+ ifn1of ($(KBUILD_TARGET), win)
+ vboxsoap_CXXFLAGS += -Wno-shadow -Wno-parentheses $(VBOX_GCC_Wno-literal-suffix) \
+ $(VBOX_GCC_Wno-stringop-overflow) $(VBOX_GCC_Wno-stringop-truncation) \
+ $(VBOX_GCC_Wno-vla) -Wno-format -Wno-deprecated-declarations $(VBOX_GCC_fno-printf-return-value)
+ ifn1of ($(KBUILD_TYPE), debug) # Save time+memory by using -O0 instead of -O2.
+ vboxsoap_CXXFLAGS += -O0 ## @todo this could be interesting for g++ (not clang++): -fcprop-registers
+ endif
+ endif
+ vboxsoap_INCS := \
+ $(VBOX_GSOAP_INCS) \
+ $(VBOXWEB_OUT_DIR) \
+ $(PATH_SUB_CURRENT)
+ ifdef VBOX_WITH_WEBSERVICES_SSL
+ vboxsoap_DEFS += WITH_OPENSSL
+ vboxsoap_SDKS += VBOX_OPENSSL2
+ endif
+ ifdef VBOX_WITHOUT_SPLIT_SOAPC
+ vboxsoap_SOURCES = \
+ $(VBOXWEB_OUT_DIR)/soapC.cpp
+ else
+ vboxsoap_SOURCES = \
+ $(VBOXWEB_OUT_DIR)/soapC-1.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-2.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-3.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-4.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-5.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-6.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-7.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-8.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-9.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-10.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-11.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-12.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-13.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-14.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-15.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-16.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-17.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-18.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-19.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-20.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-21.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-22.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-23.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-24.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-25.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-26.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-27.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-28.cpp \
+ $(VBOXWEB_OUT_DIR)/soapC-29.cpp
+ endif
+ ifndef VBOX_WITHOUT_NOINLINE_SOAPH
+ vboxsoap_SOURCES += \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-1.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-2.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-3.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-4.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-5.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-6.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-7.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-8.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-9.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-10.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-11.cpp \
+ $(VBOXWEB_OUT_DIR)/soapH-noinline-12.cpp
+ endif
+ vboxsoap_CLEAN := $(vboxsoap_SOURCES) # lazy bird
+ vboxsoap_SOURCES <= \
+ $(VBOX_GSOAP_CXX_SOURCES)
+ vboxsoap_ORDERDEPS = \
+ $(VBOXWEB_IDL_SRC) \
+ $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts
+ ifn1of ($(KBUILD_TARGET), win)
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS = \
+ -Wno-format \
+ $(VBOX_GCC_Wno-int-in-bool-context) \
+ $(VBOX_GCC_Wno-logical-op)
+ # currently necessary when compiling against OpenSSL 1.0 due to a missing
+ # typecase from 'const v3_ext_method*' to 'aka v3_ext_method*'.
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS += -fpermissive
+ # Necessary with gcc 9.2.1 for some reason:
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS += -Wno-deprecated-declarations
+ endif
+
+ if "$(KBUILD_TARGET)" == "win" && "$(VBOX_GSOAP_CXX_SOURCES)" != ""
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4668 # preprocessor / windows.h
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4211 # nonstandard extension used: redefined extern to static
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4310 # cast truncates constant value
+ if1of ($(VBOX_VCC_TOOL_STEM), VCC120)
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4056 # v2.8.36/stdsoap2.cpp(14008) : warning C4056: overflow in floating-point constant arithmetic
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4756 # v2.8.36/stdsoap2.cpp(14008) : warning C4756: overflow in constant arithmetic
+ endif
+ if "$(VBOX_VCC_TOOL_STEM)" >= "VCC140"
+ $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS.win += -wd4456 # stdsoap2.cpp(3127): warning C4456: declaration of 'i' hides previous local declaration
+ endif
+ endif
+
+ ifdef VBOX_SOAP_PRECOMPILED_HEADER
+ # This'll save a few seconds, but the compiler invocation currently makes it impracticable. This will
+ # be addressed in a future kBuild version, by adding PCH support or/and by adding some helpers to
+ # gather the required data (DEFS,INCS,CXXTOOL,CXXFLAGS).
+ vboxsoap_INTERMEDIATES += $(VBOXWEB_OUT_DIR)/soapH.h.gch
+ vboxsoap_CXXFLAGS += -Winvalid-pch -H
+ vboxsoap_CLEAN += $(VBOXWEB_OUT_DIR)/soapH.h.gch
+
+ $(VBOXWEB_OUT_DIR)/soapH.h.gch: $(VBOXWEB_OUT_DIR)/soapH.h
+ g++ -x c++-header -g -g -Wall -pedantic -Wno-long-long -Wno-trigraphs -Wno-variadic-macros -pipe -O0 -fno-omit-frame-pointer \
+ -fno-strict-aliasing -fvisibility-inlines-hidden -fvisibility=hidden -DVBOX_HAVE_VISIBILITY_HIDDEN \
+ -mmacosx-version-min=10.4 -isysroot /Developer/SDKs/MacOSX10.4u.sdk -m32 \
+ -I/Volumes/ScratchHFS/bird/vbox/svn/trunk/src/VBox/Main/webservice/gsoap \
+ -I/Volumes/ScratchHFS/bird/vbox/svn/trunk/out/darwin.x86/debug/obj/src/VBox/Main \
+ -I/Volumes/ScratchHFS/bird/vbox/svn/trunk/src/VBox/Main/webservice \
+ -I/Volumes/ScratchHFS/bird/vbox/svn/trunk/include -I/Volumes/ScratchHFS/bird/vbox/svn/trunk/out/darwin.x86/debug
+ \-DVBOX -DVBOX_WITH_DEBUGGER -DVBOX_WITH_DEBUGGER_GUI -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_DARWIN \
+ -D__DARWIN__ -DRT_ARCH_X86 -D__X86__ -DVBOX_WITH_HYBRID_32BIT_KERNEL -DIN_RING3 -DHC_ARCH_BITS=32 -DGC_ARCH_BITS=32 \
+ -DMAC_OS_X_VERSION_MIN_REQUIRED=1040 -DMAC_OS_X_VERSION_MAX_ALLOWED=1040 \
+ $< -o $@
+ endif
+
+ # Tweak for systems with too many CPUs compared to memory.
+ ifdef VBOX_WITH_SOAP_NOT_PARALLEL
+ .NOTPARALLEL: $$(vboxsoap_2_OBJS)
+ endif
+ endif # !VBOX_ONLY_SDK
+
+
+ ifndef VBOX_ONLY_SDK
+ #
+ # vboxwebsrv - webservice server process
+ #
+ PROGRAMS += vboxwebsrv
+ vboxwebsrv_TEMPLATE = VBOXMAINCLIENTEXE
+ vboxwebsrv_DEFS += SOCKET_CLOSE_ON_EXEC
+ vboxwebsrv_DEFS.win += WIN32_LEAN_AND_MEAN
+ vboxwebsrv_INCS = \
+ $(VBOX_GSOAP_INCS) \
+ $(VBOXWEB_OUT_DIR) \
+ .
+ vboxwebsrv_CXXFLAGS.win += -bigobj
+ if "$(VBOX_VCC_TOOL_STEM)" >= "VCC140"
+ vboxwebsrv_CXXFLAGS.win += -wd4774 # string(532): warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal
+ vboxwebsrv_CXXFLAGS.win += -wd4458 # stdsoap2.h(2644): warning C4458: declaration of 'type' hides class member
+ vboxwebsrv_CXXFLAGS.win += -wd5039 # x509v3.h(883): warning C5039: 'OPENSSL_sk_set_cmp_func': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception.
+ endif
+ ifn1of ($(KBUILD_TARGET), win)
+ vboxwebsrv_CXXFLAGS += -Wno-shadow $(VBOX_GCC_Wno-literal-suffix) $(VBOX_GCC_Wno-misleading-indentation)
+ ifn1of ($(KBUILD_TYPE), debug) # Save time+memory by using -O1 instead of -O2.
+ vboxwebsrv_CXXFLAGS += -O0
+ endif
+ endif
+ vboxwebsrv_LIBS += \
+ $(PATH_STAGE_LIB)/vboxsoap$(VBOX_SUFF_LIB) \
+ $(VBOX_GSOAP_CXX_LIBS) \
+ $(LIB_RUNTIME)
+ vboxwebsrv_LIBS.solaris += socket nsl
+ ifdef VBOX_WITH_WEBSERVICES_SSL
+ vboxwebsrv_DEFS += WITH_OPENSSL
+ vboxwebsrv_SDKS += VBOX_OPENSSL2
+ endif
+ vboxwebsrv_SOURCES = \
+ vboxweb.cpp \
+ $(VBOXWEB_OUT_DIR)/methodmaps.cpp \
+ $(VBOXWEB_OUT_DIR)/soapServer.cpp \
+ $(VBOXWEB_OUT_DIR)/vboxweb-wsdl.c
+ vboxwebsrv_SOURCES.win = \
+ VBoxWebSrv.rc
+ vboxwebsrv_CLEAN = \
+ $(VBOXWEB_OUT_DIR)/methodmaps.cpp \
+ $(VBOXWEB_OUT_DIR)/soapServer.cpp \
+ $(VBOXWEB_OUT_DIR)/vboxweb-wsdl.c
+ vboxwebsrv_ORDERDEPS = $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts
+ endif # !VBOX_ONLY_SDK
+
+ ifdef VBOX_WITH_JWS
+INSTALLS += VBoxJWs-inst-jar
+
+#
+# Java glue JAR files
+#
+VBOX_JWS_JAR = $(VBoxJWs-inst-jar_0_OUTDIR)/vboxjws.jar
+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
+VBOX_JAXLIB_DIR := $(PATH_ROOT)/src/VBox/Main/webservice/jaxlibs
+
+VBoxJWs-inst-jar_INST = $(INST_SDK)bindings/webservice/java/jax-ws/
+VBoxJWs-inst-jar_MODE = a+r,u+w
+VBoxJWs-inst-jar_SOURCES = \
+ $(VBOX_JWS_JAR) \
+ $(VBOX_JWSDOC_JAR) \
+ $(VBOX_JWSSRC_JAR)
+VBoxJWs-inst-jar_CLEAN = \
+ $(VBOX_JWS_JAR) \
+ $(VBOX_JWSDOC_JAR) \
+ $(VBOX_JWSSRC_JAR) \
+ $(VBOX_JWS_GEN)/jwsglue.list \
+ $(VBOX_JWSDOC_JDEST)/package-list \
+ $(wildcard \
+ $(VBOX_JWS_GEN)/java/*/*/*.java \
+ $(VBOX_JWS_GEN)/java/*/*/*/*.java \
+ $(VBOX_JWS_JDEST)/*.class \
+ $(VBOX_JWS_JDEST)/*/*.class \
+ $(VBOX_JWS_JDEST)/*/*/*.class \
+ $(VBOX_JWS_JDEST)/*/*/*/*.class \
+ $(VBOX_JWSDOC_JDEST)/*.html \
+ $(VBOX_JWSDOC_JDEST)/*.css \
+ $(VBOX_JWSDOC_JDEST)/*/*.gif \
+ $(VBOX_JWSDOC_JDEST)/*/*/*.html \
+ $(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)
+
+$(VBoxJWSGlue_KMK).ts +| $(VBoxJWSGlue_KMK): $(VBOXWEB_IDL_SRC_ORIG) $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $(VBOX_VERSION_STAMP)
+ $(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) \
+ $(VBOX_VERSION_STAMP)
+ $(call MSG_L1,Generating JAX-WS Java glue files from XIDL)
+ $(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_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_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 $(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,)
+ $(QUIET)$(RM) -Rf $(VBOX_JWS_JDEST)
+ $(QUIET)$(MKDIR) -p $(VBOX_JWS_JDEST)
+ $(call MSG_L1,Compiling bridge code)
+ $(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) $(VBOX_JAVA_WS_OPTS) \
+ @$(VBOX_JWS_GEN)/jwsglue.list \
+ -d $(VBOX_JWS_JDEST) -classpath $(VBOX_JWS_JDEST)$(VBOX_SEP)$(VBOX_JAVA_WS_EXTRA_JARS)
+ $(QUIET)$(SED) -e "s/vboxweb.wsdl/vboxweb$(VBOX_API_SUFFIX).wsdl/" < $(VBOXWEBSERVICE_WSDL) > $(VBOX_JWS_JDEST)/vboxwebService$(VBOX_API_SUFFIX).wsdl
+ $(QUIET)$(CP) -f $(VBOXWEB_WSDL) $(VBOX_JWS_JDEST)/vboxweb$(VBOX_API_SUFFIX).wsdl
+ $(call MSG_LINK,$(notdir $@),$@)
+ $(VBOX_JAR) cfm $@ $(VBOX_JWS_GEN)/MANIFEST.MF -C $(VBOX_JWS_JDEST) .
+
+$(VBOX_JWS_GEN)/MANIFEST.MF: $(VBOX_PATH_WEBSERVICE)/MANIFEST.MF.in
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(VBOX_JWS_GEN)
+ $(QUIET)$(SED) \
+ -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/' \
+ -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/' \
+ -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/' \
+ -e 's/@VBOX_API_SUFFIX@/$(VBOX_API_SUFFIX)/' \
+ < $< > $@
+
+$$(VBOX_JWSDOC_JAR): $(VBOX_JWS_GEN)/jwsglue.list $$(VBoxJWs-inst-jar_GENERATEDSOURCES) $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL) $$(VBOX_JWS_JAR) | $$(dir $$@)
+ $(call MSG_TOOL,javadoc,$(notdir $@),jwsgen.list,)
+ $(QUIET)$(RM) -Rf $(VBOX_JWSDOC_JDEST)
+ $(QUIET)$(MKDIR) -p $(VBOX_JWSDOC_JDEST)
+ $(call MSG_L1,Generating javadoc html documentation)
+ $(VBOX_JAVADOC) $(VBOX_JAVADOC_OPTS) $(VBOX_JAVA_WS_OPTS) -quiet \
+ -sourcepath $(VBOX_JWS_GEN)/java org.virtualbox$(VBOX_API_SUFFIX) \
+ -d $(VBOX_JWSDOC_JDEST) -classpath $(VBOX_SEP)$(VBOX_JAVA_WS_EXTRA_JARS)
+ $(call MSG_LINK,$(notdir $@),$@)
+ $(VBOX_JAR) cf $@ -C $(VBOX_JWSDOC_JDEST) .
+
+$$(VBOX_JWSSRC_JAR): $$(VBOX_JWS_JAR) | $$(dir $$@)
+ $(call MSG_LINK,$(notdir $@),$@)
+ $(VBOX_JAR) cf $@ -C $(VBOX_JWS_GEN)/java .
+
+## @todo compile ../glue/tests/TestVBox.java to have sanity checking
+
+ endif # VBOX_WITH_JWS
+
+ ifndef VBOX_ONLY_SDK
+ #
+ # webtest - webservice sample client in C++
+ #
+ PROGRAMS += webtest
+ webtest_TEMPLATE = VBOXWEBR3EXE
+ webtest_CXXFLAGS.win += -bigobj
+ ifn1of ($(KBUILD_TARGET), win)
+ webtest_CXXFLAGS += -Wno-shadow
+ endif
+ webtest_INCS := \
+ $(VBOX_GSOAP_INCS) \
+ $(VBOXWEB_OUT_DIR) \
+ .
+ webtest_LIBS += \
+ $(PATH_STAGE_LIB)/vboxsoap$(VBOX_SUFF_LIB) \
+ $(VBOX_GSOAP_CXX_LIBS) \
+ $(LIB_RUNTIME)
+ webtest_LIBS.solaris += nsl
+ ifdef VBOX_WITH_WEBSERVICES_SSL
+ webtest_DEFS += WITH_OPENSSL
+ webtest_SDKS += VBOX_OPENSSL2
+ endif
+ webtest_SOURCES = \
+ webtest.cpp \
+ $(VBOXWEB_OUT_DIR)/soapClient.cpp
+ webtest_CLEAN = \
+ $(VBOXWEB_OUT_DIR)/soapClient.cpp
+
+ webtest_ORDERDEPS = $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts
+ endif # !VBOX_ONLY_SDK
+
+
+ #
+ # Additional mess to cleanup (applies to both webtest and vboxwebsrv).
+ #
+ ## @todo figure out whether the SDK really needs this or not...
+ OTHER_CLEAN += \
+ $(wildcard $(VBOXWEB_OUT_DIR)/soap*.h) \
+ $(wildcard $(VBOXWEB_OUT_DIR)/soap*.cpp) \
+ $(wildcard $(VBOXWEB_OUT_DIR)/*.nsmap) \
+ $(VBOXWEB_GSOAPH_FROM_XSLT) \
+ $(VBOXWEB_GSOAPH_FROM_GSOAP) \
+ $(VBOXWEB_SOAP_CLIENT_H) \
+ $(VBOXWEB_SOAP_SERVER_H) \
+ $(VBOXWEB_OUT_DIR)/gsoap_generate_all_ts \
+ $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts \
+ $(wildcard $(PATH_TARGET_SOAPDEMOXML)/*) \
+ $(PATH_TARGET_SOAPDEMOXML)/dummy_file \
+ $(wildcard $(PATH_TARGET_SOAPDEMOHEADERS)/*) \
+ $(PATH_TARGET_SOAPDEMOHEADERS)/dummy_file \
+ $(wildcard $(PATH_TARGET_SOAPDEMONSMAPS)/*) \
+ $(PATH_TARGET_SOAPDEMONSMAPS)/dummy_file
+
+endif # VBOX_GSOAP_INSTALLED
+
+
+if defined(VBOX_ONLY_SDK) && ("$(KBUILD_TARGET)" != "win" || defined(VBOX_FORCE_SDK))
+ #
+ # Globals relevant to the SDK.
+ #
+ VBOXWEB_GLUE_PYTHON = $(VBOX_PATH_SDK)/bindings/webservice/python/lib/VirtualBox_wrappers.py
+ # The following 3 files are generated by Python ZSI 2.1_a1 (alpha version
+ # shipped by many Linux distributions). Only the first two are actually used.
+ # The 4th and 5th file is created by ZSI 2.0 (released in 2007), and gets
+ # renamed to the 1st/2nd file for simplicity reasons.
+ # ZSI 1.x used different file names. Not worth supporting any more. If you're
+ # curious, check the VirtualBox 4.3 sources.
+ VBOXWEB_WS_PYTHON = $(VBOX_PATH_SDK)/bindings/webservice/python/lib/VirtualBox_client.py
+ VBOXWEB_WS_PYTHON_TYPES = $(VBOX_PATH_SDK)/bindings/webservice/python/lib/VirtualBox_types.py
+ VBOXWEB_WS_PYTHON_SERVER = $(VBOX_PATH_SDK)/bindings/webservice/python/lib/VirtualBox_server.py
+ VBOXWEB_WS_PYTHON_ALTERNATIVE = $(VBOX_PATH_SDK)/bindings/webservice/python/lib/VirtualBox_services.py
+ VBOXWEB_WS_PERL = $(VBOX_PATH_SDK)/bindings/webservice/perl/lib/vboxService.pm
+ VBOXWEB_WS_PHP = $(VBOX_PATH_SDK)/bindings/webservice/php/lib/vboxServiceWrappers.php
+ VBOXWEB_SAMPLES_JAXWS_DIR = $(VBOX_PATH_SDK)/bindings/webservice/java/jax-ws/samples
+ VBOXWEB_JAXWSSAMPLE = $(VBOXWEB_SAMPLES_JAXWS_DIR)/clienttest.java
+ VBOXWEB_METRICSAMPLE = $(VBOXWEB_SAMPLES_JAXWS_DIR)/metrictest.java
+
+ define find_java_files
+ $(shell find $(1) -name \*.java)
+ endef
+
+ VBOXWEB_OTHERS += \
+ $(if $(VBOX_WITH_PYTHON),$(VBOXWEB_GLUE_PYTHON),) \
+ $(if $(VBOX_WITH_PYTHON),$(VBOXWEB_WS_PYTHON),) \
+ $(if $(VBOX_WITH_PYTHON),$(VBOXWEB_WS_PYTHON_TYPES),) \
+ $(if $(VBOX_WITH_PERL),$(VBOXWEB_WS_PERL),) \
+ $(if $(VBOX_WITH_PHP),$(VBOXWEB_WS_PHP),)
+
+
+ #
+ # Install sample code.
+ #
+ INSTALLS += vboxwebinst
+ vboxwebinst_INST = $(INST_SDK)bindings/webservice/
+ vboxwebinst_MODE = a+rx,u+w
+ vboxwebinst_SOURCES = \
+ $(if $(VBOX_WITH_PERL),samples/perl/clienttest.pl=>perl/samples/clienttest.pl,) \
+ $(if $(VBOX_WITH_PHP),samples/php/clienttest.php=>php/samples/clienttest.php,) \
+ $(if $(VBOX_WITH_PYTHON),samples/python/clienttest.py=>python/samples/clienttest.py,)
+
+ INSTALLS += vboxwebinst_nox
+ vboxwebinst_nox_INST = $(INST_SDK)bindings/webservice/
+ vboxwebinst_nox_MODE = a+r,u+w
+ vboxwebinst_nox_SOURCES = \
+ $(if $(VBOX_WITH_PYTHON),samples/python/Makefile=>python/samples/Makefile,) \
+ $(if $(VBOX_WITH_PYTHON),samples/python/Makefile.glue=>python/lib/Makefile,) \
+ $(if ($VBOX_WITH_JWS),$(PATH_ROOT)/COPYING.LIB=>java/jax-ws/COPYING.LIB,)
+
+ 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
+
+ INSTALLS += vboxwebinst_webtest
+ vboxwebinst_webtest_INST = $(INST_SDK)bindings/webservice/
+ vboxwebinst_webtest_MODE = a+r,u+w
+ vboxwebinst_webtest_SOURCES = \
+ $(VBOX_PATH_WEBSERVICE)/websrv-wsdl2gsoapH.xsl=>xsl/websrv-wsdl2gsoapH.xsl \
+ $(VBOX_PATH_WEBSERVICE)/websrv-nsmap.xsl=>xsl/websrv-nsmap.xsl \
+ $(VBOX_PATH_IDL)/typemap-shared.inc.xsl=>idl/typemap-shared.inc.xsl \
+ $(VBOX_PATH_WEBSERVICE)/split-soapC.cpp=>tools/split-soapC.cpp \
+ $(VBOX_PATH_WEBSERVICE)/webtest.cpp=>cpp/samples/webtest/webtest.cpp \
+ $(VBOX_PATH_WEBSERVICE)/Makefile.webtest=>cpp/samples/webtest/Makefile
+
+endif # VBOX_ONLY_SDK
+
+#
+# Update the OTHERS and OTHER_CLEAN lists with VBOXWEB_OTHERS and some more stuff.
+#
+# We can't just built up OTHERS and append it to OTHER_CLEAN because we're sharing
+# OTHERS with all the other VBox makefiles, thus VBOXWEB_OTHERS.
+#
+OTHERS += $(VBOXWEB_OTHERS)
+OTHER_CLEAN += \
+ $(VBOXWEB_OTHERS) \
+ $(if $(VBOX_WITH_PYTHON),$(VBOXWEB_WS_PYTHON_SERVER),) \
+ $(VBOXWEB_WSDL) \
+ $(VBOXWEBSERVICE_WSDL) \
+ $(VBOXWEB_TYPEMAP) \
+ $(VBOXWEB_IDL_SRC)
+
+# generate platform-specific XIDL file from original XIDL file
+$(VBOXWEB_IDL_SRC): $(VBOXWEB_IDL_SRC_STRIPPED) $(VBOX_PATH_WEBSERVICE)/platform-xidl.xsl | $$(dir $$@)
+ $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using platform-xidl.xsl)
+ $(QUIET)$(RM) -f -- $@
+ $(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_IDL)/typemap-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@)
+ $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-wsdl.xsl)
+ $(QUIET)$(RM) -f -- $@
+ $(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_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)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-wsdl-service.xsl $<
+
+ifdef VBOX_ONLY_SDK
+
+$(VBOXWEB_GLUE_PYTHON): $(VBOXWEB_IDL_SRC) $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL) $(VBOX_PATH_WEBSERVICE)/websrv-python.xsl
+ $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-python.xsl)
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(@D)
+ $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(VBOX_PATH_WEBSERVICE)/websrv-python.xsl $<
+
+$(VBOXWEB_WS_PYTHON) \
++ $(VBOXWEB_WS_PYTHON_TYPES): $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL)
+ $(call MSG_GENERATE,,$@, WS Python bindings)
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(@D)
+# Change directory to the "source", as otherwise ZSI 2.0 has trouble finding
+# the 2nd WSDL file included in the main one. ZSI 2.1 is smarter, but some
+# versions floating around (especially on Linux) lack the --file option.
+if "$(KBUILD_HOST)" != "win"
+ $(QUIET)$(REDIRECT) -C $(dir $(VBOXWEBSERVICE_WSDL)) -- $(SHELL) -c "$(VBOX_WSDL2PY) -b --output-dir $(@D) $(VBOXWEBSERVICE_WSDL) || $(VBOX_WSDL2PY) -b --file $(VBOXWEBSERVICE_WSDL) --output-dir $(@D)"
+else
+ $(QUIET)$(REDIRECT) -C $(dir $(VBOXWEBSERVICE_WSDL)) -- $(VBOX_WSDL2PY) -b --file $(subst /,\\\\,$(VBOXWEBSERVICE_WSDL)) --output-dir $(@D)
+endif
+# Hack: some wsdl2py versions generate VirtualBox_client.py, some generate
+# VirtualBox_services.py. Standardize on the former.
+ -$(QUIET)$(MV) -f $(VBOXWEB_WS_PYTHON_ALTERNATIVE) $(VBOXWEB_WS_PYTHON)
+# We do not ever need the VirtualBox_server.py file. Delete it immediately
+# so that it will not get packaged in the SDK.
+ $(QUIET)$(RM) -f -- $(VBOXWEB_WS_PYTHON_SERVER)
+ $(QUIET)$(APPEND) $@ ''
+
+$(VBOXWEB_WS_PERL): $(VBOXWEB_WSDL) $(VBOXWEBSERVICE_WSDL)
+ $(call MSG_GENERATE,,$@, WS Perl bindings)
+ $(QUIET)$(MKDIR) -p $(@D)
+ $(QUIET)$(REDIRECT) -C $(@D) -- $(VBOX_STUBMAKER) file://$(VBOXWEBSERVICE_WSDL)
+# Ugly, ugly, ugly, make me right once
+ $(QUIET)$(SED) -e "s+http://www.virtualbox.org/Service+http://www.virtualbox.org/+" --output $(VBOXWEB_WS_PERL).tmp $(VBOXWEB_WS_PERL)
+ $(QUIET)$(MV) $(VBOXWEB_WS_PERL).tmp $(VBOXWEB_WS_PERL)
+ $(QUIET)$(APPEND) $@ ''
+
+$(VBOXWEB_WS_PHP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/websrv-php.xsl
+ $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using websrv-php.xsl)
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(@D)
+ $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) -o $@ $(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_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_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_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 $<
+
+ifdef VBOX_GSOAP_INSTALLED
+# ... and once with the gSOAP tool (just for comparison, we don't use it for licensing reasons)
+$(VBOXWEB_GSOAPH_FROM_GSOAP): $(VBOXWEB_WSDL) $(VBOXWEB_TYPEMAP) | $$(dir $$@)
+ $(call MSG_GENERATE,,$@,)
+ $(QUIET)$(RM) -f -- $@
+ $(VBOX_WSDL2H) $(VBOXWEB_WSDL_VERBOSE) -t$(VBOXWEB_TYPEMAP) -nvbox -o $@ $<
+
+# this sets the gsoap header that we use for further compilation; if stuff works, then the
+# one we generate via XSLT produces the same end result as the one from the gSOAP tool;
+# with this variable we can swap for testing, but shipped code must use VBOXWEB_GSOAPH_FROM_XSLT
+GSOAPH_RELEVANT = $(VBOXWEB_GSOAPH_FROM_XSLT)
+
+# wsdl2h -v: verbose
+# wsdl2h -e: don't qualify enum names
+# wsdl2h -n<prefix>: namespace header prefix
+
+## @todo change this to state explicitly what will be generated?
+
+#
+# Generate server and client code from gsoap pseudo-C header file.
+#
+# Options for soapcpp2:
+# -2: generate SOAP 1.2 calls
+# -L: don't generate soapClientLib/soapServerLib
+# -w: don't generate WSDL and schema files
+# -x: don't generate sample XML files (VBOXWEB_SOAPCPP2_SKIP_FILES).
+#
+$(VBOXWEB_OUT_DIR)/gsoap_generate_all_ts \
++ $(VBOXWEB_OUT_DIR)/soapH.h \
+$(if-expr !defined(VBOX_WITHOUT_NOINLINE_SOAPH),\
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-1.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-2.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-3.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-4.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-5.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-6.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-7.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-8.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-9.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-10.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-11.cpp \
++ $(VBOXWEB_OUT_DIR)/soapH-noinline-12.cpp,) \
++ $(VBOXWEB_SOAP_CLIENT_H) \
++ $(VBOXWEB_OUT_DIR)/soapC.cpp \
++ $(VBOXWEB_OUT_DIR)/soapClient.cpp \
++ $(VBOXWEB_OUT_DIR)/soapServer.cpp \
+: $(VBOXWEB_GSOAPH_FROM_GSOAP) $(VBOXWEB_GSOAPH_FROM_XSLT) $(VBOX_NSMAP) \
+ $(VBOX_PATH_WEBSERVICE)/stdsoap2.sed \
+ $(VBOX_PATH_WEBSERVICE)/soap-header-to-inline-source-file.sed \
+ $(VBOX_PATH_WEBSERVICE)/soap-header-strip-inline.sed \
+ $$(split-soapC_1_TARGET) \
+ $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@)
+ $(call MSG_GENERATE,,lots of files,$(GSOAPH_RELEVANT))
+ $(RM) -f $@
+ $(REDIRECT) -C $(VBOXWEB_OUT_DIR) -- $(VBOX_SOAPCPP2) $(VBOXWEB_SOAPCPP2_SKIP_FILES) -L -2 -w -I$(VBOX_PATH_GSOAP_IMPORT) $(GSOAPH_RELEVANT)
+ifeq ($(KBUILD_TARGET),win) # MSC -Wall workaround.
+ $(CP) -f "$(VBOXWEB_SOAP_CLIENT_H)" "$(VBOXWEB_SOAP_CLIENT_H).tmp"
+ $(SED) -f $(VBOX_PATH_WEBSERVICE)/stdsoap2.sed --output "$(VBOXWEB_SOAP_CLIENT_H)" "$(VBOXWEB_SOAP_CLIENT_H).tmp"
+ $(RM) -f "$(VBOXWEB_SOAP_CLIENT_H).tmp"
+endif
+ifndef VBOX_WITHOUT_NOINLINE_SOAPH
+ $(MV) -f -- "$(VBOXWEB_OUT_DIR)/soapH.h" "$(VBOXWEB_OUT_DIR)/soapH.h.tmp"
+ $(SED) -f $(VBOX_PATH_WEBSERVICE)/soap-header-to-inline-source-file.sed \
+ --output "$(VBOXWEB_OUT_DIR)/soapH-noinline.cpp" \
+ "$(VBOXWEB_OUT_DIR)/soapH.h.tmp"
+ $(split-soapC_1_TARGET) $(VBOXWEB_OUT_DIR)/soapH-noinline.cpp $(VBOXWEB_OUT_DIR)/soapH-noinline- 12
+ $(SED) -f $(VBOX_PATH_WEBSERVICE)/soap-header-strip-inline.sed \
+ --output "$(VBOXWEB_OUT_DIR)/soapH.h" \
+ "$(VBOXWEB_OUT_DIR)/soapH.h.tmp"
+ $(RM) -f -- "$(VBOXWEB_OUT_DIR)/soapH.h.tmp" "$(VBOXWEB_OUT_DIR)/soapH-noinline.cpp"
+endif
+ $(APPEND) $@ done
+
+# Copy the generated headers and stuff. This was split into a separate rule
+# way back because we thought we could use $(wildcard ) and avoid the shell,
+# however we cannot as it is subject to caching. Let the shell do the globbing.
+# GSOAP versions 2.8 and later do not generate the unneeded soapvbox*.h files
+# any more. Ignoring the exit code is the simple solution, accepting the error.
+$(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts: $(VBOXWEB_OUT_DIR)/gsoap_generate_all_ts | $$(dir $$@)
+ $(RM) -f $@
+ $(MKDIR) -p $(PATH_TARGET_SOAPDEMOXML) $(PATH_TARGET_SOAPDEMOHEADERS) $(PATH_TARGET_SOAPDEMONSMAPS)
+ifdef VBOX_GSOAP_VERBOSE
+ $(MV_EXT) -f -- $(VBOXWEB_OUT_DIR)/*.req.xml $(VBOXWEB_OUT_DIR)/*.res.xml $(PATH_TARGET_SOAPDEMOXML)/
+endif
+ -$(MV_EXT) -f -- $(VBOXWEB_OUT_DIR)/soapvbox*.h $(PATH_TARGET_SOAPDEMOHEADERS)/
+ $(MV_EXT) -f -- $(VBOXWEB_OUT_DIR)/vboxBinding.nsmap $(PATH_TARGET_SOAPDEMONSMAPS)/
+ $(APPEND) $@ done
+
+$(PATH_TARGET_SOAPDEMONSMAPS) \
+$(PATH_TARGET_SOAPDEMOHEADERS)/soapvboxBindingProxy.h \
+$(PATH_TARGET_SOAPDEMOHEADERS)/soapvboxBindingObject.h: $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts
+
+hack: $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts
+
+ifndef VBOX_WITHOUT_SPLIT_SOAPC
+#
+# Split up the soapC.cpp monster into manageable bits that can be
+# built in parallel and without exhausting all available memory.
+#
+$(VBOXWEB_OUT_DIR)/soapC-1.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-2.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-3.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-4.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-5.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-6.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-7.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-8.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-9.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-10.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-11.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-12.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-13.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-14.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-15.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-16.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-17.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-18.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-19.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-20.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-21.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-22.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-23.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-24.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-25.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-26.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-27.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-28.cpp \
++ $(VBOXWEB_OUT_DIR)/soapC-29.cpp \
+: $(VBOXWEB_OUT_DIR)/soapC.cpp $$(split-soapC_1_TARGET) | $$(dir $$@)
+ $(RM) -f -- $(wildcard $(VBOXWEB_OUT_DIR)/soapC-?.cpp $(VBOXWEB_OUT_DIR)/soapC-??.cpp)
+ $(split-soapC_1_TARGET) $(VBOXWEB_OUT_DIR)/soapC.cpp $(VBOXWEB_OUT_DIR)/soapC- 29
+endif # !VBOX_WITHOUT_SPLIT_SOAPC
+
+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_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) -ascii VBoxWebWSDL $< $@
+
+
+ifdef VBOX_ONLY_SDK
+
+$(VBOXWEB_JAXWSSAMPLE): $(VBOX_PATH_WEBSERVICE)/samples/java/jax-ws/clienttest.java
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(VBOXWEB_SAMPLES_JAXWS_DIR)
+ $(QUIET)$(SED) -e 's/{VBOX_API_SUFFIX}/$(VBOX_API_SUFFIX)/' < $< > $@
+
+$(VBOXWEB_METRICSAMPLE): $(VBOX_PATH_WEBSERVICE)/samples/java/jax-ws/metrictest.java
+ $(QUIET)$(RM) -f -- $@
+ $(QUIET)$(MKDIR) -p $(VBOXWEB_SAMPLES_JAXWS_DIR)
+ $(QUIET)$(SED) -e 's/{VBOX_API_SUFFIX}/$(VBOX_API_SUFFIX)/' < $< > $@
+
+endif # VBOX_ONLY_SDK
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/Main/webservice/Makefile.webtest b/src/VBox/Main/webservice/Makefile.webtest
new file mode 100644
index 00000000..d506b14d
--- /dev/null
+++ b/src/VBox/Main/webservice/Makefile.webtest
@@ -0,0 +1,94 @@
+# $Id: Makefile.webtest $
+## @files
+# ???
+#
+
+#
+# Copyright (C) 2016-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+XSLTPROC = xsltproc
+ifeq ($(PATH_GSOAP),)
+ PATH_GSOAP = $(lastword $(sort $(wildcard $(KBUILD_DEVTOOLS)/common/gsoap/*)))
+endif
+PATH_GSOAP_BIN := $(strip $(PATH_GSOAP))
+ifeq ($(PATH_GSOAP_BIN),)
+ PATH_GSOAP_BIN = /usr/bin
+endif
+SOAPCPP2 = $(PATH_GSOAP_BIN)/soapcpp2
+
+ifneq ($(MAKECMDGOALS),clean)
+ ifeq ($(wildcard $(PATH_GSOAP)/stdsoap2.cpp),)
+ $(error Fix PATH_GSOAP!)
+ endif
+endif
+
+WEBSRVWSDL2GSOAPH = ../../../xsl/websrv-wsdl2gsoapH.xsl
+WEBSRVNSMAPXSL = ../../../xsl/websrv-nsmap.xsl
+VBOXWEBIDLSRC = ../../../../VirtualBox.xidl
+VBOXWEBWSDL = ../../../vboxweb.wsdl
+SPLITSOAPCCPP = ../../../tools/split-soapC.cpp
+SOAPCCPP = $(foreach num,1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20,soapC-$(num).cpp)
+SOAPCO = $(patsubst %.cpp,%.o,$(SOAPCCPP))
+
+webtest: webtest.o soapClient.o $(SOAPCO) stdsoap2.o
+ $(CXX) -O2 -o $@ $^ -lssl -lcrypto
+
+webtest.o: webtest.cpp soapC.cpp vboxwebsrv.nsmap
+ $(CXX) -O2 -DWITH_OPENSSL -c -o $@ $< -I$(PATH_GSOAP)
+
+soapClient.o: soapC.cpp
+ $(CXX) -O2 -c -o $@ soapClient.cpp -I$(PATH_GSOAP)
+
+$(SOAPCO): soapC-%.o: soapC-%.cpp
+ $(CXX) -O0 -c -o $@ $< -I$(PATH_GSOAP)
+
+soapC.cpp: gsoapH_from_xslt.h
+ $(SOAPCPP2) -x -L -2 -w -I$(PATH_GSOAP)/import $^
+
+stdsoap2.o: $(PATH_GSOAP)/stdsoap2.cpp
+ $(CXX) -O2 -DWITH_OPENSSL -c -o $@ $<
+
+gsoapH_from_xslt.h:
+ $(XSLTPROC) -o $@ $(WEBSRVWSDL2GSOAPH) $(VBOXWEBWSDL)
+
+vboxwebsrv.nsmap:
+ $(XSLTPROC) -o $@ $(WEBSRVNSMAPXSL) $(VBOXWEBIDLSRC)
+
+$(subst soapC,%,$(SOAPCCPP)): split-soapC %.cpp
+ ./split-soapC soapC.cpp . 20
+
+split-soapC: $(SPLITSOAPCCPP)
+ $(CXX) -O2 -o $@ $<
+
+.PHONY: clean
+clean:
+ rm -f gsoapH_from_xslt.h
+ rm -f soapStub.h soapServer.cpp soapC.cpp soapClient.cpp
+ rm -f soapH.h soapvboxBindingObject.h soapvboxBindingProxy.h
+ rm -f vboxBinding.nsmap
+ rm -f vboxwebsrv.nsmap
+ rm -f split-soapC
+ rm -f $(SOAPCCPP) $(SOAPCO)
+ rm -f soapClient.o stdsoap2.o
+ rm -f webtest.o webtest
+ rm -f soapC-split-done
+
diff --git a/src/VBox/Main/webservice/VBoxWebSrv.rc b/src/VBox/Main/webservice/VBoxWebSrv.rc
new file mode 100644
index 00000000..764a52c7
--- /dev/null
+++ b/src/VBox/Main/webservice/VBoxWebSrv.rc
@@ -0,0 +1,61 @@
+/* $Id: VBoxWebSrv.rc $ */
+/** @file
+ * VBoxWebSrv - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_APP
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox Web Service\0"
+ VALUE "InternalName", "VBoxWebSrv\0"
+ VALUE "OriginalFilename", "VBoxWebSrv.exe\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Main/webservice/platform-xidl.xsl b/src/VBox/Main/webservice/platform-xidl.xsl
new file mode 100644
index 00000000..42915887
--- /dev/null
+++ b/src/VBox/Main/webservice/platform-xidl.xsl
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+
+<!--
+ platform-xidl.xsl:
+ XSLT stylesheet that generates a platform-specific
+ VirtualBox.xidl from ../idl/VirtualBox.xidl, which
+ is identical to the original except that all <if...>
+ sections are resolved (for easier processing).
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output
+ method="xml"
+ version="1.0"
+ encoding="utf-8"
+ indent="yes"/>
+
+<xsl:strip-space
+ elements="*" />
+
+<!--
+ template for "idl" match; this emits the header of the target file
+ and recurses into the libraries with interfaces (which are matched below)
+ -->
+<xsl:template match="/idl">
+ <xsl:comment>
+ DO NOT EDIT! This is a generated file.
+ Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML)
+ Generator: src/VBox/Main/webservice/platform-xidl.xsl
+</xsl:comment>
+
+ <idl>
+ <xsl:apply-templates />
+ </idl>
+
+</xsl:template>
+
+<!--
+ template for "if" match: ignore all ifs except those for wsdl
+ -->
+<xsl:template match="if">
+ <xsl:if test="@target='wsdl'">
+ <xsl:apply-templates/>
+ </xsl:if>
+</xsl:template>
+
+<!--
+ ignore everything we don't need
+ -->
+<xsl:template match="cpp|class|enumerator">
+</xsl:template>
+
+<!--
+ and keep the rest intact (including all attributes)
+
+ NOTE: this drops class and everything in it, which I left unchanged
+ since the other xslt scripts blow up badly.
+ -->
+<xsl:template match="library|module|enum|const|interface|attribute|collection|method|param|result">
+ <xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
+</xsl:template>
+
+<!--
+ keep those completely unchanged, including child nodes (including all
+ attributes)
+ -->
+<xsl:template match="descGroup|desc|note">
+ <xsl:copy-of select="."/>
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/samples/java/axis/clienttest.java b/src/VBox/Main/webservice/samples/java/axis/clienttest.java
new file mode 100644
index 00000000..31043d3e
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/java/axis/clienttest.java
@@ -0,0 +1,310 @@
+/* $Id: clienttest.java $ */
+/*!file
+ * Sample client for the VirtualBox web service, written in Java (raw web service variant).
+ *
+ * Run the VirtualBox web service server first; see the VirtualBox
+ * SDK reference for details.
+ *
+ * The following license applies to this file only:
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+
+import org.virtualbox.www.Service.VboxService;
+import org.virtualbox.www.Service.VboxServiceLocator;
+import org.virtualbox.www.VboxPortType;
+
+public class clienttest
+{
+ private VboxService _service;
+ private VboxPortType _port;
+ private String _oVbox;
+
+ public clienttest()
+ {
+ try
+ {
+ // instantiate the webservice in instance data; the classes
+ // VboxServiceLocator and VboxPortType have been created
+ // by the WSDL2Java helper that you should have run prior
+ // to compiling this example, as described in the User Manual.
+ _service = new VboxServiceLocator();
+ _port = _service.getvboxServicePort();
+
+ // From now on, we can call any method in the webservice by
+ // prefixing it with "port."
+
+ // First step is always to log on to the webservice. This
+ // returns a managed object reference to the webservice's
+ // global instance of IVirtualBox, which in turn contains
+ // the most important methods provided by the Main API.
+ _oVbox = _port.IWebsessionManager_logon("", "");
+
+ // Call IVirtualBox::getVersion and print out the result
+ String version = _port.IVirtualBox_getVersion(_oVbox);
+ System.out.println("Initialized connection to VirtualBox version " + version);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void showVMs()
+ {
+ try
+ {
+ // Call IVirtualBox::getMachines, which yields an array
+ // of managed object references to all machines which have
+ // been registered:
+ String[] aMachines = _port.IVirtualBox_getMachines2(_oVbox);
+ // Walk through this array and, for each machine, call
+ // IMachine::getName (accessor method to the "name" attribute)
+ for (int i = 0; i < aMachines.length; i++)
+ {
+ String oMachine = aMachines[i];
+ String machinename = _port.IMachine_getName(oMachine);
+ System.out.println("Machine " + i + ": " + oMachine + " - " + machinename);
+
+ // release managed object reference
+ _port.IManagedObjectRef_release(oMachine);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void listHostInfo()
+ {
+ try
+ {
+ String oHost = _port.IVirtualBox_getHost(_oVbox);
+
+ org.apache.axis.types.UnsignedInt uProcCount = _port.IHost_getProcessorCount(oHost);
+ System.out.println("Processor count: " + uProcCount);
+
+ String oCollector = _port.IVirtualBox_getPerformanceCollector(_oVbox);
+
+ String aobj[] = {oHost};
+ String astrMetrics[] = {"*"};
+ String aMetrics[] = {};
+ aMetrics = _port.IPerformanceCollector_getMetrics(oCollector,
+ astrMetrics,
+ aobj);
+
+// String astrMetricNames[] = { "*" };
+// String aObjects[];
+// String aRetNames[];
+// int aRetIndices[];
+// int aRetLengths[];
+// int aRetData[];
+// int rc = _port.ICollector_queryMetricsData(oCollector,
+// aObjects,
+// aRetNames,
+// aRetObjects,
+// aRetIndices,
+// aRetLengths,
+// aRetData);
+//
+/*
+ Bstr metricNames[] = { L"*" };
+ com::SafeArray<BSTR> metrics (1);
+ metricNames[0].cloneTo (&metrics [0]);
+ com::SafeArray<BSTR> retNames;
+ com::SafeIfaceArray<IUnknown> retObjects;
+ com::SafeArray<ULONG> retIndices;
+ com::SafeArray<ULONG> retLengths;
+ com::SafeArray<LONG> retData;
+ CHECK_ERROR (collector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
+ ComSafeArrayInArg(objects),
+ ComSafeArrayAsOutParam(retNames),
+ ComSafeArrayAsOutParam(retObjects),
+ ComSafeArrayAsOutParam(retIndices),
+ ComSafeArrayAsOutParam(retLengths),
+ ComSafeArrayAsOutParam(retData)) );
+*/
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void startVM(String strVM)
+ {
+ String oSession = "";
+ Boolean fSessionOpen = false;
+
+ try
+ {
+ // this is pretty much what VBoxManage does to start a VM
+ String oMachine = "";
+ Boolean fOK = false;
+
+ oSession = _port.IWebsessionManager_getSessionObject(_oVbox);
+
+ // first assume we were given a UUID
+ try
+ {
+ oMachine = _port.IVirtualBox_getMachine(_oVbox, strVM);
+ fOK = true;
+ }
+ catch (Exception e)
+ {
+ }
+
+ if (!fOK)
+ {
+ try
+ {
+ // or try by name
+ oMachine = _port.IVirtualBox_findMachine(_oVbox, strVM);
+ fOK = true;
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ if (!fOK)
+ {
+ System.out.println("Error: can't find VM \"" + strVM + "\"");
+ }
+ else
+ {
+ String uuid = _port.IMachine_getId(oMachine);
+ String sessionType = "gui";
+ String env = "DISPLAY=:0.0";
+ String oProgress = _port.IVirtualBox_openRemoteSession(_oVbox, oSession, uuid, sessionType, env);
+ fSessionOpen = true;
+
+ System.out.println("Session for VM " + uuid + " is opening...");
+ _port.IProgress_waitForCompletion(oProgress, 10000);
+
+ int rc = _port.IProgress_getResultCode(oProgress).intValue();
+ if (rc != 0)
+ {
+ System.out.println("Session failed!");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ if (fSessionOpen)
+ {
+ try
+ {
+ _port.ISession_close(oSession);
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+
+ public void cleanup()
+ {
+ try
+ {
+ if (_oVbox.length() > 0)
+ {
+ // log off
+ _port.IWebsessionManager_logoff(_oVbox);
+ _oVbox = null;
+ System.out.println("Logged off.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void printArgs()
+ {
+ System.out.println( "Usage: java clienttest <mode> ..." +
+ "\nwith <mode> being:" +
+ "\n show vms list installed virtual machines" +
+ "\n list hostinfo list host info" +
+ "\n startvm <vmname|uuid> start the given virtual machine");
+ }
+
+ public static void main(String[] args)
+ {
+ if (args.length < 1)
+ {
+ System.out.println("Error: Must specify at least one argument.");
+ printArgs();
+ }
+ else
+ {
+ clienttest c = new clienttest();
+ if (args[0].equals("show"))
+ {
+ if (args.length == 2)
+ {
+ if (args[1].equals("vms"))
+ c.showVMs();
+ else
+ System.out.println("Error: Unknown argument to \"show\": \"" + args[1] + "\".");
+ }
+ else
+ System.out.println("Error: Missing argument to \"show\" command");
+ }
+ else if (args[0].equals("list"))
+ {
+ if (args.length == 2)
+ {
+ if (args[1].equals("hostinfo"))
+ c.listHostInfo();
+ else
+ System.out.println("Error: Unknown argument to \"show\": \"" + args[1] + "\".");
+ }
+ else
+ System.out.println("Error: Missing argument to \"show\" command");
+ }
+ else if (args[0].equals("startvm"))
+ {
+ if (args.length == 2)
+ {
+ c.startVM(args[1]);
+ }
+ else
+ System.out.println("Error: Missing argument to \"startvm\" command");
+ }
+ else
+ System.out.println("Error: Unknown command: \"" + args[0] + "\".");
+
+ c.cleanup();
+ }
+ }
+}
diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile
new file mode 100644
index 00000000..7bd53a61
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile
@@ -0,0 +1,83 @@
+# $Id: Makefile $
+## @file
+# Makefile for java samples.
+#
+
+
+#
+# Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+JAVA16=java
+JAVA15=/usr/lib/jvm/java-1.5.0-sun/bin/java
+JAVAC = javac
+JAVAC15 = javac -target 1.5
+JAVAC16 = javac -target 1.6
+MKDIR = mkdir
+RM = rm
+
+DEST16 = ./gen16
+DEST15 = ./gen15
+
+VBOXWS15 = ../lib/vboxws_java15.jar
+VBOXWS16 = ../lib/vboxws_java16.jar
+
+JAXWS=./jaxws-ri
+JAXWSLIBS=$(JAXWS)/lib/jaxws-api.jar:$(JAXWS)/lib/jaxb-api.jar:$(JAXWS)/lib/jsr181-api.jar:$(JAXWS)/lib/jaxws-rt.jar
+
+all: run16
+
+metric: metric16
+
+$(DEST16)/clienttest.class: clienttest.java
+ $(MKDIR) -p $(DEST16)
+ $(JAVAC16) -d $(DEST16) -cp $(VBOXWS16) $<
+
+$(DEST15)/clienttest.class: clienttest.java
+ $(MKDIR) -p $(DEST15)
+ $(JAVAC15) -d $(DEST15) -cp $(VBOXWS15):$(JAXWSLIBS) $<
+
+run16: $(DEST16)/clienttest.class
+ $(JAVA16) -cp $(VBOXWS16):$(DEST16) clienttest show vms
+
+run15: $(DEST15)/clienttest.class
+ $(JAVA15) -cp $(VBOXWS15):$(JAXWSLIBS):$(DEST15) clienttest show vms
+
+$(DEST16)/metrictest.class: metrictest.java
+ $(MKDIR) -p $(DEST16)
+ $(JAVAC16) -d $(DEST16) -cp $(VBOXWS16) $<
+
+$(DEST15)/metrictest.class: metrictest.java
+ $(MKDIR) -p $(DEST15)
+ $(JAVAC15) -d $(DEST15) -cp $(VBOXWS15):$(JAXWSLIBS) $<
+
+metric16: $(DEST16)/metrictest.class
+ -$(JAVA16) -cp $(VBOXWS16):$(DEST16) metrictest
+
+metric15: $(DEST15)/metrictest.class
+ -$(JAVA15) -cp $(VBOXWS15):$(JAXWSLIBS):$(DEST15) metrictest
+
+clean:
+ $(RM) -rf $(DEST15) $(DEST16)
+
diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue
new file mode 100644
index 00000000..295ea77c
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/java/jax-ws/Makefile.glue
@@ -0,0 +1,72 @@
+# $Id: Makefile.glue $
+## @file
+# Makefile for java samples.
+#
+
+#
+# Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+JAXWS=./jaxws-ri
+JAXWSLIBS=$(JAXWS)/lib/jaxws-api.jar:$(JAXWS)/lib/jaxb-api.jar:$(JAXWS)/lib/jsr181-api.jar:$(JAXWS)/lib/jaxws-rt.jar
+
+
+JAVA16=java
+JAVA15=/usr/lib/jvm/java-1.5.0-sun/bin/java
+JAVAC15 = javac -target 1.5
+JAVAC16 = javac -target 1.6
+WSIMPORT15 = $(JAVA15) -cp $(JAXWS)/lib/jaxws-tools.jar com.sun.tools.ws.WsImport
+WSIMPORT16 = wsimport
+JAR = jar
+CP = cp
+MKDIR = mkdir
+RM = rm
+
+DEST16 = ./gen16
+DEST15 = ./gen15
+
+VBOXWS15 = ../lib/vboxws_java15.jar
+VBOXWS16 = ../lib/vboxws_java16.jar
+
+all: $(VBOXWS15) $(VBOXWS16)
+
+$(VBOXWS15): ../../../vboxwebService.wsdl ../../../vboxweb.wsdl *.java
+ $(RM) -rf $(DEST15)
+ $(MKDIR) -p $(DEST15)
+ $(WSIMPORT15) -d $(DEST15) $<
+ $(JAVAC15) -cp $(DEST15) *.java -d $(DEST15)
+ $(CP) ../../../vboxwebService.wsdl ../../../vboxweb.wsdl $(DEST15)
+ $(JAR) cvf $(VBOXWS15) -C $(DEST15) . > /dev/null
+
+$(VBOXWS16): ../../../vboxwebService.wsdl ../../../vboxweb.wsdl *.java
+ $(RM) -rf $(DEST16)
+ $(MKDIR) -p $(DEST16)
+ $(WSIMPORT16) -d $(DEST16) $<
+ $(JAVAC16) -cp $(DEST16) *.java -d $(DEST16)
+ $(CP) ../../../vboxwebService.wsdl ../../../vboxweb.wsdl $(DEST16)
+ $(JAR) cvf $(VBOXWS16) -C $(DEST16) . > /dev/null
+
+clean:
+ $(RM) -rf $(DEST)
+
diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/clienttest.java b/src/VBox/Main/webservice/samples/java/jax-ws/clienttest.java
new file mode 100644
index 00000000..02d67ab0
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/java/jax-ws/clienttest.java
@@ -0,0 +1,339 @@
+/* $Id: clienttest.java $ */
+/*!file
+ * Sample client for the VirtualBox web service, written in Java (object-oriented bindings).
+ *
+ * Run the VirtualBox web service server first; see the VirtualBox
+ * SDK reference for details.
+ *
+ * The following license applies to this file only:
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+
+/* Somewhat ugly way to support versioning */
+import com.sun.xml.ws.commons.virtualbox{VBOX_API_SUFFIX}.*;
+
+import java.util.*;
+import javax.xml.ws.Holder;
+
+public class clienttest
+{
+ IWebsessionManager mgr;
+ IVirtualBox vbox;
+
+ public clienttest()
+ {
+ mgr = new IWebsessionManager("http://localhost:18083/");
+ vbox = mgr.logon("test", "test");
+ System.out.println("Initialized connection to VirtualBox version " + vbox.getVersion());
+ }
+
+ public void disconnect()
+ {
+ mgr.disconnect(vbox);
+ }
+
+ class Desktop
+ {
+ String name;
+ String uuid;
+
+ Desktop(int n)
+ {
+ name = "Mach"+n;
+ uuid = UUID.randomUUID().toString();
+ }
+ String getName()
+ {
+ return name;
+ }
+ String getId()
+ {
+ return uuid;
+ }
+ }
+
+ public void test()
+ {
+ for (int i=0; i<100; i++)
+ {
+ String baseFolder =
+ vbox.getSystemProperties().getDefaultMachineFolder();
+ Desktop desktop = new Desktop(i);
+ IMachine machine = vbox.createMachine(baseFolder,
+ "linux",
+ desktop.getName(),
+ desktop.getId(),
+ true);
+ machine.saveSettings();
+ mgr.cleanupUnused();
+ }
+ }
+
+ public void test2()
+ {
+ ISession session = mgr.getSessionObject(vbox);
+ String id = "bc8b6219-2775-42c4-f1b2-b48b3c177294";
+ vbox.openSession(session, id);
+ IMachine mach = session.getMachine();
+ IBIOSSettings bios = mach.getBIOSSettings();
+ bios.setIOAPICEnabled(true);
+ mach.saveSettings();
+ session.close();
+ }
+
+
+ public void test3()
+ {
+
+ IWebsessionManager mgr1 = new IWebsessionManager("http://localhost:18082/");
+ IWebsessionManager mgr2 = new IWebsessionManager("http://localhost:18083/");
+ IVirtualBox vbox1 = mgr1.logon("test", "test");
+ IVirtualBox vbox2 = mgr2.logon("test", "test");
+
+
+ System.out.println("connection 1 to VirtualBox version " + vbox1.getVersion());
+ System.out.println("connection 2 to VirtualBox version " + vbox2.getVersion());
+ mgr1.disconnect(vbox1);
+ mgr2.disconnect(vbox2);
+
+ mgr1 = new IWebsessionManager("http://localhost:18082/");
+ mgr2 = new IWebsessionManager("http://localhost:18083/");
+ vbox1 = mgr1.logon("test", "test");
+ vbox2 = mgr2.logon("test", "test");
+
+ System.out.println("second connection 1 to VirtualBox version " + vbox1.getVersion());
+ System.out.println("second connection 2 to VirtualBox version " + vbox2.getVersion());
+
+ mgr1.disconnect(vbox1);
+ mgr2.disconnect(vbox2);
+ }
+
+ public void showVMs()
+ {
+ try
+ {
+ int i = 0;
+ for (IMachine m : vbox.getMachines())
+ {
+ System.out.println("Machine " + (i++) + ": " + " [" + m.getId() + "]" + " - " + m.getName());
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void listHostInfo()
+ {
+ try
+ {
+ IHost host = vbox.getHost();
+ long uProcCount = host.getProcessorCount();
+ System.out.println("Processor count: " + uProcCount);
+
+ for (long i=0; i<uProcCount; i++)
+ {
+ System.out.println("Processor #" + i + " speed: " + host.getProcessorSpeed(i) + "MHz");
+ }
+
+ IPerformanceCollector oCollector = vbox.getPerformanceCollector();
+
+ List<IPerformanceMetric> aMetrics =
+ oCollector.getMetrics(Arrays.asList(new String[]{"*"}),
+ Arrays.asList(new IUnknown[]{host}));
+
+ for (IPerformanceMetric m : aMetrics)
+ {
+ System.out.println("known metric = "+m.getMetricName());
+ }
+
+ Holder<List<String>> names = new Holder<List<String>> ();
+ Holder<List<IUnknown>> objects = new Holder<List<IUnknown>>() ;
+ Holder<List<String>> units = new Holder<List<String>>();
+ Holder<List<Long>> scales = new Holder<List<Long>>();
+ Holder<List<Long>> sequenceNumbers = new Holder<List<Long>>();
+ Holder<List<Long>> indices = new Holder<List<Long>>();
+ Holder<List<Long>> lengths = new Holder<List<Long>>();
+
+ List<Integer> vals =
+ oCollector.queryMetricsData(Arrays.asList(new String[]{"*"}),
+ Arrays.asList(new IUnknown[]{host}),
+ names, objects, units, scales,
+ sequenceNumbers, indices, lengths);
+
+ for (int i=0; i < names.value.size(); i++)
+ System.out.println("name: "+names.value.get(i));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void startVM(String strVM)
+ {
+ ISession oSession = null;
+ IMachine oMachine = null;
+
+ try
+ {
+ oSession = mgr.getSessionObject(vbox);
+
+ // first assume we were given a UUID
+ try
+ {
+ oMachine = vbox.getMachine(strVM);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ oMachine = vbox.findMachine(strVM);
+ }
+ catch (Exception e1)
+ {
+ }
+ }
+
+ if (oMachine == null)
+ {
+ System.out.println("Error: can't find VM \"" + strVM + "\"");
+ }
+ else
+ {
+ String uuid = oMachine.getId();
+ String sessionType = "gui";
+ ArrayList<String> env = new ArrayList<String>();
+ env.add("DISPLAY=:0.0");
+ IProgress oProgress =
+ oMachine.launchVMProcess(oSession,
+ sessionType,
+ env);
+ System.out.println("Session for VM " + uuid + " is opening...");
+ oProgress.waitForCompletion(10000);
+
+ long rc = oProgress.getResultCode();
+ if (rc != 0)
+ System.out.println("Session failed!");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ if (oSession != null)
+ {
+ oSession.close();
+ }
+ }
+ }
+
+ public void cleanup()
+ {
+ try
+ {
+ if (vbox != null)
+ {
+ disconnect();
+ vbox = null;
+ System.out.println("Logged off.");
+ }
+ mgr.cleanupUnused();
+ mgr = null;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void printArgs()
+ {
+ System.out.println( "Usage: java clienttest <mode> ..." +
+ "\nwith <mode> being:" +
+ "\n show vms list installed virtual machines" +
+ "\n list hostinfo list host info" +
+ "\n startvm <vmname|uuid> start the given virtual machine");
+ }
+
+ public static void main(String[] args)
+ {
+ if (args.length < 1)
+ {
+ System.out.println("Error: Must specify at least one argument.");
+ printArgs();
+ }
+ else
+ {
+ clienttest c = new clienttest();
+ if (args[0].equals("show"))
+ {
+ if (args.length == 2)
+ {
+ if (args[1].equals("vms"))
+ c.showVMs();
+ else
+ System.out.println("Error: Unknown argument to \"show\": \"" + args[1] + "\".");
+ }
+ else
+ System.out.println("Error: Missing argument to \"show\" command");
+ }
+ else if (args[0].equals("list"))
+ {
+ if (args.length == 2)
+ {
+ if (args[1].equals("hostinfo"))
+ c.listHostInfo();
+ else
+ System.out.println("Error: Unknown argument to \"show\": \"" + args[1] + "\".");
+ }
+ else
+ System.out.println("Error: Missing argument to \"list\" command");
+ }
+ else if (args[0].equals("startvm"))
+ {
+ if (args.length == 2)
+ {
+ c.startVM(args[1]);
+ }
+ else
+ System.out.println("Error: Missing argument to \"startvm\" command");
+ }
+ else if (args[0].equals("test"))
+ {
+ c.test3();
+ }
+ else
+ System.out.println("Error: Unknown command: \"" + args[0] + "\".");
+
+ c.cleanup();
+ }
+ }
+}
diff --git a/src/VBox/Main/webservice/samples/java/jax-ws/metrictest.java b/src/VBox/Main/webservice/samples/java/jax-ws/metrictest.java
new file mode 100644
index 00000000..05cfabba
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/java/jax-ws/metrictest.java
@@ -0,0 +1,231 @@
+/* $Id: metrictest.java $ */
+/*!file
+ * Sample of performance API usage, written in Java.
+ *
+ * Don't forget to run VBOX webserver
+ * with 'vboxwebsrv -t 1000' command, to calm down watchdog thread.
+ *
+ * The following license applies to this file only:
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+
+import com.sun.xml.ws.commons.virtualbox{VBOX_API_SUFFIX}.*;
+
+import java.util.*;
+import javax.xml.ws.Holder;
+
+class PerformanceData
+{
+ public String name;
+ public IUnknown object;
+ public String unit;
+ public Long scale;
+ public Long sequenceNumber;
+ public List<Long> samples;
+
+ public String getFormattedSamples()
+ {
+ String out = "[";
+ String separator = "";
+
+ if (scale != 1)
+ {
+ for (Long sample : samples)
+ {
+ out += separator + (sample.doubleValue() / scale) + " " + unit;
+ separator = ", ";
+ }
+ }
+ else
+ {
+ for (Long sample : samples)
+ {
+ out += separator + sample.toString() + " " + unit;
+ separator = ", ";
+ }
+ }
+ out += "]";
+ return out;
+ }
+}
+
+class PerformanceCollector
+{
+ private IVirtualBox _vbox;
+ private IPerformanceCollector _collector;
+
+ public PerformanceCollector(IVirtualBox vbox)
+ {
+ _vbox = vbox;
+ _collector = vbox.getPerformanceCollector();
+ }
+
+ public void cleanup()
+ {
+ _collector.releaseRemote();
+ }
+
+ public List<IPerformanceMetric> setup(List<String> metricNames, List<IUnknown> objects, Long period, Long samples)
+ {
+ return _collector.setupMetrics(metricNames, objects, period, samples);
+ }
+
+ public List<IPerformanceMetric> enable(List<String> metricNames, List<IUnknown> objects)
+ {
+ return _collector.enableMetrics(metricNames, objects);
+ }
+
+ public List<IPerformanceMetric> disable(List<String> metricNames, List<IUnknown> objects)
+ {
+ return _collector.disableMetrics(metricNames, objects);
+ }
+
+ public List<PerformanceData> query(List<String> filterMetrics, List<IUnknown> filterObjects)
+ {
+ Holder<List<String>> names = new Holder<List<String>>();
+ Holder<List<IUnknown>> objects = new Holder<List<IUnknown>>();
+ Holder<List<String>> units = new Holder<List<String>>();
+ Holder<List<Long>> scales = new Holder<List<Long>>();
+ Holder<List<Long>> sequenceNumbers = new Holder<List<Long>>();
+ Holder<List<Long>> indices = new Holder<List<Long>>();
+ Holder<List<Long>> lengths = new Holder<List<Long>>();
+ List<Integer> values =
+ _collector.queryMetricsData(filterMetrics, filterObjects,
+ names, objects, units, scales, sequenceNumbers, indices, lengths);
+ List<PerformanceData> data = new ArrayList<PerformanceData>(names.value.size());
+ for (int i = 0; i < names.value.size(); i++)
+ {
+ PerformanceData singleMetricData = new PerformanceData();
+ singleMetricData.name = names.value.get(i);
+ singleMetricData.object = objects.value.get(i);
+ singleMetricData.unit = units.value.get(i);
+ singleMetricData.scale = scales.value.get(i);
+ singleMetricData.sequenceNumber = sequenceNumbers.value.get(i);
+ List<Long> samples = new ArrayList<Long>(lengths.value.get(i).intValue());
+ for (int j = 0; j < lengths.value.get(i); j++)
+ {
+ samples.add(values.get(indices.value.get(i).intValue() + j).longValue());
+ }
+ singleMetricData.samples = samples;
+ data.add(singleMetricData);
+ }
+
+ return data;
+ }
+}
+
+public class metrictest implements Runnable
+{
+ IVirtualBox vbox;
+ IWebsessionManager mgr;
+ PerformanceCollector perf;
+
+ public metrictest()
+ {
+ mgr = new IWebsessionManager("http://localhost:18083/");
+ vbox = mgr.logon("test", "test");
+ System.out.println("Initialized connection to VirtualBox version " + vbox.getVersion());
+ perf = new PerformanceCollector(vbox);
+ }
+
+ private String getObjectName(IUnknown object)
+ {
+ try
+ {
+ String machineName = object.getRemoteWSPort().iMachineGetName(object.getRef());
+ return machineName;
+ } catch (Exception e)
+ {
+ }
+ return new String("host");
+ }
+
+ public void setup()
+ {
+ perf.setup(Arrays.asList(new String[]{"*"}),
+ new ArrayList<IUnknown>(),
+ new Long(1), new Long(5));
+ }
+
+ public void collect()
+ {
+ try
+ {
+ List<IUnknown> allObjects = new ArrayList<IUnknown>();
+ List<PerformanceData> metricData = perf.query(Arrays.asList(new String[]{"*"}),
+ allObjects);
+ for (PerformanceData md : metricData)
+ {
+ System.out.println("(" + getObjectName(md.object) + ") " +
+ md.name + " " + md.getFormattedSamples());
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void run()
+ {
+ // Clean up
+ try
+ {
+ if (perf != null)
+ {
+ perf.cleanup();
+ perf = null;
+ }
+ if (vbox != null)
+ {
+ mgr.logoff(vbox);
+ vbox = null;
+ mgr = null;
+ System.out.println("Logged off.");
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException
+ {
+ metrictest c = new metrictest();
+ // Add a shutdown handle to clean up
+ Runtime.getRuntime().addShutdownHook(new Thread(c));
+ // Start metric collection
+ c.setup();
+ // Obtain and print out stats continuously until ctrl-C is pressed
+ while (true)
+ {
+ Thread.sleep(1000); // Sleep for a second
+ c.collect();
+ }
+ }
+}
diff --git a/src/VBox/Main/webservice/samples/perl/clienttest.pl b/src/VBox/Main/webservice/samples/perl/clienttest.pl
new file mode 100755
index 00000000..d7ef31a8
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/perl/clienttest.pl
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+# $Id: clienttest.pl $
+## @file
+# This little perl program attempts to connect to a running VirtualBox
+# webservice and calls various methods on it. Please refer to the SDK
+# programming reference (SDKRef.pdf) for how to use this sample.
+#
+# Note! The following license applies to this file only
+#
+
+#
+# Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+use strict;
+use SOAP::Lite;
+use vboxService; # generated by stubmaker, see SDKRef.pdf
+use Data::Dumper;
+
+my $cmd = 'clienttest';
+my $optMode;
+my $vmname;
+my $disk;
+
+while (my $this = shift(@ARGV))
+{
+ if (($this =~ /^-h/) || ($this =~ /^--help/))
+ {
+ print "$cmd: test the VirtualBox web service.\n".
+ "Usage:\n".
+ " $cmd <mode>\n".
+ "with <mode> being one of 'version', 'list', 'start'; default is 'list'.\n".
+ " $cmd version: print version of VirtualBox web service.\n".
+ " $cmd list: list installed virtual machines.\n".
+ " $cmd startvm <vm>: start the virtual machine named <vm>.\n".
+ " $cmd acpipowerbutton <vm>: shutdown of the irtual machine named <vm>.\n";
+ " $cmd openhd <disk>: open disk image <disk>.\n";
+ exit 0;
+ }
+ elsif ( ($this eq 'version')
+ || ($this eq 'list')
+ )
+ {
+ $optMode = $this;
+ }
+ elsif ( ($this eq 'startvm')
+ || ($this eq 'acpipowerbutton')
+ )
+ {
+ $optMode = $this;
+
+ if (!($vmname = shift(@ARGV)))
+ {
+ die "[$cmd] Missing parameter: You must specify the name of the VM to start.\nStopped";
+ }
+ }
+ elsif ($this eq 'openhd')
+ {
+ $optMode = $this;
+
+ if (!($disk = shift(@ARGV)))
+ {
+ die "[$cmd] Missing parameter: You must specify the name of the disk to open.\nStopped";
+ }
+ }
+ else
+ {
+ die "[$cmd] Unknown option \"$this\"; stopped";
+ }
+}
+
+$optMode = "list"
+ if (!$optMode);
+
+# SOAP::Lite hacking to make it serialize the enum types we use correctly.
+# In the long run, this needs to be done either by stubmaker.pl or something
+# else, because the WSDL clearly says they're restricted strings. Quite silly
+# that the default behavior is to ignore the parameter and just let the server
+# use the default value for the type.
+
+sub SOAP::Serializer::as_LockType
+{
+ my ($self, $value, $name, $type, $attr) = @_;
+ die "String value expected instead of @{[ref $value]} reference\n"
+ if ref $value;
+ return [
+ $name,
+ {'xsi:type' => 'vbox:LockType', %$attr},
+ SOAP::Utils::encode_data($value)
+ ];
+}
+
+sub SOAP::Serializer::as_DeviceType
+{
+ my ($self, $value, $name, $type, $attr) = @_;
+ die "String value expected instead of @{[ref $value]} reference\n"
+ if ref $value;
+ return [
+ $name,
+ {'xsi:type' => 'vbox:DeviceType', %$attr},
+ SOAP::Utils::encode_data($value)
+ ];
+}
+
+sub SOAP::Serializer::as_AccessMode
+{
+ my ($self, $value, $name, $type, $attr) = @_;
+ die "String value expected instead of @{[ref $value]} reference\n"
+ if ref $value;
+ return [
+ $name,
+ {'xsi:type' => 'vbox:AccessMode', %$attr},
+ SOAP::Utils::encode_data($value)
+ ];
+}
+
+## @todo needs much more error handling, e.g. openhd never complains
+
+my $vbox = vboxService->IWebsessionManager_logon("test", "test");
+
+if (!$vbox)
+{
+ die "[$cmd] Logon to session manager with user \"test\" and password \"test\" failed.\nStopped";
+}
+
+if ($optMode eq "version")
+{
+ my $v = vboxService->IVirtualBox_getVersion($vbox);
+ print "[$cmd] Version number of running VirtualBox web service: $v\n";
+}
+elsif ($optMode eq "list")
+{
+ print "[$cmd] Listing machines:\n";
+ my @result = vboxService->IVirtualBox_getMachines($vbox);
+ foreach my $idMachine (@result)
+ {
+ my $if = vboxService->IManagedObjectRef_getInterfaceName($idMachine);
+ my $name = vboxService->IMachine_getName($idMachine);
+
+ print "machine $if $idMachine: $name\n";
+ }
+}
+elsif ($optMode eq "startvm")
+{
+ my $machine = vboxService->IVirtualBox_findMachine($vbox, $vmname);
+
+ die "[$cmd] Cannot find VM \"$vmname\"; stopped"
+ if (!$machine);
+
+ my $session = vboxService->IWebsessionManager_getSessionObject($vbox);
+ die "[$cmd] Cannot get session object; stopped"
+ if (!$session);
+
+ my $uuid = vboxService->IMachine_getId($machine);
+ die "[$cmd] Cannot get uuid for machine; stopped"
+ if (!$uuid);
+
+ print "[$cmd] UUID: $uuid\n";
+
+ my @env = ();
+ my $progress = vboxService->IMachine_launchVMProcess($machine,
+ $session,
+ "headless",
+ @env);
+ die "[$cmd] Cannot launch VM; stopped"
+ if (!$progress);
+
+ print("[$cmd] Waiting for the VM to start...\n");
+ vboxService->IProgress_waitForCompletion($progress, -1);
+
+ my $fCompleted;
+ $fCompleted = vboxService->IProgress_getCompleted($progress);
+ print("[$cmd] Completed: $fCompleted\n");
+
+ my $resultCode;
+ $resultCode = vboxService->IProgress_getResultCode($progress);
+
+ print("[$cmd] Result: $resultCode\n");
+
+ vboxService->ISession_unlockMachine($session);
+
+ vboxService->IWebsessionManager_logoff($vbox);
+}
+elsif ($optMode eq "acpipowerbutton")
+{
+ my $machine = vboxService->IVirtualBox_findMachine($vbox, $vmname);
+
+ die "[$cmd] Cannot find VM \"$vmname\"; stopped"
+ if (!$machine);
+
+ my $session = vboxService->IWebsessionManager_getSessionObject($vbox);
+ die "[$cmd] Cannot get session object; stopped"
+ if (!$session);
+
+ vboxService->IMachine_lockMachine($machine, $session, 'Shared');
+
+ my $console = vboxService->ISession_getConsole($session);
+
+ vboxService->IConsole_powerButton($console);
+
+ vboxService->ISession_unlockMachine($session);
+
+ vboxService->IWebsessionManager_logoff($vbox);
+}
+elsif ($optMode eq "openhd")
+{
+ my $medium = vboxService->IVirtualBox_openMedium($vbox, $disk,
+ 'HardDisk',
+ 'ReadWrite',
+ 0);
+}
diff --git a/src/VBox/Main/webservice/samples/php/clienttest.php b/src/VBox/Main/webservice/samples/php/clienttest.php
new file mode 100644
index 00000000..39552d2a
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/php/clienttest.php
@@ -0,0 +1,108 @@
+<?php
+/* $Id: clienttest.php $ */
+/*!file
+ * Sample client for the VirtualBox webservice, written in PHP.
+ *
+ * Run the VirtualBox web service server first; see the VirtualBox
+ * SDK reference for details.
+ *
+ * The following license applies to this file only:
+ */
+
+/*
+ * Contributed by James Lucas (mjlucas at eng.uts.edu.au).
+ *
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+
+require_once('./vboxServiceWrappers.php');
+
+//Connect to webservice
+$connection = new SoapClient("vboxwebService.wsdl", array('location' => "http://localhost:18083/"));
+
+//Logon to webservice
+$websessionManager = new IWebsessionManager($connection);
+// Dummy username and password (change to appropriate values or set authentication method to null)
+$virtualbox = $websessionManager->logon("username","password");
+
+//Get a list of registered machines
+$machines = $virtualbox->machines;
+
+//Take a screenshot of the first vm we find that is running
+foreach ($machines as $machine)
+{
+ if ( 'Running' == $machine->state )
+ {
+ $session = $websessionManager->getSessionObject($virtualbox->handle);
+ $uuid = $machine->id;
+ $machine->lockMachine($session->handle, "Shared");
+ try
+ {
+ $console = $session->console;
+ $display = $console->display;
+ list($screenWidth, $screenHeight, $screenBpp, $screenX, $screenY, $screenStatus) = $display->getScreenResolution(0 /* First screen */);
+
+ $imageraw = $display->takeScreenShotToArray(0 /* First screen */, $screenWidth, $screenHeight, "RGBA");
+ echo "Screenshot size: " . sizeof($imageraw) . "\n";
+
+ $filename = 'screenshot.png';
+ echo "Saving screenshot of " . $machine->name . " (${screenWidth}x${screenHeight}, ${screenBpp}BPP) to $filename\n";
+ $image = imagecreatetruecolor($screenWidth, $screenHeight);
+
+ for ($height = 0; $height < $screenHeight; $height++)
+ {
+ for ($width = 0; $width < $screenWidth; $width++)
+ {
+ $start = ($height*$screenWidth + $width)*4;
+ $red = $imageraw[$start];
+ $green = $imageraw[($start+1)];
+ $blue = $imageraw[($start+2)];
+ //$alpha = $image[$start+3];
+
+ $colour = imagecolorallocate($image, $red, $green, $blue);
+
+ imagesetpixel($image, $width, $height, $colour);
+ }
+ }
+
+ imagepng($image, $filename);
+ }
+ catch (Exception $ex)
+ {
+ echo $ex->getMessage();
+ }
+
+ $session->unlockMachine();
+
+ $machine->releaseRemote();
+ $session->releaseRemote();
+
+ break;
+ }
+}
+
+$websessionManager->logoff($virtualbox->handle);
+
+?>
+
diff --git a/src/VBox/Main/webservice/samples/python/Makefile b/src/VBox/Main/webservice/samples/python/Makefile
new file mode 100644
index 00000000..2430639b
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/python/Makefile
@@ -0,0 +1,39 @@
+# $Id: Makefile $
+## @file
+# Makefile for java samples.
+#
+
+#
+# Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+all: run
+
+run:
+ @echo !!!! Don\'t forget to start webserver with \"vboxwebsrv -t 10000\" !!!
+ PYTHONPATH=../lib python ../../../glue/python/sample/vboxshell.py -w
+
+server:
+ nohup vboxwebsrv -t 10000 &
+
diff --git a/src/VBox/Main/webservice/samples/python/Makefile.glue b/src/VBox/Main/webservice/samples/python/Makefile.glue
new file mode 100644
index 00000000..768bc242
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/python/Makefile.glue
@@ -0,0 +1,35 @@
+# $Id: Makefile.glue $
+## @file
+# Makefile for java samples.
+#
+
+#
+# Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+all: wrappers
+
+wrappers: ../../vboxwebService.wsdl ../../vboxweb.wsdl
+ wsdl2py -b --file $<
+
diff --git a/src/VBox/Main/webservice/samples/python/clienttest.py b/src/VBox/Main/webservice/samples/python/clienttest.py
new file mode 100755
index 00000000..2c4f3097
--- /dev/null
+++ b/src/VBox/Main/webservice/samples/python/clienttest.py
@@ -0,0 +1,132 @@
+#!/usr/bin/python
+
+__copyright__ = \
+"""
+Copyright (C) 2012-2022 Oracle and/or its affiliates.
+
+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.
+"""
+
+
+# Things needed to be set up before running this sample:
+# - Install Python and verify it works (2.7.2 will do, 3.x is untested yet)
+# - On Windows: Install the PyWin32 extensions for your Python version
+# (see http://sourceforge.net/projects/pywin32/)
+# - If not already done, set the environment variable "VBOX_INSTALL_PATH"
+# to point to your VirtualBox installation directory (which in turn must have
+# the "sdk" subfolder")
+# - Install the VirtualBox Python bindings by doing a
+# "[python] vboxapisetup.py install"
+# - Run this sample with "[python] clienttest.py"
+
+import os,sys
+import traceback
+
+#
+# Converts an enumeration to a printable string.
+#
+def enumToString(constants, enum, elem):
+ all = constants.all_values(enum)
+ for e in all.keys():
+ if str(elem) == str(all[e]):
+ return e
+ return "<unknown>"
+
+def main(argv):
+
+ from vboxapi import VirtualBoxManager
+ # This is a VirtualBox COM/XPCOM API client, no data needed.
+ mgr = VirtualBoxManager(None, None)
+
+ # Get the global VirtualBox object
+ vbox = mgr.getVirtualBox()
+
+ print "Running VirtualBox version %s" %(vbox.version)
+
+ # Get all constants through the Python manager code
+ vboxConstants = mgr.constants
+
+ # Enumerate all defined machines
+ for mach in mgr.getArray(vbox, 'machines'):
+
+ try:
+ # Be prepared for failures - the VM can be inaccessible
+ vmname = '<inaccessible>'
+ 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 == '<inaccessible>' 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))
+
+ # Do some stuff which requires a running VM
+ if mach.state == vboxConstants.MachineState_Running:
+
+ # Get the session object
+ session = mgr.getSessionObject()
+
+ # Lock the current machine (shared mode, since we won't modify the machine)
+ mach.lockMachine(session, vboxConstants.LockType_Shared)
+
+ # Acquire the VM's console and guest object
+ console = session.console
+ guest = console.guest
+
+ # Retrieve the current Guest Additions runlevel and print
+ # the installed Guest Additions version
+ addRunLevel = guest.additionsRunLevel
+ print " Additions State: %s" %(enumToString(vboxConstants, "AdditionsRunLevelType", addRunLevel))
+ if addRunLevel != vboxConstants.AdditionsRunLevelType_None:
+ print " Additions Ver: %s" %(guest.additionsVersion)
+
+ # Get the VM's display object
+ display = console.display
+
+ # Get the VM's current display resolution + bit depth + position
+ screenNum = 0 # From first screen
+ (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()
+
+ except Exception, e:
+ print "Errror [%s]: %s" %(mach.name, str(e))
+ traceback.print_exc()
+
+ # Call destructor and delete manager
+ del mgr
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/src/VBox/Main/webservice/soap-header-strip-inline.sed b/src/VBox/Main/webservice/soap-header-strip-inline.sed
new file mode 100644
index 00000000..be8a02bd
--- /dev/null
+++ b/src/VBox/Main/webservice/soap-header-strip-inline.sed
@@ -0,0 +1,35 @@
+# $Id: soap-header-strip-inline.sed $
+## @file
+# WebService - SED script for stripping inlined bodies from soapH.h.
+#
+
+#
+# Copyright (C) 2020-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+/^inline /,/^}/ {
+ /^inline/,/^{/ {
+ s/^inline/\/\*noinline\*\//
+ s/^{.*/;/
+ p
+ }
+ d
+}
diff --git a/src/VBox/Main/webservice/soap-header-to-inline-source-file.sed b/src/VBox/Main/webservice/soap-header-to-inline-source-file.sed
new file mode 100644
index 00000000..3e540848
--- /dev/null
+++ b/src/VBox/Main/webservice/soap-header-to-inline-source-file.sed
@@ -0,0 +1,38 @@
+# $Id: soap-header-to-inline-source-file.sed $
+## @file
+# WebService - SED script for extracting inline functions from soapH.h
+# for putting them in a C++ source file.
+#
+
+#
+# Copyright (C) 2020-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+/^inline /,/^}/ {
+ /^inline /,/^{/ {
+ s/^inline/\n\/\*noinline\*\//
+ s/ *= *\([^,)]*\)\([),]\)/ \/\*=\1\*\/\2/
+ }
+ p
+}
+1 c #include "soapH.h"
+d
+
diff --git a/src/VBox/Main/webservice/split-soapC.cpp b/src/VBox/Main/webservice/split-soapC.cpp
new file mode 100644
index 00000000..1a8b3493
--- /dev/null
+++ b/src/VBox/Main/webservice/split-soapC.cpp
@@ -0,0 +1,236 @@
+/* $Id: split-soapC.cpp $ */
+/** @file
+ * Splits soapC.cpp and soapH-noinline.cpp into more manageable portions.
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/types.h>
+#include <iprt/path.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+
+static char *readfileIntoBuffer(const char *pszFile, size_t *pcbFile)
+{
+ FILE *pFileIn = fopen(pszFile, "rb");
+ if (pFileIn)
+ {
+ int rc2 = fseek(pFileIn, 0, SEEK_END);
+ long cbFileIn = ftell(pFileIn);
+ int rc3 = fseek(pFileIn, 0, SEEK_SET);
+ if (rc3 != -1 && rc2 != -1 && cbFileIn >= 0)
+ {
+ char *pBuffer = (char *)malloc(cbFileIn + 1);
+ if (pBuffer)
+ {
+ size_t cbRead = fread(pBuffer, 1, cbFileIn, pFileIn);
+ if (cbRead == (size_t)cbFileIn)
+ {
+ pBuffer[cbFileIn] = '\0';
+ fclose(pFileIn);
+ *pcbFile = (size_t)cbFileIn;
+ return pBuffer;
+ }
+
+ fprintf(stderr, "split-soapC: Failed to read %ld bytes from input file.\n", cbFileIn);
+ free(pBuffer);
+ }
+ else
+ fprintf(stderr, "split-soapC: Failed to allocate %ld bytes.\n", cbFileIn);
+ }
+ else
+ fprintf(stderr, "split-soapC: Seek failure.\n");
+ fclose(pFileIn);
+ }
+ else
+ fprintf(stderr, "split-soapC: Cannot open file \"%s\" for reading.\n", pszFile);
+ return NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+ /*
+ * Check argument count.
+ */
+ if (argc != 4)
+ {
+ fprintf(stderr, "split-soapC: Must be started with exactly four arguments,\n"
+ "1) the input file, 2) the output filename prefix and\n"
+ "3) the number chunks to create.");
+ return RTEXITCODE_SYNTAX;
+ }
+
+ /*
+ * Number of chunks (argv[3]).
+ */
+ char *pszEnd = NULL;
+ unsigned long cChunks = strtoul(argv[3], &pszEnd, 0);
+ if (cChunks == ULONG_MAX || cChunks == 0 || !argv[3] || *pszEnd)
+ {
+ fprintf(stderr, "split-soapC: Given argument \"%s\" is not a valid chunk count.\n", argv[3]);
+ return RTEXITCODE_SYNTAX;
+ }
+
+ /*
+ * Read the input file into a zero terminated memory buffer.
+ */
+ size_t cbFileIn;
+ char *pszBuffer = readfileIntoBuffer(argv[1], &cbFileIn);
+ if (!pszBuffer)
+ return RTEXITCODE_FAILURE;
+
+ /*
+ * Split the file.
+ */
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ FILE *pFileOut = NULL;
+ const char *pszLine = pszBuffer;
+ size_t cbChunk = cbFileIn / cChunks;
+ unsigned long cFiles = 0;
+ size_t cbLimit = 0;
+ size_t cbWritten = 0;
+ unsigned long cIfNesting = 0;
+ unsigned long cWarningNesting = 0;
+ unsigned long cBraceNesting = 0;
+ unsigned long cLinesSinceStaticMap = ~0UL / 2;
+ bool fJustZero = false;
+
+ do
+ {
+ if (!pFileOut)
+ {
+ /* construct output filename */
+ char szFilename[1024];
+ sprintf(szFilename, "%s%lu.cpp", argv[2], ++cFiles);
+ szFilename[sizeof(szFilename)-1] = '\0';
+
+ size_t offName = strlen(szFilename);
+ while (offName > 0 && !RTPATH_IS_SEP(szFilename[offName - 1]))
+ offName -= 1;
+ printf("info: %s\n", &szFilename[offName]);
+
+ /* create output file */
+ pFileOut = fopen(szFilename, "wb");
+ if (!pFileOut)
+ {
+ fprintf(stderr, "split-soapC: Failed to open file \"%s\" for writing\n", szFilename);
+ rcExit = RTEXITCODE_FAILURE;
+ break;
+ }
+ if (cFiles > 1)
+ fprintf(pFileOut, "#include \"soapH.h\"%s\n",
+#ifdef RT_OS_WINDOWS
+ "\r"
+#else
+ ""
+#endif
+ );
+ cbLimit += cbChunk;
+ cLinesSinceStaticMap = ~0UL / 2;
+ }
+
+ /* find begin of next line and print current line */
+ const char *pszNextLine = strchr(pszLine, '\n');
+ size_t cbLine;
+ if (pszNextLine)
+ {
+ pszNextLine++;
+ cbLine = pszNextLine - pszLine;
+ }
+ else
+ cbLine = strlen(pszLine);
+ if (fwrite(pszLine, 1, cbLine, pFileOut) != cbLine)
+ {
+ fprintf(stderr, "split-soapC: Failed to write to output file\n");
+ rcExit = RTEXITCODE_FAILURE;
+ break;
+ }
+ cbWritten += cbLine;
+
+ /* process nesting depth information */
+ if (!strncmp(pszLine, "#if", 3))
+ cIfNesting++;
+ else if (!strncmp(pszLine, "#endif", 6))
+ {
+ cIfNesting--;
+ if (!cBraceNesting && !cIfNesting)
+ fJustZero = true;
+ }
+ else if (!strncmp(pszLine, RT_STR_TUPLE("#pragma warning(push)")))
+ cWarningNesting++;
+ else if (!strncmp(pszLine, RT_STR_TUPLE("#pragma warning(pop)")))
+ cWarningNesting--;
+ else
+ {
+ for (const char *p = pszLine; p < pszLine + cbLine; p++)
+ {
+ if (*p == '{')
+ cBraceNesting++;
+ else if (*p == '}')
+ {
+ cBraceNesting--;
+ if (!cBraceNesting && !cIfNesting)
+ fJustZero = true;
+ }
+ }
+ }
+
+ /* look for static variables used for enum conversion. */
+ if (!strncmp(pszLine, "static const struct soap_code_map", sizeof("static const struct soap_code_map") - 1))
+ cLinesSinceStaticMap = 0;
+ else
+ cLinesSinceStaticMap++;
+
+ /* start a new output file if necessary and possible */
+ if ( cbWritten >= cbLimit
+ && cIfNesting == 0
+ && cWarningNesting == 0
+ && fJustZero
+ && cFiles < cChunks
+ && cLinesSinceStaticMap > 150 /*hack!*/)
+ {
+ fclose(pFileOut);
+ pFileOut = NULL;
+ }
+
+ fJustZero = false;
+ pszLine = pszNextLine;
+ } while (pszLine);
+
+ printf("split-soapC: Created %lu files.\n", (unsigned long)cFiles);
+
+ free(pszBuffer);
+ if (pFileOut)
+ fclose(pFileOut);
+
+ return rcExit;
+}
diff --git a/src/VBox/Main/webservice/stdsoap2.sed b/src/VBox/Main/webservice/stdsoap2.sed
new file mode 100644
index 00000000..6bb0f9d5
--- /dev/null
+++ b/src/VBox/Main/webservice/stdsoap2.sed
@@ -0,0 +1,31 @@
+# $Id: stdsoap2.sed $
+## @file
+# WebService - SED script for inserting a iprt/win/windows.h include
+# before stdsoap2.h in soapStub.h. This prevents hacking
+# client and server code to do the same when using -Wall.
+#
+
+#
+# Copyright (C) 2016-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+s/\(#include "stdsoap2\.h"\)/#ifdef RT_OS_WINDOWS\n# include <iprt\/win\/windows.h>\n#endif\n\1/
+
diff --git a/src/VBox/Main/webservice/types.txt b/src/VBox/Main/webservice/types.txt
new file mode 100644
index 00000000..c976d172
--- /dev/null
+++ b/src/VBox/Main/webservice/types.txt
@@ -0,0 +1,30 @@
+
+ XIDL IPRT COM XPCOM WSDL gSOAP default JAX-WS PHP
+
+ boolean BOOL PRBool xsd:boolean bool Boolean boolean
+
+ octet uint8_t BYTE PRUint8 xsd:unsignedByte Short integer
+
+ short int16_t SHORT PRInt16 xsd:short short Short (2) integer
+ unsigned short uint16_t USHORT PRUint16 xsd:unsignedShort unsigned short Integer (2) integer
+ long int32_t LONG PRInt32 xsd:int int Integer (2) integer
+ unsigned long uint32_t ULONG PRUint32 xsd:unsignedInt unsigned int Long (2) float (3)
+ long long int64_t LONG64 PRInt64 xsd:long long long Long (2) float (3)
+ unsigned long long uint64_t ULONG64 PRUint64 xsd:unsignedLong unsigned long long BigInteger (2) float (3)
+
+ double xsd:double double Double float
+ float xsd:float float Float float
+
+ wstring BSTR PRUnichar* xsd:string std::string String string
+
+ result xsd:unsignedInt(1) (undefined)
+
+ uuid xsd:string(1) (undefined)
+
+
+(1) my definition
+(2) Java "Short" is signed 16-bit integer; since Java has no support for unsigned types, we need to use the
+ next bigger class, which is Integer, for IPRT uint16_t. Similarly for the other integer types.
+(3) PHP does not support unsigned integers; Size of integer is platform-dependent, usual value of at least 32-bits signed. Use float for numbers greeted that signed 32-bit int
+
+
diff --git a/src/VBox/Main/webservice/vboxweb.cpp b/src/VBox/Main/webservice/vboxweb.cpp
new file mode 100644
index 00000000..a419c354
--- /dev/null
+++ b/src/VBox/Main/webservice/vboxweb.cpp
@@ -0,0 +1,2518 @@
+/* $Id: vboxweb.cpp $ */
+/** @file
+ * vboxweb.cpp:
+ * hand-coded parts of the webservice server. This is linked with the
+ * generated code in out/.../src/VBox/Main/webservice/methodmaps.cpp
+ * (plus static gSOAP server code) to implement the actual webservice
+ * server, to which clients can connect.
+ */
+
+/*
+ * Copyright (C) 2007-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+// shared webservice header
+#include "vboxweb.h"
+
+// vbox headers
+#include <VBox/com/com.h>
+#include <VBox/com/array.h>
+#include <VBox/com/string.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/com/listeners.h>
+#include <VBox/com/NativeEventQueue.h>
+#include <VBox/VBoxAuth.h>
+#include <VBox/version.h>
+#include <VBox/log.h>
+
+#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/ldr.h>
+#include <iprt/message.h>
+#include <iprt/process.h>
+#include <iprt/rand.h>
+#include <iprt/semaphore.h>
+#include <iprt/critsect.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+#include <iprt/path.h>
+#include <iprt/system.h>
+#include <iprt/base64.h>
+#include <iprt/stream.h>
+#include <iprt/asm.h>
+
+#ifdef WITH_OPENSSL
+# include <openssl/opensslv.h>
+#endif
+
+#ifndef RT_OS_WINDOWS
+# include <signal.h>
+#endif
+
+// workaround for compile problems on gcc 4.1
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+// gSOAP headers (must come after vbox includes because it checks for conflicting defs)
+#include "soapH.h"
+
+// standard headers
+#include <map>
+#include <list>
+
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+// include generated namespaces table
+#include "vboxwebsrv.nsmap"
+
+RT_C_DECLS_BEGIN
+
+// declarations for the generated WSDL text
+extern const unsigned char g_abVBoxWebWSDL[];
+extern const unsigned g_cbVBoxWebWSDL;
+
+RT_C_DECLS_END
+
+static void WebLogSoapError(struct soap *soap);
+
+/****************************************************************************
+ *
+ * private typedefs
+ *
+ ****************************************************************************/
+
+typedef std::map<uint64_t, ManagedObjectRef*> ManagedObjectsMapById;
+typedef ManagedObjectsMapById::iterator ManagedObjectsIteratorById;
+typedef std::map<uintptr_t, ManagedObjectRef*> ManagedObjectsMapByPtr;
+typedef ManagedObjectsMapByPtr::iterator ManagedObjectsIteratorByPtr;
+
+typedef std::map<uint64_t, WebServiceSession*> WebsessionsMap;
+typedef WebsessionsMap::iterator WebsessionsMapIterator;
+
+typedef std::map<RTTHREAD, com::Utf8Str> ThreadsMap;
+
+static DECLCALLBACK(int) fntWatchdog(RTTHREAD ThreadSelf, void *pvUser);
+
+/****************************************************************************
+ *
+ * Read-only global variables
+ *
+ ****************************************************************************/
+
+static ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
+
+// generated strings in methodmaps.cpp
+extern const char *g_pcszISession,
+ *g_pcszIVirtualBox,
+ *g_pcszIVirtualBoxErrorInfo;
+
+// globals for vboxweb command-line arguments
+#define DEFAULT_TIMEOUT_SECS 300
+#define DEFAULT_TIMEOUT_SECS_STRING "300"
+static int g_iWatchdogTimeoutSecs = DEFAULT_TIMEOUT_SECS;
+static int g_iWatchdogCheckInterval = 5;
+
+static const char *g_pcszBindToHost = NULL; // host; NULL = localhost
+static unsigned int g_uBindToPort = 18083; // port
+static unsigned int g_uBacklog = 100; // backlog = max queue size for requests
+
+#ifdef WITH_OPENSSL
+static bool g_fSSL = false; // if SSL is enabled
+static const char *g_pcszKeyFile = NULL; // server key file
+static const char *g_pcszPassword = NULL; // password for server key
+static const char *g_pcszCACert = NULL; // file with trusted CA certificates
+static const char *g_pcszCAPath = NULL; // directory with trusted CA certificates
+static const char *g_pcszDHFile = NULL; // DH file name or DH key length in bits, NULL=use RSA
+static const char *g_pcszRandFile = NULL; // file with random data seed
+static const char *g_pcszSID = "vboxwebsrv"; // server ID for SSL session cache
+#endif /* WITH_OPENSSL */
+
+static unsigned int g_cMaxWorkerThreads = 100; // max. no. of worker threads
+static unsigned int g_cMaxKeepAlive = 100; // maximum number of soap requests in one connection
+
+static const char *g_pcszAuthentication = NULL; // web service authentication
+
+static uint32_t g_cHistory = 10; // enable log rotation, 10 files
+static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
+static uint64_t g_uHistoryFileSize = 100 * _1M; // max 100MB per file
+bool g_fVerbose = false; // be verbose
+
+static bool g_fDaemonize = false; // run in background.
+static volatile bool g_fKeepRunning = true; // controlling the exit
+
+const WSDLT_ID g_EmptyWSDLID; // for NULL MORs
+
+/****************************************************************************
+ *
+ * Writeable global variables
+ *
+ ****************************************************************************/
+
+// The one global SOAP queue created by main().
+class SoapQ;
+static SoapQ *g_pSoapQ = NULL;
+
+// this mutex protects the auth lib and authentication
+static util::WriteLockHandle *g_pAuthLibLockHandle;
+
+// this mutex protects the global VirtualBox reference below
+static util::RWLockHandle *g_pVirtualBoxLockHandle;
+
+static ComPtr<IVirtualBox> g_pVirtualBox = NULL;
+
+// this mutex protects all of the below
+util::WriteLockHandle *g_pWebsessionsLockHandle;
+
+static WebsessionsMap g_mapWebsessions;
+static ULONG64 g_cManagedObjects = 0;
+
+// this mutex protects g_mapThreads
+static util::RWLockHandle *g_pThreadsLockHandle;
+
+// Threads map, so we can quickly map an RTTHREAD struct to a logger prefix
+static ThreadsMap g_mapThreads;
+
+/****************************************************************************
+ *
+ * Command line help
+ *
+ ****************************************************************************/
+
+static const RTGETOPTDEF g_aOptions[]
+ = {
+ { "--help", 'h', RTGETOPT_REQ_NOTHING }, /* for DisplayHelp() */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+ { "--background", 'b', RTGETOPT_REQ_NOTHING },
+#endif
+ { "--host", 'H', RTGETOPT_REQ_STRING },
+ { "--port", 'p', RTGETOPT_REQ_UINT32 },
+#ifdef WITH_OPENSSL
+ { "--ssl", 's', RTGETOPT_REQ_NOTHING },
+ { "--keyfile", 'K', RTGETOPT_REQ_STRING },
+ { "--passwordfile", 'a', RTGETOPT_REQ_STRING },
+ { "--cacert", 'c', RTGETOPT_REQ_STRING },
+ { "--capath", 'C', RTGETOPT_REQ_STRING },
+ { "--dhfile", 'D', RTGETOPT_REQ_STRING },
+ { "--randfile", 'r', RTGETOPT_REQ_STRING },
+#endif /* WITH_OPENSSL */
+ { "--timeout", 't', RTGETOPT_REQ_UINT32 },
+ { "--check-interval", 'i', RTGETOPT_REQ_UINT32 },
+ { "--threads", 'T', RTGETOPT_REQ_UINT32 },
+ { "--keepalive", 'k', RTGETOPT_REQ_UINT32 },
+ { "--authentication", 'A', RTGETOPT_REQ_STRING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ { "--pidfile", 'P', RTGETOPT_REQ_STRING },
+ { "--logfile", 'F', RTGETOPT_REQ_STRING },
+ { "--logrotate", 'R', RTGETOPT_REQ_UINT32 },
+ { "--logsize", 'S', RTGETOPT_REQ_UINT64 },
+ { "--loginterval", 'I', RTGETOPT_REQ_UINT32 }
+ };
+
+static void DisplayHelp()
+{
+ RTStrmPrintf(g_pStdErr, "\nUsage: vboxwebsrv [options]\n\nSupported options (default values in brackets):\n");
+ for (unsigned i = 0;
+ i < RT_ELEMENTS(g_aOptions);
+ ++i)
+ {
+ std::string str(g_aOptions[i].pszLong);
+ str += ", -";
+ str += g_aOptions[i].iShort;
+ str += ":";
+
+ const char *pcszDescr = "";
+
+ switch (g_aOptions[i].iShort)
+ {
+ case 'h':
+ pcszDescr = "Print this help message and exit.";
+ break;
+
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+ case 'b':
+ pcszDescr = "Run in background (daemon mode).";
+ break;
+#endif
+
+ case 'H':
+ pcszDescr = "The host to bind to (localhost).";
+ break;
+
+ case 'p':
+ pcszDescr = "The port to bind to (18083).";
+ break;
+
+#ifdef WITH_OPENSSL
+ case 's':
+ pcszDescr = "Enable SSL/TLS encryption.";
+ break;
+
+ case 'K':
+ pcszDescr = "Server key and certificate file, PEM format (\"\").";
+ break;
+
+ case 'a':
+ pcszDescr = "File name for password to server key (\"\").";
+ break;
+
+ case 'c':
+ pcszDescr = "CA certificate file, PEM format (\"\").";
+ break;
+
+ case 'C':
+ pcszDescr = "CA certificate path (\"\").";
+ break;
+
+ case 'D':
+ pcszDescr = "DH file name or DH key length in bits (\"\").";
+ break;
+
+ case 'r':
+ pcszDescr = "File containing seed for random number generator (\"\").";
+ break;
+#endif /* WITH_OPENSSL */
+
+ case 't':
+ pcszDescr = "Session timeout in seconds; 0 = disable timeouts (" DEFAULT_TIMEOUT_SECS_STRING ").";
+ break;
+
+ case 'T':
+ pcszDescr = "Maximum number of worker threads to run in parallel (100).";
+ break;
+
+ case 'k':
+ pcszDescr = "Maximum number of requests before a socket will be closed (100).";
+ break;
+
+ case 'A':
+ pcszDescr = "Authentication method for the webservice (\"\").";
+ break;
+
+ case 'i':
+ pcszDescr = "Frequency of timeout checks in seconds (5).";
+ break;
+
+ case 'v':
+ pcszDescr = "Be verbose.";
+ break;
+
+ case 'P':
+ pcszDescr = "Name of the PID file which is created when the daemon was started.";
+ break;
+
+ case 'F':
+ pcszDescr = "Name of file to write log to (no file).";
+ break;
+
+ case 'R':
+ pcszDescr = "Number of log files (0 disables log rotation).";
+ break;
+
+ case 'S':
+ pcszDescr = "Maximum size of a log file to trigger rotation (bytes).";
+ break;
+
+ case 'I':
+ pcszDescr = "Maximum time interval to trigger log rotation (seconds).";
+ break;
+ }
+
+ RTStrmPrintf(g_pStdErr, "%-23s%s\n", str.c_str(), pcszDescr);
+ }
+}
+
+/****************************************************************************
+ *
+ * SoapQ, SoapThread (multithreading)
+ *
+ ****************************************************************************/
+
+class SoapQ;
+
+class SoapThread
+{
+public:
+ /**
+ * Constructor. Creates the new thread and makes it call process() for processing the queue.
+ * @param u Thread number. (So we can count from 1 and be readable.)
+ * @param q SoapQ instance which has the queue to process.
+ * @param soap struct soap instance from main() which we copy here.
+ */
+ SoapThread(size_t u,
+ SoapQ &q,
+ const struct soap *soap)
+ : m_u(u),
+ m_strThread(com::Utf8StrFmt("SQW%02d", m_u)),
+ m_pQ(&q)
+ {
+ // make a copy of the soap struct for the new thread
+ m_soap = soap_copy(soap);
+ m_soap->fget = fnHttpGet;
+
+ /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed,
+ * which is important to avoid a client from holding a thread indefinitely.
+ * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive
+ *
+ * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is
+ * possible by enabling the SOAP_C_UTFSTRING flag.
+ */
+ soap_set_omode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
+ soap_set_imode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
+ m_soap->max_keep_alive = g_cMaxKeepAlive;
+
+ int rc = RTThreadCreate(&m_pThread,
+ fntWrapper,
+ this, // pvUser
+ 0, // cbStack
+ RTTHREADTYPE_MAIN_HEAVY_WORKER,
+ 0,
+ m_strThread.c_str());
+ if (RT_FAILURE(rc))
+ {
+ RTMsgError("Cannot start worker thread %d: %Rrc\n", u, rc);
+ exit(1);
+ }
+ }
+
+ void process();
+
+ static int fnHttpGet(struct soap *soap)
+ {
+ char *s = strchr(soap->path, '?');
+ if (!s || strcmp(s, "?wsdl"))
+ return SOAP_GET_METHOD;
+ soap_response(soap, SOAP_HTML);
+ soap_send_raw(soap, (const char *)g_abVBoxWebWSDL, g_cbVBoxWebWSDL);
+ soap_end_send(soap);
+ return SOAP_OK;
+ }
+
+ /**
+ * Static function that can be passed to RTThreadCreate and that calls
+ * process() on the SoapThread instance passed as the thread parameter.
+ *
+ * @param hThreadSelf
+ * @param pvThread
+ * @return
+ */
+ static DECLCALLBACK(int) fntWrapper(RTTHREAD hThreadSelf, void *pvThread)
+ {
+ RT_NOREF(hThreadSelf);
+ SoapThread *pst = (SoapThread*)pvThread;
+ pst->process();
+ return VINF_SUCCESS;
+ }
+
+ size_t m_u; // thread number
+ com::Utf8Str m_strThread; // thread name ("SoapQWrkXX")
+ SoapQ *m_pQ; // the single SOAP queue that all the threads service
+ struct soap *m_soap; // copy of the soap structure for this thread (from soap_copy())
+ RTTHREAD m_pThread; // IPRT thread struct for this thread
+};
+
+/**
+ * SOAP queue encapsulation. There is only one instance of this, to
+ * which add() adds a queue item (called on the main thread),
+ * and from which get() fetch items, called from each queue thread.
+ */
+class SoapQ
+{
+public:
+
+ /**
+ * Constructor. Creates the soap queue.
+ * @param pSoap
+ */
+ SoapQ(const struct soap *pSoap)
+ : m_soap(pSoap),
+ m_mutex(util::LOCKCLASS_OBJECTSTATE), // lowest lock order, no other may be held while this is held
+ m_cIdleThreads(0)
+ {
+ RTSemEventMultiCreate(&m_event);
+ }
+
+ ~SoapQ()
+ {
+ /* Tell the threads to terminate. */
+ RTSemEventMultiSignal(m_event);
+ {
+ util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
+ int i = 0;
+ while (m_llAllThreads.size() && i++ <= 30)
+ {
+ qlock.release();
+ RTThreadSleep(1000);
+ RTSemEventMultiSignal(m_event);
+ qlock.acquire();
+ }
+ LogRel(("ending queue processing (%d out of %d threads idle)\n", m_cIdleThreads, m_llAllThreads.size()));
+ }
+
+ RTSemEventMultiDestroy(m_event);
+ }
+
+ /**
+ * Adds the given socket to the SOAP queue and posts the
+ * member event sem to wake up the workers. Called on the main thread
+ * whenever a socket has work to do. Creates a new SOAP thread on the
+ * first call or when all existing threads are busy.
+ * @param s Socket from soap_accept() which has work to do.
+ */
+ size_t add(SOAP_SOCKET s)
+ {
+ 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,
+ // create a new SOAP thread
+ if ( !m_cIdleThreads
+ // but only if we're not exceeding the global maximum (default is 100)
+ && (m_llAllThreads.size() < g_cMaxWorkerThreads)
+ )
+ {
+ SoapThread *pst = new SoapThread(m_llAllThreads.size() + 1,
+ *this,
+ m_soap);
+ m_llAllThreads.push_back(pst);
+ util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
+ g_mapThreads[pst->m_pThread] = com::Utf8StrFmt("[%3u]", pst->m_u);
+ ++m_cIdleThreads;
+ }
+
+ // enqueue the socket of this connection and post eventsem so that
+ // one of the threads (possibly the one just created) can pick it up
+ m_llSocketsQ.push_back(s);
+ cItems = m_llSocketsQ.size();
+ qlock.release();
+
+ // unblock one of the worker threads
+ RTSemEventMultiSignal(m_event);
+
+ return cItems;
+ }
+
+ /**
+ * Blocks the current thread until work comes in; then returns
+ * the SOAP socket which has work to do. This reduces m_cIdleThreads
+ * by one, and the caller MUST call done() when it's done processing.
+ * Called from the worker threads.
+ * @param cIdleThreads out: no. of threads which are currently idle (not counting the caller)
+ * @param cThreads out: total no. of SOAP threads running
+ * @return
+ */
+ SOAP_SOCKET get(size_t &cIdleThreads, size_t &cThreads)
+ {
+ while (g_fKeepRunning)
+ {
+ // wait for something to happen
+ RTSemEventMultiWait(m_event, RT_INDEFINITE_WAIT);
+
+ if (!g_fKeepRunning)
+ break;
+
+ util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
+ if (!m_llSocketsQ.empty())
+ {
+ SOAP_SOCKET socket = m_llSocketsQ.front();
+ m_llSocketsQ.pop_front();
+ cIdleThreads = --m_cIdleThreads;
+ cThreads = m_llAllThreads.size();
+
+ // reset the multi event only if the queue is now empty; otherwise
+ // another thread will also wake up when we release the mutex and
+ // process another one
+ if (m_llSocketsQ.empty())
+ RTSemEventMultiReset(m_event);
+
+ qlock.release();
+
+ return socket;
+ }
+
+ // nothing to do: keep looping
+ }
+ return SOAP_INVALID_SOCKET;
+ }
+
+ /**
+ * To be called by a worker thread after fetching an item from the
+ * queue via get() and having finished its lengthy processing.
+ */
+ void done()
+ {
+ util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
+ ++m_cIdleThreads;
+ }
+
+ /**
+ * To be called by a worker thread when signing off, i.e. no longer
+ * willing to process requests.
+ */
+ void signoff(SoapThread *th)
+ {
+ {
+ util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
+ size_t c = g_mapThreads.erase(th->m_pThread);
+ AssertReturnVoid(c == 1);
+ }
+ {
+ util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
+ m_llAllThreads.remove(th);
+ --m_cIdleThreads;
+ }
+ }
+
+ const struct soap *m_soap; // soap structure created by main(), passed to constructor
+
+ util::WriteLockHandle m_mutex;
+ RTSEMEVENTMULTI m_event; // posted by add(), blocked on by get()
+
+ std::list<SoapThread*> m_llAllThreads; // all the threads created by the constructor
+ size_t m_cIdleThreads; // threads which are currently idle (statistics)
+
+ // A std::list abused as a queue; this contains the actual jobs to do,
+ // each int being a socket from soap_accept()
+ std::list<SOAP_SOCKET> m_llSocketsQ;
+};
+
+/**
+ * Thread function for each of the SOAP queue worker threads. This keeps
+ * running, blocks on the event semaphore in SoapThread.SoapQ and picks
+ * up a socket from the queue therein, which has been put there by
+ * beginProcessing().
+ */
+void SoapThread::process()
+{
+ LogRel(("New SOAP thread started\n"));
+
+ while (g_fKeepRunning)
+ {
+ // wait for a socket to arrive on the queue
+ size_t cIdleThreads = 0, cThreads = 0;
+ m_soap->socket = m_pQ->get(cIdleThreads, cThreads);
+
+ if (!soap_valid_socket(m_soap->socket))
+ continue;
+
+ LogRel(("Processing connection from IP=%RTnaipv4 socket=%d (%d out of %d threads idle)\n",
+ RT_H2N_U32(m_soap->ip), m_soap->socket, cIdleThreads, cThreads));
+
+ // Ensure that we don't get stuck indefinitely for connections using
+ // keepalive, otherwise stale connections tie up worker threads.
+ m_soap->send_timeout = 60;
+ m_soap->recv_timeout = 60;
+ // Limit the maximum SOAP request size to a generous amount, just to
+ // be on the safe side (SOAP is quite wordy when representing arrays,
+ // and some API uses need to deal with large arrays). Good that binary
+ // data is no longer represented by byte arrays...
+ m_soap->recv_maxlength = _16M;
+ // process the request; this goes into the COM code in methodmaps.cpp
+ do {
+#ifdef WITH_OPENSSL
+ if (g_fSSL && soap_ssl_accept(m_soap))
+ {
+ WebLogSoapError(m_soap);
+ break;
+ }
+#endif /* WITH_OPENSSL */
+ soap_serve(m_soap);
+ } while (0);
+
+ soap_destroy(m_soap); // clean up class instances
+ soap_end(m_soap); // clean up everything and close socket
+
+ // tell the queue we're idle again
+ m_pQ->done();
+ }
+ m_pQ->signoff(this);
+}
+
+/****************************************************************************
+ *
+ * VirtualBoxClient event listener
+ *
+ ****************************************************************************/
+
+class VirtualBoxClientEventListener
+{
+public:
+ VirtualBoxClientEventListener()
+ {
+ }
+
+ virtual ~VirtualBoxClientEventListener()
+ {
+ }
+
+ HRESULT init()
+ {
+ return S_OK;
+ }
+
+ void uninit()
+ {
+ }
+
+
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
+ {
+ switch (aType)
+ {
+ case VBoxEventType_OnVBoxSVCAvailabilityChanged:
+ {
+ ComPtr<IVBoxSVCAvailabilityChangedEvent> pVSACEv = aEvent;
+ Assert(pVSACEv);
+ BOOL fAvailable = FALSE;
+ pVSACEv->COMGETTER(Available)(&fAvailable);
+ if (!fAvailable)
+ {
+ LogRel(("VBoxSVC became unavailable\n"));
+ {
+ util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+ g_pVirtualBox.setNull();
+ }
+ {
+ // we're messing with websessions, so lock them
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+ WEBDEBUG(("SVC unavailable: deleting %d websessions\n", g_mapWebsessions.size()));
+
+ WebsessionsMapIterator it = g_mapWebsessions.begin(),
+ itEnd = g_mapWebsessions.end();
+ while (it != itEnd)
+ {
+ WebServiceSession *pWebsession = it->second;
+ WEBDEBUG(("SVC unavailable: websession %#llx stale, deleting\n", pWebsession->getID()));
+ delete pWebsession;
+ it = g_mapWebsessions.begin();
+ }
+ }
+ }
+ else
+ {
+ LogRel(("VBoxSVC became available\n"));
+ util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+ HRESULT hrc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam());
+ AssertComRC(hrc);
+ }
+ break;
+ }
+ default:
+ AssertFailed();
+ }
+
+ return S_OK;
+ }
+
+private:
+};
+
+typedef ListenerImpl<VirtualBoxClientEventListener> VirtualBoxClientEventListenerImpl;
+
+VBOX_LISTENER_DECLARE(VirtualBoxClientEventListenerImpl)
+
+/**
+ * Helper for printing SOAP error messages.
+ * @param soap
+ */
+/*static*/
+void WebLogSoapError(struct soap *soap)
+{
+ if (soap_check_state(soap))
+ {
+ LogRel(("Error: soap struct not initialized\n"));
+ return;
+ }
+
+ const char *pcszFaultString = *soap_faultstring(soap);
+ const char **ppcszDetail = soap_faultcode(soap);
+ LogRel(("#### SOAP FAULT: %s [%s]\n",
+ pcszFaultString ? pcszFaultString : "[no fault string available]",
+ (ppcszDetail && *ppcszDetail) ? *ppcszDetail : "no details available"));
+}
+
+/**
+ * Helper for decoding AuthResult.
+ * @param result AuthResult
+ */
+static const char * decodeAuthResult(AuthResult result)
+{
+ switch (result)
+ {
+ case AuthResultAccessDenied: return "access DENIED";
+ case AuthResultAccessGranted: return "access granted";
+ case AuthResultDelegateToGuest: return "delegated to guest";
+ default: return "unknown AuthResult";
+ }
+}
+
+#if defined(WITH_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER))
+/****************************************************************************
+ *
+ * OpenSSL convenience functions for multithread support.
+ * Not required for OpenSSL 1.1+
+ *
+ ****************************************************************************/
+
+static RTCRITSECT *g_pSSLMutexes = NULL;
+
+struct CRYPTO_dynlock_value
+{
+ RTCRITSECT mutex;
+};
+
+static unsigned long CRYPTO_id_function()
+{
+ return (unsigned long)RTThreadNativeSelf();
+}
+
+static void CRYPTO_locking_function(int mode, int n, const char * /*file*/, int /*line*/)
+{
+ if (mode & CRYPTO_LOCK)
+ RTCritSectEnter(&g_pSSLMutexes[n]);
+ else
+ RTCritSectLeave(&g_pSSLMutexes[n]);
+}
+
+static struct CRYPTO_dynlock_value *CRYPTO_dyn_create_function(const char * /*file*/, int /*line*/)
+{
+ static uint32_t s_iCritSectDynlock = 0;
+ struct CRYPTO_dynlock_value *value = (struct CRYPTO_dynlock_value *)RTMemAlloc(sizeof(struct CRYPTO_dynlock_value));
+ if (value)
+ RTCritSectInitEx(&value->mutex, RTCRITSECT_FLAGS_NO_LOCK_VAL,
+ NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE,
+ "openssl-dyn-%u", ASMAtomicIncU32(&s_iCritSectDynlock) - 1);
+
+ return value;
+}
+
+static void CRYPTO_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *value, const char * /*file*/, int /*line*/)
+{
+ if (mode & CRYPTO_LOCK)
+ RTCritSectEnter(&value->mutex);
+ else
+ RTCritSectLeave(&value->mutex);
+}
+
+static void CRYPTO_dyn_destroy_function(struct CRYPTO_dynlock_value *value, const char * /*file*/, int /*line*/)
+{
+ if (value)
+ {
+ RTCritSectDelete(&value->mutex);
+ free(value);
+ }
+}
+
+static int CRYPTO_thread_setup()
+{
+ int num_locks = CRYPTO_num_locks();
+ g_pSSLMutexes = (RTCRITSECT *)RTMemAlloc(num_locks * sizeof(RTCRITSECT));
+ if (!g_pSSLMutexes)
+ return SOAP_EOM;
+
+ for (int i = 0; i < num_locks; i++)
+ {
+ int rc = RTCritSectInitEx(&g_pSSLMutexes[i], RTCRITSECT_FLAGS_NO_LOCK_VAL,
+ NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE,
+ "openssl-%d", i);
+ if (RT_FAILURE(rc))
+ {
+ for ( ; i >= 0; i--)
+ RTCritSectDelete(&g_pSSLMutexes[i]);
+ RTMemFree(g_pSSLMutexes);
+ g_pSSLMutexes = NULL;
+ return SOAP_EOM;
+ }
+ }
+
+ CRYPTO_set_id_callback(CRYPTO_id_function);
+ CRYPTO_set_locking_callback(CRYPTO_locking_function);
+ CRYPTO_set_dynlock_create_callback(CRYPTO_dyn_create_function);
+ CRYPTO_set_dynlock_lock_callback(CRYPTO_dyn_lock_function);
+ CRYPTO_set_dynlock_destroy_callback(CRYPTO_dyn_destroy_function);
+
+ return SOAP_OK;
+}
+
+static void CRYPTO_thread_cleanup()
+{
+ if (!g_pSSLMutexes)
+ return;
+
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_dynlock_create_callback(NULL);
+ CRYPTO_set_dynlock_lock_callback(NULL);
+ CRYPTO_set_dynlock_destroy_callback(NULL);
+
+ int num_locks = CRYPTO_num_locks();
+ for (int i = 0; i < num_locks; i++)
+ RTCritSectDelete(&g_pSSLMutexes[i]);
+
+ RTMemFree(g_pSSLMutexes);
+ g_pSSLMutexes = NULL;
+}
+#endif /* WITH_OPENSSL && (OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER)) */
+
+/****************************************************************************
+ *
+ * SOAP queue pumper thread
+ *
+ ****************************************************************************/
+
+static void doQueuesLoop()
+{
+#if defined(WITH_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER))
+ if (g_fSSL && CRYPTO_thread_setup())
+ {
+ LogRel(("Failed to set up OpenSSL thread mutex!"));
+ exit(RTEXITCODE_FAILURE);
+ }
+#endif
+
+ // set up gSOAP
+ struct soap soap;
+ soap_init(&soap);
+
+#ifdef WITH_OPENSSL
+ if (g_fSSL && soap_ssl_server_context(&soap, SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION | SOAP_TLSv1, g_pcszKeyFile,
+ g_pcszPassword, g_pcszCACert, g_pcszCAPath,
+ g_pcszDHFile, g_pcszRandFile, g_pcszSID))
+ {
+ WebLogSoapError(&soap);
+ exit(RTEXITCODE_FAILURE);
+ }
+#endif /* WITH_OPENSSL */
+
+ soap.bind_flags |= SO_REUSEADDR;
+ // avoid EADDRINUSE on bind()
+
+ SOAP_SOCKET m, s; // master and slave sockets
+ m = soap_bind(&soap,
+ g_pcszBindToHost ? g_pcszBindToHost : "localhost", // safe default host
+ g_uBindToPort, // port
+ g_uBacklog); // backlog = max queue size for requests
+ if (m == SOAP_INVALID_SOCKET)
+ WebLogSoapError(&soap);
+ else
+ {
+#ifdef WITH_OPENSSL
+ const char *pszSsl = g_fSSL ? "SSL, " : "";
+#else /* !WITH_OPENSSL */
+ const char *pszSsl = "";
+#endif /*!WITH_OPENSSL */
+ LogRel(("Socket connection successful: host = %s, port = %u, %smaster socket = %d\n",
+ (g_pcszBindToHost) ? g_pcszBindToHost : "default (localhost)",
+ g_uBindToPort, pszSsl, m));
+
+ // initialize thread queue, mutex and eventsem
+ g_pSoapQ = new SoapQ(&soap);
+
+ uint64_t cAccepted = 1;
+ while (g_fKeepRunning)
+ {
+ struct timeval timeout;
+ fd_set ReadFds, WriteFds, XcptFds;
+ int rv;
+ for (;;)
+ {
+ timeout.tv_sec = 60;
+ timeout.tv_usec = 0;
+ FD_ZERO(&ReadFds);
+ FD_SET(soap.master, &ReadFds);
+ FD_ZERO(&WriteFds);
+ FD_SET(soap.master, &WriteFds);
+ FD_ZERO(&XcptFds);
+ FD_SET(soap.master, &XcptFds);
+ rv = select((int)soap.master + 1, &ReadFds, &WriteFds, &XcptFds, &timeout);
+ if (rv > 0)
+ break; // work is waiting
+ if (rv == 0)
+ continue; // timeout, not necessary to bother gsoap
+ // r < 0, errno
+#if GSOAP_VERSION >= 208103
+ if (soap_socket_errno == SOAP_EINTR)
+#else
+ if (soap_socket_errno(soap.master) == SOAP_EINTR)
+#endif
+ rv = 0; // re-check if we should terminate
+ break;
+ }
+ if (rv == 0)
+ continue;
+
+ // call gSOAP to handle incoming SOAP connection
+ soap.accept_timeout = -1; // 1usec timeout, actual waiting is above
+ s = soap_accept(&soap);
+ if (!soap_valid_socket(s))
+ {
+ if (soap.errnum)
+ WebLogSoapError(&soap);
+ continue;
+ }
+
+ // add the socket to the queue and tell worker threads to
+ // pick up the job
+ size_t cItemsOnQ = g_pSoapQ->add(s);
+ LogRel(("Request %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ));
+ cAccepted++;
+ }
+
+ delete g_pSoapQ;
+ g_pSoapQ = NULL;
+
+ LogRel(("ending SOAP request handling\n"));
+
+ delete g_pSoapQ;
+ g_pSoapQ = NULL;
+
+ }
+ soap_done(&soap); // close master socket and detach environment
+
+#if defined(WITH_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_NUMBER))
+ if (g_fSSL)
+ CRYPTO_thread_cleanup();
+#endif
+}
+
+/**
+ * Thread function for the "queue pumper" thread started from main(). This implements
+ * the loop that takes SOAP calls from HTTP and serves them by handing sockets to the
+ * SOAP queue worker threads.
+ */
+static DECLCALLBACK(int) fntQPumper(RTTHREAD hThreadSelf, void *pvUser)
+{
+ RT_NOREF(hThreadSelf, pvUser);
+
+ // store a log prefix for this thread
+ util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
+ g_mapThreads[RTThreadSelf()] = "[ P ]";
+ thrLock.release();
+
+ doQueuesLoop();
+
+ thrLock.acquire();
+ g_mapThreads.erase(RTThreadSelf());
+ return VINF_SUCCESS;
+}
+
+#ifdef RT_OS_WINDOWS
+/**
+ * "Signal" handler for cleanly terminating the event loop.
+ */
+static BOOL WINAPI websrvSignalHandler(DWORD dwCtrlType)
+{
+ bool fEventHandled = FALSE;
+ switch (dwCtrlType)
+ {
+ /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
+ * via GenerateConsoleCtrlEvent(). */
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_C_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ {
+ ASMAtomicWriteBool(&g_fKeepRunning, false);
+ com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue();
+ pQ->interruptEventQueueProcessing();
+ fEventHandled = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ return fEventHandled;
+}
+#else
+/**
+ * Signal handler for cleanly terminating the event loop.
+ */
+static void websrvSignalHandler(int iSignal)
+{
+ NOREF(iSignal);
+ ASMAtomicWriteBool(&g_fKeepRunning, false);
+ com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue();
+ pQ->interruptEventQueueProcessing();
+}
+#endif
+
+
+/**
+ * Start up the webservice server. This keeps running and waits
+ * for incoming SOAP connections; for each request that comes in,
+ * it calls method implementation code, most of it in the generated
+ * code in methodmaps.cpp.
+ *
+ * @param argc
+ * @param argv[]
+ * @return
+ */
+int main(int argc, char *argv[])
+{
+ // initialize runtime
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+#ifdef RT_OS_WINDOWS
+ ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
+#endif
+
+ // store a log prefix for this thread
+ g_mapThreads[RTThreadSelf()] = "[M ]";
+
+ RTStrmPrintf(g_pStdErr, VBOX_PRODUCT " web service Version " VBOX_VERSION_STRING "\n"
+ "Copyright (C) 2007-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
+
+ int c;
+ const char *pszLogFile = NULL;
+ const char *pszPidFile = NULL;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, 0 /*fFlags*/);
+ while ((c = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ switch (c)
+ {
+ case 'H':
+ if (!ValueUnion.psz || !*ValueUnion.psz)
+ {
+ /* Normalize NULL/empty string to NULL, which will be
+ * interpreted as "localhost" below. */
+ g_pcszBindToHost = NULL;
+ }
+ else
+ g_pcszBindToHost = ValueUnion.psz;
+ break;
+
+ case 'p':
+ g_uBindToPort = ValueUnion.u32;
+ break;
+
+#ifdef WITH_OPENSSL
+ case 's':
+ g_fSSL = true;
+ break;
+
+ case 'K':
+ g_pcszKeyFile = ValueUnion.psz;
+ break;
+
+ case 'a':
+ if (ValueUnion.psz[0] == '\0')
+ g_pcszPassword = NULL;
+ else
+ {
+ PRTSTREAM StrmIn;
+ if (!strcmp(ValueUnion.psz, "-"))
+ StrmIn = g_pStdIn;
+ else
+ {
+ int vrc = RTStrmOpen(ValueUnion.psz, "r", &StrmIn);
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open password file (%s, %Rrc)", ValueUnion.psz, vrc);
+ }
+ char szPasswd[512];
+ int vrc = RTStrmGetLine(StrmIn, szPasswd, sizeof(szPasswd));
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to read password (%s, %Rrc)", ValueUnion.psz, vrc);
+ g_pcszPassword = RTStrDup(szPasswd);
+ memset(szPasswd, '\0', sizeof(szPasswd));
+ if (StrmIn != g_pStdIn)
+ RTStrmClose(StrmIn);
+ }
+ break;
+
+ case 'c':
+ g_pcszCACert = ValueUnion.psz;
+ break;
+
+ case 'C':
+ g_pcszCAPath = ValueUnion.psz;
+ break;
+
+ case 'D':
+ g_pcszDHFile = ValueUnion.psz;
+ break;
+
+ case 'r':
+ g_pcszRandFile = ValueUnion.psz;
+ break;
+#endif /* WITH_OPENSSL */
+
+ case 't':
+ g_iWatchdogTimeoutSecs = ValueUnion.u32;
+ break;
+
+ case 'i':
+ g_iWatchdogCheckInterval = ValueUnion.u32;
+ break;
+
+ case 'F':
+ pszLogFile = ValueUnion.psz;
+ break;
+
+ case 'R':
+ g_cHistory = ValueUnion.u32;
+ break;
+
+ case 'S':
+ g_uHistoryFileSize = ValueUnion.u64;
+ break;
+
+ case 'I':
+ g_uHistoryFileTime = ValueUnion.u32;
+ break;
+
+ case 'P':
+ pszPidFile = ValueUnion.psz;
+ break;
+
+ case 'T':
+ g_cMaxWorkerThreads = ValueUnion.u32;
+ break;
+
+ case 'k':
+ g_cMaxKeepAlive = ValueUnion.u32;
+ break;
+
+ case 'A':
+ g_pcszAuthentication = ValueUnion.psz;
+ break;
+
+ case 'h':
+ DisplayHelp();
+ return 0;
+
+ case 'v':
+ g_fVerbose = true;
+ break;
+
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+ case 'b':
+ g_fDaemonize = true;
+ break;
+#endif
+ case 'V':
+ RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
+ return 0;
+
+ default:
+ rc = RTGetOptPrintError(c, &ValueUnion);
+ return rc;
+ }
+ }
+
+ /* create release logger, to stdout */
+ RTERRINFOSTATIC ErrInfo;
+ rc = com::VBoxLogRelCreate("web service", g_fDaemonize ? NULL : pszLogFile,
+ RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
+ "all", "VBOXWEBSRV_RELEASE_LOG",
+ RTLOGDEST_STDOUT, UINT32_MAX /* cMaxEntriesPerGroup */,
+ g_cHistory, g_uHistoryFileTime, g_uHistoryFileSize,
+ RTErrInfoInitStatic(&ErrInfo));
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", ErrInfo.Core.pszMsg, rc);
+
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+ if (g_fDaemonize)
+ {
+ /* prepare release logging */
+ char szLogFile[RTPATH_MAX];
+
+ if (!pszLogFile || !*pszLogFile)
+ {
+ rc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "could not get base directory for logging: %Rrc", rc);
+ rc = RTPathAppend(szLogFile, sizeof(szLogFile), "vboxwebsrv.log");
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "could not construct logging path: %Rrc", rc);
+ pszLogFile = szLogFile;
+ }
+
+ rc = RTProcDaemonizeUsingFork(false /* fNoChDir */, false /* fNoClose */, pszPidFile);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to daemonize, rc=%Rrc. exiting.", rc);
+
+ /* create release logger, to file */
+ rc = com::VBoxLogRelCreate("web service", pszLogFile,
+ RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
+ "all", "VBOXWEBSRV_RELEASE_LOG",
+ RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
+ g_cHistory, g_uHistoryFileTime, g_uHistoryFileSize,
+ RTErrInfoInitStatic(&ErrInfo));
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", ErrInfo.Core.pszMsg, rc);
+ }
+#endif
+
+ // initialize SOAP SSL support if enabled
+#ifdef WITH_OPENSSL
+ if (g_fSSL)
+ soap_ssl_init();
+#endif /* WITH_OPENSSL */
+
+ // initialize COM/XPCOM
+ HRESULT hrc = com::Initialize();
+#ifdef VBOX_WITH_XPCOM
+ if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
+ {
+ char szHome[RTPATH_MAX] = "";
+ com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
+ return RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
+ }
+#endif
+ if (FAILED(hrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to initialize COM! hrc=%Rhrc\n", hrc);
+
+ hrc = g_pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
+ if (FAILED(hrc))
+ {
+ RTMsgError("failed to create the VirtualBoxClient object!");
+ com::ErrorInfo info;
+ if (!info.isFullAvailable() && !info.isBasicAvailable())
+ {
+ com::GluePrintRCMessage(hrc);
+ RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
+ }
+ else
+ com::GluePrintErrorInfo(info);
+ return RTEXITCODE_FAILURE;
+ }
+
+ hrc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam());
+ if (FAILED(hrc))
+ {
+ RTMsgError("Failed to get VirtualBox object (rc=%Rhrc)!", hrc);
+ return RTEXITCODE_FAILURE;
+ }
+
+ // set the authentication method if requested
+ if (g_pVirtualBox && g_pcszAuthentication && g_pcszAuthentication[0])
+ {
+ ComPtr<ISystemProperties> pSystemProperties;
+ g_pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
+ if (pSystemProperties)
+ pSystemProperties->COMSETTER(WebServiceAuthLibrary)(com::Bstr(g_pcszAuthentication).raw());
+ }
+
+ /* VirtualBoxClient events registration. */
+ ComPtr<IEventListener> vboxClientListener;
+ {
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR(g_pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
+ ComObjPtr<VirtualBoxClientEventListenerImpl> clientListener;
+ clientListener.createObject();
+ clientListener->init(new VirtualBoxClientEventListener());
+ vboxClientListener = clientListener;
+ com::SafeArray<VBoxEventType_T> eventTypes;
+ eventTypes.push_back(VBoxEventType_OnVBoxSVCAvailabilityChanged);
+ CHECK_ERROR(pES, RegisterListener(vboxClientListener, ComSafeArrayAsInParam(eventTypes), true));
+ }
+
+ // create the global mutexes
+ g_pAuthLibLockHandle = new util::WriteLockHandle(util::LOCKCLASS_WEBSERVICE);
+ g_pVirtualBoxLockHandle = new util::RWLockHandle(util::LOCKCLASS_WEBSERVICE);
+ g_pWebsessionsLockHandle = new util::WriteLockHandle(util::LOCKCLASS_WEBSERVICE);
+ g_pThreadsLockHandle = new util::RWLockHandle(util::LOCKCLASS_OBJECTSTATE);
+
+ // SOAP queue pumper thread
+ RTTHREAD threadQPumper;
+ rc = RTThreadCreate(&threadQPumper,
+ fntQPumper,
+ NULL, // pvUser
+ 0, // cbStack (default)
+ RTTHREADTYPE_MAIN_WORKER,
+ RTTHREADFLAGS_WAITABLE,
+ "SQPmp");
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot start SOAP queue pumper thread: %Rrc", rc);
+
+ // watchdog thread
+ RTTHREAD threadWatchdog = NIL_RTTHREAD;
+ if (g_iWatchdogTimeoutSecs > 0)
+ {
+ // start our watchdog thread
+ rc = RTThreadCreate(&threadWatchdog,
+ fntWatchdog,
+ NULL,
+ 0,
+ RTTHREADTYPE_MAIN_WORKER,
+ RTTHREADFLAGS_WAITABLE,
+ "Watchdog");
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot start watchdog thread: %Rrc", rc);
+ }
+
+#ifdef RT_OS_WINDOWS
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)websrvSignalHandler, TRUE /* Add handler */))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ RTMsgError("Unable to install console control handler, rc=%Rrc\n", rc);
+ }
+#else
+ signal(SIGINT, websrvSignalHandler);
+ signal(SIGTERM, websrvSignalHandler);
+# ifdef SIGBREAK
+ signal(SIGBREAK, websrvSignalHandler);
+# endif
+#endif
+
+ com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue();
+ while (g_fKeepRunning)
+ {
+ // we have to process main event queue
+ WEBDEBUG(("Pumping COM event queue\n"));
+ rc = pQ->processEventQueue(RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc))
+ RTMsgError("processEventQueue -> %Rrc", rc);
+ }
+
+ LogRel(("requested termination, cleaning up\n"));
+
+#ifdef RT_OS_WINDOWS
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)websrvSignalHandler, FALSE /* Remove handler */))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ RTMsgError("Unable to remove console control handler, rc=%Rrc\n", rc);
+ }
+#else
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+# ifdef SIGBREAK
+ signal(SIGBREAK, SIG_DFL);
+# endif
+#endif
+
+#ifndef RT_OS_WINDOWS
+ RTThreadPoke(threadQPumper);
+#endif
+ RTThreadWait(threadQPumper, 30000, NULL);
+ if (threadWatchdog != NIL_RTTHREAD)
+ {
+#ifndef RT_OS_WINDOWS
+ RTThreadPoke(threadWatchdog);
+#endif
+ RTThreadWait(threadWatchdog, g_iWatchdogCheckInterval * 1000 + 10000, NULL);
+ }
+
+ /* VirtualBoxClient events unregistration. */
+ if (vboxClientListener)
+ {
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR(g_pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR(pES, UnregisterListener(vboxClientListener));
+ vboxClientListener.setNull();
+ }
+
+ {
+ util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+ g_pVirtualBox.setNull();
+ }
+ {
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+ WebsessionsMapIterator it = g_mapWebsessions.begin(),
+ itEnd = g_mapWebsessions.end();
+ while (it != itEnd)
+ {
+ WebServiceSession *pWebsession = it->second;
+ WEBDEBUG(("SVC unavailable: websession %#llx stale, deleting\n", pWebsession->getID()));
+ delete pWebsession;
+ it = g_mapWebsessions.begin();
+ }
+ }
+ g_pVirtualBoxClient.setNull();
+
+ com::Shutdown();
+
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * Watchdog thread
+ *
+ ****************************************************************************/
+
+/**
+ * Watchdog thread, runs in the background while the webservice is alive.
+ *
+ * This gets started by main() and runs in the background to check all websessions
+ * for whether they have been no requests in a configurable timeout period. In
+ * that case, the websession is automatically logged off.
+ */
+static DECLCALLBACK(int) fntWatchdog(RTTHREAD hThreadSelf, void *pvUser)
+{
+ RT_NOREF(hThreadSelf, pvUser);
+
+ // store a log prefix for this thread
+ util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
+ g_mapThreads[RTThreadSelf()] = "[W ]";
+ thrLock.release();
+
+ WEBDEBUG(("Watchdog thread started\n"));
+
+ uint32_t tNextStat = 0;
+
+ while (g_fKeepRunning)
+ {
+ WEBDEBUG(("Watchdog: sleeping %d seconds\n", g_iWatchdogCheckInterval));
+ RTThreadSleep(g_iWatchdogCheckInterval * 1000);
+
+ uint32_t tNow = RTTimeProgramSecTS();
+
+ // we're messing with websessions, so lock them
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+ WEBDEBUG(("Watchdog: checking %d websessions\n", g_mapWebsessions.size()));
+
+ WebsessionsMapIterator it = g_mapWebsessions.begin(),
+ itEnd = g_mapWebsessions.end();
+ while (it != itEnd)
+ {
+ WebServiceSession *pWebsession = it->second;
+ WEBDEBUG(("Watchdog: tNow: %d, websession timestamp: %d\n", tNow, pWebsession->getLastObjectLookup()));
+ if (tNow > pWebsession->getLastObjectLookup() + g_iWatchdogTimeoutSecs)
+ {
+ WEBDEBUG(("Watchdog: websession %#llx timed out, deleting\n", pWebsession->getID()));
+ delete pWebsession;
+ it = g_mapWebsessions.begin();
+ }
+ else
+ ++it;
+ }
+
+ // re-set the authentication method in case it has been changed
+ if (g_pVirtualBox && g_pcszAuthentication && g_pcszAuthentication[0])
+ {
+ ComPtr<ISystemProperties> pSystemProperties;
+ g_pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
+ if (pSystemProperties)
+ pSystemProperties->COMSETTER(WebServiceAuthLibrary)(com::Bstr(g_pcszAuthentication).raw());
+ }
+
+ // Log some MOR usage statistics every 5 minutes, but only if there's
+ // something worth logging (at least one reference or a transition to
+ // zero references). Avoids useless log spamming in idle webservice.
+ if (tNow >= tNextStat)
+ {
+ size_t cMOR = 0;
+ it = g_mapWebsessions.begin();
+ itEnd = g_mapWebsessions.end();
+ while (it != itEnd)
+ {
+ cMOR += it->second->CountRefs();
+ ++it;
+ }
+ static bool fLastZero = false;
+ if (cMOR || !fLastZero)
+ LogRel(("Statistics: %zu websessions, %zu references\n",
+ g_mapWebsessions.size(), cMOR));
+ fLastZero = (cMOR == 0);
+ while (tNextStat <= tNow)
+ tNextStat += 5 * 60; /* 5 minutes */
+ }
+ }
+
+ thrLock.acquire();
+ g_mapThreads.erase(RTThreadSelf());
+
+ LogRel(("ending Watchdog thread\n"));
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * SOAP exceptions
+ *
+ ****************************************************************************/
+
+/**
+ * Helper function to raise a SOAP fault. Called by the other helper
+ * functions, which raise specific SOAP faults.
+ *
+ * @param soap
+ * @param pcsz
+ * @param extype
+ * @param ex
+ */
+static void RaiseSoapFault(struct soap *soap,
+ const char *pcsz,
+ int extype,
+ void *ex)
+{
+ // raise the fault
+ soap_sender_fault(soap, pcsz, NULL);
+
+ struct SOAP_ENV__Detail *pDetail = (struct SOAP_ENV__Detail*)soap_malloc(soap, sizeof(struct SOAP_ENV__Detail));
+
+ // without the following, gSOAP crashes miserably when sending out the
+ // data because it will try to serialize all fields (stupid documentation)
+ memset(pDetail, 0, sizeof(struct SOAP_ENV__Detail));
+
+ // fill extended info depending on SOAP version
+ if (soap->version == 2) // SOAP 1.2 is used
+ {
+ soap->fault->SOAP_ENV__Detail = pDetail;
+ soap->fault->SOAP_ENV__Detail->__type = extype;
+ soap->fault->SOAP_ENV__Detail->fault = ex;
+ soap->fault->SOAP_ENV__Detail->__any = NULL; // no other XML data
+ }
+ else
+ {
+ soap->fault->detail = pDetail;
+ soap->fault->detail->__type = extype;
+ soap->fault->detail->fault = ex;
+ soap->fault->detail->__any = NULL; // no other XML data
+ }
+}
+
+/**
+ * Raises a SOAP fault that signals that an invalid object was passed.
+ *
+ * @param soap
+ * @param obj
+ */
+void RaiseSoapInvalidObjectFault(struct soap *soap,
+ WSDLT_ID obj)
+{
+ _vbox__InvalidObjectFault *ex = soap_new__vbox__InvalidObjectFault(soap, 1);
+ ex->badObjectID = obj;
+
+ std::string str("VirtualBox error: ");
+ str += "Invalid managed object reference \"" + obj + "\"";
+
+ RaiseSoapFault(soap,
+ str.c_str(),
+ SOAP_TYPE__vbox__InvalidObjectFault,
+ ex);
+}
+
+/**
+ * Return a safe C++ string from the given COM string,
+ * without crashing if the COM string is empty.
+ * @param bstr
+ * @return
+ */
+std::string ConvertComString(const com::Bstr &bstr)
+{
+ com::Utf8Str ustr(bstr);
+ return ustr.c_str(); /// @todo r=dj since the length is known, we can probably use a better std::string allocator
+}
+
+/**
+ * Return a safe C++ string from the given COM UUID,
+ * without crashing if the UUID is empty.
+ * @param uuid
+ * @return
+ */
+std::string ConvertComString(const com::Guid &uuid)
+{
+ com::Utf8Str ustr(uuid.toString());
+ return ustr.c_str(); /// @todo r=dj since the length is known, we can probably use a better std::string allocator
+}
+
+/** Code to handle string <-> byte arrays base64 conversion. */
+std::string Base64EncodeByteArray(ComSafeArrayIn(BYTE, aData))
+{
+
+ com::SafeArray<BYTE> sfaData(ComSafeArrayInArg(aData));
+ ssize_t cbData = sfaData.size();
+
+ if (cbData == 0)
+ return "";
+
+ ssize_t cchOut = RTBase64EncodedLength(cbData);
+
+ RTCString aStr;
+
+ aStr.reserve(cchOut+1);
+ int rc = RTBase64Encode(sfaData.raw(), cbData,
+ aStr.mutableRaw(), aStr.capacity(),
+ NULL);
+ AssertRC(rc);
+ aStr.jolt();
+
+ return aStr.c_str();
+}
+
+#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)
+ {
+ LogRel(("Decode string too long.\n"));
+ RaiseSoapRuntimeFault(soap, idThis, pszMethodName, E_INVALIDARG, pObj, iid);
+ }
+
+ com::SafeArray<BYTE> result(cbOut);
+ int rc = RTBase64Decode(pszStr, result.raw(), cbOut, NULL, NULL);
+ if (FAILED(rc))
+ {
+ LogRel(("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.
+ *
+ * @param soap
+ * @param idThis
+ * @param pcszMethodName
+ * @param apirc
+ * @param pObj
+ * @param 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"));
+
+ LogRel(("API method name: %s\n", pcszMethodName));
+ LogRel(("API return code: %#10lx (%Rhrc)\n", apirc, apirc));
+ if (info.isFullAvailable() || info.isBasicAvailable())
+ {
+ const com::ErrorInfo *pInfo = &info;
+ do
+ {
+ LogRel(("COM error info result code: %#10lx (%Rhrc)\n", pInfo->getResultCode(), pInfo->getResultCode()));
+ LogRel(("COM error info text: %ls\n", pInfo->getText().raw()));
+
+ pInfo = pInfo->getNext();
+ }
+ while (pInfo);
+ }
+
+ // compose descriptive message
+ 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<IVirtualBoxErrorInfo> pVirtualBoxErrorInfo;
+ info.getVirtualBoxErrorInfo(pVirtualBoxErrorInfo);
+ ex->resultCode = apirc;
+ ex->returnval = createOrFindRefFromComPtr(idThis, g_pcszIVirtualBoxErrorInfo, pVirtualBoxErrorInfo);
+
+ RaiseSoapFault(soap,
+ str.c_str(),
+ SOAP_TYPE__vbox__RuntimeFault,
+ ex);
+}
+
+/****************************************************************************
+ *
+ * splitting and merging of object IDs
+ *
+ ****************************************************************************/
+
+/**
+ * Splits a managed object reference (in string form, as passed in from a SOAP
+ * method call) into two integers for websession and object IDs, respectively.
+ *
+ * @param id
+ * @param pWebsessId
+ * @param pObjId
+ * @return
+ */
+static bool SplitManagedObjectRef(const WSDLT_ID &id,
+ uint64_t *pWebsessId,
+ uint64_t *pObjId)
+{
+ // 64-bit numbers in hex have 16 digits; hence
+ // the object-ref string must have 16 + "-" + 16 characters
+ if ( id.length() == 33
+ && id[16] == '-'
+ )
+ {
+ char psz[34];
+ memcpy(psz, id.c_str(), 34);
+ psz[16] = '\0';
+ if (pWebsessId)
+ RTStrToUInt64Full(psz, 16, pWebsessId);
+ if (pObjId)
+ RTStrToUInt64Full(psz + 17, 16, pObjId);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Creates a managed object reference (in string form) from
+ * two integers representing a websession and object ID, respectively.
+ *
+ * @param sz Buffer with at least 34 bytes space to receive MOR string.
+ * @param websessId
+ * @param objId
+ * @return
+ */
+static void MakeManagedObjectRef(char *sz,
+ uint64_t websessId,
+ uint64_t objId)
+{
+ RTStrFormatNumber(sz, websessId, 16, 16, 0, RTSTR_F_64BIT | RTSTR_F_ZEROPAD);
+ sz[16] = '-';
+ RTStrFormatNumber(sz + 17, objId, 16, 16, 0, RTSTR_F_64BIT | RTSTR_F_ZEROPAD);
+}
+
+/****************************************************************************
+ *
+ * class WebServiceSession
+ *
+ ****************************************************************************/
+
+class WebServiceSessionPrivate
+{
+ public:
+ ManagedObjectsMapById _mapManagedObjectsById;
+ ManagedObjectsMapByPtr _mapManagedObjectsByPtr;
+};
+
+/**
+ * Constructor for the websession object.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ */
+WebServiceSession::WebServiceSession()
+ : _uNextObjectID(1), // avoid 0 for no real reason
+ _fDestructing(false),
+ _tLastObjectLookup(0)
+{
+ _pp = new WebServiceSessionPrivate;
+ _uWebsessionID = RTRandU64();
+
+ // register this websession globally
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+ g_mapWebsessions[_uWebsessionID] = this;
+}
+
+/**
+ * Destructor. Cleans up and destroys all contained managed object references on the way.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ */
+WebServiceSession::~WebServiceSession()
+{
+ // delete us from global map first so we can't be found
+ // any more while we're cleaning up
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+ g_mapWebsessions.erase(_uWebsessionID);
+
+ // notify ManagedObjectRef destructor so it won't
+ // remove itself from the maps; this avoids rebalancing
+ // the map's tree on every delete as well
+ _fDestructing = true;
+
+ ManagedObjectsIteratorById it,
+ end = _pp->_mapManagedObjectsById.end();
+ for (it = _pp->_mapManagedObjectsById.begin();
+ it != end;
+ ++it)
+ {
+ ManagedObjectRef *pRef = it->second;
+ delete pRef; // this frees the contained ComPtr as well
+ }
+
+ delete _pp;
+}
+
+/**
+ * Authenticate the username and password against an authentication authority.
+ *
+ * @return 0 if the user was successfully authenticated, or an error code
+ * otherwise.
+ */
+int WebServiceSession::authenticate(const char *pcszUsername,
+ const char *pcszPassword,
+ IVirtualBox **ppVirtualBox)
+{
+ int rc = VERR_WEB_NOT_AUTHENTICATED;
+ ComPtr<IVirtualBox> pVirtualBox;
+ {
+ util::AutoReadLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+ pVirtualBox = g_pVirtualBox;
+ }
+ if (pVirtualBox.isNull())
+ return rc;
+ pVirtualBox.queryInterfaceTo(ppVirtualBox);
+
+ util::AutoReadLock lock(g_pAuthLibLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ static bool fAuthLibLoaded = false;
+ static PAUTHENTRY pfnAuthEntry = NULL;
+ static PAUTHENTRY2 pfnAuthEntry2 = NULL;
+ static PAUTHENTRY3 pfnAuthEntry3 = NULL;
+
+ if (!fAuthLibLoaded)
+ {
+ // retrieve authentication library from system properties
+ ComPtr<ISystemProperties> systemProperties;
+ pVirtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
+
+ com::Bstr authLibrary;
+ systemProperties->COMGETTER(WebServiceAuthLibrary)(authLibrary.asOutParam());
+ com::Utf8Str filename = authLibrary;
+
+ LogRel(("External authentication library is '%ls'\n", authLibrary.raw()));
+
+ if (filename == "null")
+ // authentication disabled, let everyone in:
+ fAuthLibLoaded = true;
+ else
+ {
+ RTLDRMOD hlibAuth = 0;
+ do
+ {
+ 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 '%s'. Error code: %Rrc\n",
+ __FUNCTION__, filename.c_str(), rc));
+ break;
+ }
+
+ if (RT_FAILURE(rc = RTLdrGetSymbol(hlibAuth, AUTHENTRY3_NAME, (void**)&pfnAuthEntry3)))
+ {
+ WEBDEBUG(("%s(): Could not resolve import '%s'. Error code: %Rrc\n",
+ __FUNCTION__, AUTHENTRY3_NAME, rc));
+
+ if (RT_FAILURE(rc = RTLdrGetSymbol(hlibAuth, AUTHENTRY2_NAME, (void**)&pfnAuthEntry2)))
+ {
+ WEBDEBUG(("%s(): Could not resolve import '%s'. Error code: %Rrc\n",
+ __FUNCTION__, AUTHENTRY2_NAME, rc));
+
+ if (RT_FAILURE(rc = RTLdrGetSymbol(hlibAuth, AUTHENTRY_NAME, (void**)&pfnAuthEntry)))
+ WEBDEBUG(("%s(): Could not resolve import '%s'. Error code: %Rrc\n",
+ __FUNCTION__, AUTHENTRY_NAME, rc));
+ }
+ }
+
+ if (pfnAuthEntry || pfnAuthEntry2 || pfnAuthEntry3)
+ fAuthLibLoaded = true;
+
+ } while (0);
+ }
+ }
+
+ if (strlen(pcszUsername) >= _1K)
+ {
+ LogRel(("Access denied, excessive username length: %zu\n", strlen(pcszUsername)));
+ rc = VERR_WEB_NOT_AUTHENTICATED;
+ }
+ else if (strlen(pcszPassword) >= _1K)
+ {
+ LogRel(("Access denied, excessive password length: %zu\n", strlen(pcszPassword)));
+ rc = VERR_WEB_NOT_AUTHENTICATED;
+ }
+ else if (pfnAuthEntry3 || pfnAuthEntry2 || pfnAuthEntry)
+ {
+ const char *pszFn;
+ AuthResult result;
+ if (pfnAuthEntry3)
+ {
+ result = pfnAuthEntry3("webservice", NULL, AuthGuestNotAsked, pcszUsername, pcszPassword, NULL, true, 0);
+ pszFn = AUTHENTRY3_NAME;
+ }
+ else if (pfnAuthEntry2)
+ {
+ result = pfnAuthEntry2(NULL, AuthGuestNotAsked, pcszUsername, pcszPassword, NULL, true, 0);
+ pszFn = AUTHENTRY2_NAME;
+ }
+ else
+ {
+ result = pfnAuthEntry(NULL, AuthGuestNotAsked, pcszUsername, pcszPassword, NULL);
+ pszFn = AUTHENTRY_NAME;
+ }
+ WEBDEBUG(("%s(): result of %s('%s', [%d]): %d (%s)\n",
+ __FUNCTION__, pszFn, pcszUsername, strlen(pcszPassword), result, decodeAuthResult(result)));
+ if (result == AuthResultAccessGranted)
+ {
+ LogRel(("Access for user '%s' granted\n", pcszUsername));
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ if (result == AuthResultAccessDenied)
+ LogRel(("Access for user '%s' denied\n", pcszUsername));
+ rc = VERR_WEB_NOT_AUTHENTICATED;
+ }
+ }
+ else if (fAuthLibLoaded)
+ {
+ // fAuthLibLoaded = true but all pointers are NULL:
+ // The authlib was "null" and auth was disabled
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ WEBDEBUG(("Could not resolve AuthEntry, VRDPAuth2 or VRDPAuth entry point"));
+ rc = VERR_WEB_NOT_AUTHENTICATED;
+ }
+
+ lock.release();
+
+ return rc;
+}
+
+/**
+ * Look up, in this websession, whether a ManagedObjectRef has already been
+ * created for the given COM pointer.
+ *
+ * Note how we require that a ComPtr<IUnknown> is passed, which causes a
+ * queryInterface call when the caller passes in a different type, since
+ * a ComPtr<IUnknown> will point to something different than a
+ * ComPtr<IVirtualBox>, for example. As we store the ComPtr<IUnknown> in
+ * our private hash table, we must search for one too.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ *
+ * @param pObject pointer to a COM object.
+ * @return The existing ManagedObjectRef that represents the COM object, or NULL if there's none yet.
+ */
+ManagedObjectRef* WebServiceSession::findRefFromPtr(const IUnknown *pObject)
+{
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+
+ uintptr_t ulp = (uintptr_t)pObject;
+ // WEBDEBUG((" %s: looking up %#lx\n", __FUNCTION__, ulp));
+ ManagedObjectsIteratorByPtr it = _pp->_mapManagedObjectsByPtr.find(ulp);
+ if (it != _pp->_mapManagedObjectsByPtr.end())
+ {
+ ManagedObjectRef *pRef = it->second;
+ WEBDEBUG((" %s: found existing ref %s (%s) for COM obj %#lx\n", __FUNCTION__, pRef->getWSDLID().c_str(), pRef->getInterfaceName(), ulp));
+ return pRef;
+ }
+
+ return NULL;
+}
+
+/**
+ * Static method which attempts to find the websession for which the given
+ * managed object reference was created, by splitting the reference into the
+ * websession and object IDs and then looking up the websession object.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle in read mode.
+ *
+ * @param id Managed object reference (with combined websession and object IDs).
+ * @return
+ */
+WebServiceSession *WebServiceSession::findWebsessionFromRef(const WSDLT_ID &id)
+{
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+
+ WebServiceSession *pWebsession = NULL;
+ uint64_t websessId;
+ if (SplitManagedObjectRef(id,
+ &websessId,
+ NULL))
+ {
+ WebsessionsMapIterator it = g_mapWebsessions.find(websessId);
+ if (it != g_mapWebsessions.end())
+ pWebsession = it->second;
+ }
+ return pWebsession;
+}
+
+/**
+ * Touches the websession to prevent it from timing out.
+ *
+ * Each websession has an internal timestamp that records the last request made
+ * to it from the client that started it. If no request was made within a
+ * configurable timeframe, then the client is logged off automatically,
+ * by calling IWebsessionManager::logoff()
+ */
+void WebServiceSession::touch()
+{
+ _tLastObjectLookup = RTTimeProgramSecTS();
+}
+
+/**
+ * Counts the number of managed object references in this websession.
+ */
+size_t WebServiceSession::CountRefs()
+{
+ return _pp->_mapManagedObjectsById.size();
+}
+
+
+/****************************************************************************
+ *
+ * class ManagedObjectRef
+ *
+ ****************************************************************************/
+
+/**
+ * Constructor, which assigns a unique ID to this managed object
+ * reference and stores it in two hashes (living in the associated
+ * WebServiceSession object):
+ *
+ * a) _mapManagedObjectsById, which maps ManagedObjectID's to
+ * instances of this class; this hash is then used by the
+ * findObjectFromRef() template function in vboxweb.h
+ * to quickly retrieve the COM object from its managed
+ * object ID (mostly in the context of the method mappers
+ * in methodmaps.cpp, when a web service client passes in
+ * a managed object ID);
+ *
+ * b) _mapManagedObjectsByPtr, which maps COM pointers to
+ * instances of this class; this hash is used by
+ * createRefFromObject() to quickly figure out whether an
+ * instance already exists for a given COM pointer.
+ *
+ * This constructor calls AddRef() on the given COM object, and
+ * the destructor will call Release(). We require two input pointers
+ * for that COM object, one generic IUnknown* pointer which is used
+ * as the map key, and a specific interface pointer (e.g. IMachine*)
+ * which must support the interface given in guidInterface. All
+ * three values are returned by getPtr(), which gives future callers
+ * a chance to reuse the specific interface pointer without having
+ * to call QueryInterface, which can be expensive.
+ *
+ * This does _not_ check whether another instance already
+ * exists in the hash. This gets called only from the
+ * createOrFindRefFromComPtr() template function in vboxweb.h, which
+ * does perform that check.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ *
+ * @param websession Websession to which the MOR will be added.
+ * @param pobjUnknown Pointer to IUnknown* interface for the COM object; this will be used in the hashes.
+ * @param pobjInterface Pointer to a specific interface for the COM object, described by guidInterface.
+ * @param guidInterface Interface which pobjInterface points to.
+ * @param pcszInterface String representation of that interface (e.g. "IMachine") for readability and logging.
+ */
+ManagedObjectRef::ManagedObjectRef(WebServiceSession &websession,
+ IUnknown *pobjUnknown,
+ void *pobjInterface,
+ const com::Guid &guidInterface,
+ const char *pcszInterface)
+ : _websession(websession),
+ _pobjUnknown(pobjUnknown),
+ _pobjInterface(pobjInterface),
+ _guidInterface(guidInterface),
+ _pcszInterface(pcszInterface)
+{
+ Assert(pobjUnknown);
+ Assert(pobjInterface);
+
+ // keep both stubs alive while this MOR exists (matching Release() calls are in destructor)
+ uint32_t cRefs1 = pobjUnknown->AddRef();
+ uint32_t cRefs2 = ((IUnknown*)pobjInterface)->AddRef();
+ _ulp = (uintptr_t)pobjUnknown;
+
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+ _id = websession.createObjectID();
+ // and count globally
+ ULONG64 cTotal = ++g_cManagedObjects; // raise global count and make a copy for the debug message below
+
+ char sz[34];
+ MakeManagedObjectRef(sz, websession._uWebsessionID, _id);
+ _strID = sz;
+
+ websession._pp->_mapManagedObjectsById[_id] = this;
+ websession._pp->_mapManagedObjectsByPtr[_ulp] = this;
+
+ websession.touch();
+
+ 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,
+ pobjUnknown,
+ cRefs1,
+ cRefs2,
+ _id,
+ cTotal));
+}
+
+/**
+ * Destructor; removes the instance from the global hash of
+ * managed objects. Calls Release() on the contained COM object.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ */
+ManagedObjectRef::~ManagedObjectRef()
+{
+ Assert(g_pWebsessionsLockHandle->isWriteLockOnCurrentThread());
+ ULONG64 cTotal = --g_cManagedObjects;
+
+ Assert(_pobjUnknown);
+ Assert(_pobjInterface);
+
+ // we called AddRef() on both interfaces, so call Release() on
+ // both as well, but in reverse order
+ uint32_t cRefs2 = ((IUnknown*)_pobjInterface)->Release();
+ uint32_t cRefs1 = _pobjUnknown->Release();
+ WEBDEBUG((" * %s: deleting MOR for ID %#llx (%s; COM refcount now %RI32/%RI32); now %lld objects total\n", __FUNCTION__, _id, _pcszInterface, cRefs1, cRefs2, cTotal));
+
+ // if we're being destroyed from the websession's destructor,
+ // then that destructor is iterating over the maps, so
+ // don't remove us there! (data integrity + speed)
+ if (!_websession._fDestructing)
+ {
+ WEBDEBUG((" * %s: removing from websession maps\n", __FUNCTION__));
+ _websession._pp->_mapManagedObjectsById.erase(_id);
+ if (_websession._pp->_mapManagedObjectsByPtr.erase(_ulp) != 1)
+ WEBDEBUG((" WARNING: could not find %#llx in _mapManagedObjectsByPtr\n", _ulp));
+ }
+}
+
+/**
+ * Static helper method for findObjectFromRef() template that actually
+ * looks up the object from a given integer ID.
+ *
+ * This has been extracted into this non-template function to reduce
+ * code bloat as we have the actual STL map lookup only in this function.
+ *
+ * This also "touches" the timestamp in the websession whose ID is encoded
+ * in the given integer ID, in order to prevent the websession from timing
+ * out.
+ *
+ * Preconditions: Caller must have locked g_pWebsessionsLockHandle.
+ *
+ * @param id
+ * @param pRef
+ * @param fNullAllowed
+ * @return
+ */
+int ManagedObjectRef::findRefFromId(const WSDLT_ID &id,
+ ManagedObjectRef **pRef,
+ bool fNullAllowed)
+{
+ int rc = 0;
+
+ do
+ {
+ // allow NULL (== empty string) input reference, which should return a NULL pointer
+ if (!id.length() && fNullAllowed)
+ {
+ *pRef = NULL;
+ return 0;
+ }
+
+ uint64_t websessId;
+ uint64_t objId;
+ WEBDEBUG((" %s(): looking up objref %s\n", __FUNCTION__, id.c_str()));
+ if (!SplitManagedObjectRef(id,
+ &websessId,
+ &objId))
+ {
+ rc = VERR_WEB_INVALID_MANAGED_OBJECT_REFERENCE;
+ break;
+ }
+
+ WebsessionsMapIterator it = g_mapWebsessions.find(websessId);
+ if (it == g_mapWebsessions.end())
+ {
+ WEBDEBUG((" %s: cannot find websession for objref %s\n", __FUNCTION__, id.c_str()));
+ rc = VERR_WEB_INVALID_SESSION_ID;
+ break;
+ }
+
+ WebServiceSession *pWebsession = it->second;
+ // "touch" websession to prevent it from timing out
+ pWebsession->touch();
+
+ ManagedObjectsIteratorById iter = pWebsession->_pp->_mapManagedObjectsById.find(objId);
+ if (iter == pWebsession->_pp->_mapManagedObjectsById.end())
+ {
+ WEBDEBUG((" %s: cannot find comobj for objref %s\n", __FUNCTION__, id.c_str()));
+ rc = VERR_WEB_INVALID_OBJECT_ID;
+ break;
+ }
+
+ *pRef = iter->second;
+
+ } while (0);
+
+ return rc;
+}
+
+/****************************************************************************
+ *
+ * interface IManagedObjectRef
+ *
+ ****************************************************************************/
+
+/**
+ * This is the hard-coded implementation for the IManagedObjectRef::getInterfaceName()
+ * that our WSDL promises to our web service clients. This method returns a
+ * string describing the interface that this managed object reference
+ * supports, e.g. "IMachine".
+ *
+ * @param soap
+ * @param req
+ * @param resp
+ * @return
+ */
+int __vbox__IManagedObjectRef_USCOREgetInterfaceName(
+ struct soap *soap,
+ _vbox__IManagedObjectRef_USCOREgetInterfaceName *req,
+ _vbox__IManagedObjectRef_USCOREgetInterfaceNameResponse *resp)
+{
+ RT_NOREF(soap);
+ HRESULT rc = S_OK;
+ WEBDEBUG(("-- entering %s\n", __FUNCTION__));
+
+ do
+ {
+ // findRefFromId require the lock
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ ManagedObjectRef *pRef;
+ if (!ManagedObjectRef::findRefFromId(req->_USCOREthis, &pRef, false))
+ resp->returnval = pRef->getInterfaceName();
+
+ } while (0);
+
+ WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc));
+ if (FAILED(rc))
+ return SOAP_FAULT;
+ return SOAP_OK;
+}
+
+/**
+ * This is the hard-coded implementation for the IManagedObjectRef::release()
+ * that our WSDL promises to our web service clients. This method releases
+ * a managed object reference and removes it from our stacks.
+ *
+ * @param soap
+ * @param req
+ * @param resp
+ * @return
+ */
+int __vbox__IManagedObjectRef_USCORErelease(
+ struct soap *soap,
+ _vbox__IManagedObjectRef_USCORErelease *req,
+ _vbox__IManagedObjectRef_USCOREreleaseResponse *resp)
+{
+ RT_NOREF(resp);
+ HRESULT rc;
+ WEBDEBUG(("-- entering %s\n", __FUNCTION__));
+
+ {
+ // findRefFromId and the delete call below require the lock
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ ManagedObjectRef *pRef;
+ rc = ManagedObjectRef::findRefFromId(req->_USCOREthis, &pRef, false);
+ if (rc == S_OK)
+ {
+ WEBDEBUG((" found reference; deleting!\n"));
+ // this removes the object from all stacks; since
+ // there's a ComPtr<> hidden inside the reference,
+ // this should also invoke Release() on the COM
+ // object
+ delete pRef;
+ }
+ else
+ RaiseSoapInvalidObjectFault(soap, req->_USCOREthis);
+ }
+
+ WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc));
+ if (FAILED(rc))
+ return SOAP_FAULT;
+ return SOAP_OK;
+}
+
+/****************************************************************************
+ *
+ * interface IWebsessionManager
+ *
+ ****************************************************************************/
+
+/**
+ * Hard-coded implementation for IWebsessionManager::logon. As opposed to the underlying
+ * COM API, this is the first method that a webservice client must call before the
+ * webservice will do anything useful.
+ *
+ * This returns a managed object reference to the global IVirtualBox object; into this
+ * reference a websession ID is encoded which remains constant with all managed object
+ * references returned by other methods.
+ *
+ * When the webservice client is done, it should call IWebsessionManager::logoff. This
+ * will clean up internally (destroy all remaining managed object references and
+ * related COM objects used internally).
+ *
+ * After logon, an internal timeout ensures that if the webservice client does not
+ * call any methods, after a configurable number of seconds, the webservice will log
+ * off the client automatically. This is to ensure that the webservice does not
+ * drown in managed object references and eventually deny service. Still, it is
+ * a much better solution, both for performance and cleanliness, for the webservice
+ * client to clean up itself.
+ *
+ * @param soap
+ * @param req
+ * @param resp
+ * @return
+ */
+int __vbox__IWebsessionManager_USCORElogon(
+ struct soap *soap,
+ _vbox__IWebsessionManager_USCORElogon *req,
+ _vbox__IWebsessionManager_USCORElogonResponse *resp)
+{
+ RT_NOREF(soap);
+ HRESULT rc = S_OK;
+ WEBDEBUG(("-- entering %s\n", __FUNCTION__));
+
+ do
+ {
+ // WebServiceSession constructor tinkers with global MOR map and requires a write lock
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ // create new websession; the constructor stores the new websession
+ // in the global map automatically
+ WebServiceSession *pWebsession = new WebServiceSession();
+ ComPtr<IVirtualBox> pVirtualBox;
+
+ // authenticate the user
+ if (!(pWebsession->authenticate(req->username.c_str(),
+ req->password.c_str(),
+ pVirtualBox.asOutParam())))
+ {
+ // fake up a "root" MOR for this websession
+ char sz[34];
+ MakeManagedObjectRef(sz, pWebsession->getID(), 0ULL);
+ WSDLT_ID id = sz;
+
+ // in the new websession, create a managed object reference (MOR) for the
+ // global VirtualBox object; this encodes the websession ID in the MOR so
+ // that it will be implicitly be included in all future requests of this
+ // webservice client
+ resp->returnval = createOrFindRefFromComPtr(id, g_pcszIVirtualBox, pVirtualBox);
+ WEBDEBUG(("VirtualBox object ref is %s\n", resp->returnval.c_str()));
+ }
+ else
+ rc = E_FAIL;
+ } while (0);
+
+ WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc));
+ if (FAILED(rc))
+ return SOAP_FAULT;
+ return SOAP_OK;
+}
+
+/**
+ * Returns a new ISession object every time.
+ *
+ * No longer connected in any way to logons, one websession can easily
+ * handle multiple sessions.
+ */
+int __vbox__IWebsessionManager_USCOREgetSessionObject(
+ struct soap*,
+ _vbox__IWebsessionManager_USCOREgetSessionObject *req,
+ _vbox__IWebsessionManager_USCOREgetSessionObjectResponse *resp)
+{
+ HRESULT rc = S_OK;
+ WEBDEBUG(("-- entering %s\n", __FUNCTION__));
+
+ do
+ {
+ // create a new ISession object
+ ComPtr<ISession> pSession;
+ rc = g_pVirtualBoxClient->COMGETTER(Session)(pSession.asOutParam());
+ if (FAILED(rc))
+ {
+ WEBDEBUG(("ERROR: cannot create session object!"));
+ break;
+ }
+
+ // return its MOR
+ resp->returnval = createOrFindRefFromComPtr(req->refIVirtualBox, g_pcszISession, pSession);
+ WEBDEBUG(("Session object ref is %s\n", resp->returnval.c_str()));
+ } while (0);
+
+ WEBDEBUG(("-- leaving %s, rc: %#lx\n", __FUNCTION__, rc));
+ if (FAILED(rc))
+ return SOAP_FAULT;
+ return SOAP_OK;
+}
+
+/**
+ * hard-coded implementation for IWebsessionManager::logoff.
+ *
+ * @param req
+ * @param resp
+ * @return
+ */
+int __vbox__IWebsessionManager_USCORElogoff(
+ struct soap*,
+ _vbox__IWebsessionManager_USCORElogoff *req,
+ _vbox__IWebsessionManager_USCORElogoffResponse *resp)
+{
+ RT_NOREF(resp);
+ HRESULT rc = S_OK;
+ WEBDEBUG(("-- entering %s\n", __FUNCTION__));
+
+ {
+ // findWebsessionFromRef and the websession destructor require the lock
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ WebServiceSession *pWebsession = WebServiceSession::findWebsessionFromRef(req->refIVirtualBox);
+ if (pWebsession)
+ {
+ WEBDEBUG(("websession logoff, deleting websession %#llx\n", pWebsession->getID()));
+ delete pWebsession;
+ // destructor cleans up
+
+ WEBDEBUG(("websession destroyed, %d websessions left open\n", g_mapWebsessions.size()));
+ }
+ }
+
+ 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
new file mode 100644
index 00000000..00408490
--- /dev/null
+++ b/src/VBox/Main/webservice/vboxweb.h
@@ -0,0 +1,376 @@
+/* $Id: vboxweb.h $ */
+/** @file
+ * vboxweb.h - header file for "real" web server code.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef MAIN_INCLUDED_SRC_webservice_vboxweb_h
+#define MAIN_INCLUDED_SRC_webservice_vboxweb_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define LOG_GROUP LOG_GROUP_WEBSERVICE
+#include <VBox/log.h>
+#include <VBox/err.h>
+
+#include <VBox/com/VirtualBox.h>
+#include <VBox/com/Guid.h>
+#include <VBox/com/AutoLock.h>
+
+#include <iprt/asm.h>
+
+#include <iprt/sanitized/string>
+
+/****************************************************************************
+ *
+ * debug macro
+ *
+ ****************************************************************************/
+
+#define WEBDEBUG(a) do { if (g_fVerbose) { LogRel(a); } } while (0)
+
+/****************************************************************************
+ *
+ * typedefs
+ *
+ ****************************************************************************/
+
+// type used by gSOAP-generated code
+typedef std::string WSDLT_ID; // combined managed object ref (websession ID plus object ID)
+typedef std::string vbox__uuid;
+
+/****************************************************************************
+ *
+ * global variables
+ *
+ ****************************************************************************/
+
+extern bool g_fVerbose;
+
+extern util::WriteLockHandle *g_pWebsessionsLockHandle;
+
+extern const WSDLT_ID g_EmptyWSDLID;
+
+/****************************************************************************
+ *
+ * SOAP exceptions
+ *
+ ****************************************************************************/
+
+extern void RaiseSoapInvalidObjectFault(struct soap *soap, WSDLT_ID obj);
+
+extern void RaiseSoapRuntimeFault(struct soap *soap, const WSDLT_ID &idThis, const char *pcszMethodName, HRESULT apirc, IUnknown *pObj, const com::Guid &iid);
+
+/****************************************************************************
+ *
+ * conversion helpers
+ *
+ ****************************************************************************/
+
+extern std::string ConvertComString(const com::Bstr &bstr);
+
+extern std::string ConvertComString(const com::Guid &bstr);
+
+extern std::string Base64EncodeByteArray(ComSafeArrayIn(BYTE, aData));
+
+extern 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
+ *
+ ****************************************************************************/
+
+class WebServiceSessionPrivate;
+class ManagedObjectRef;
+
+/**
+ * An instance of this gets created for every client that logs onto the
+ * webservice (via the special IWebsessionManager::logon() SOAP API) and
+ * maintains the managed object references for that websession.
+ */
+class WebServiceSession
+{
+ friend class ManagedObjectRef;
+
+ private:
+ uint64_t _uWebsessionID;
+ uint64_t _uNextObjectID;
+ WebServiceSessionPrivate *_pp; // opaque data struct (defined in vboxweb.cpp)
+ bool _fDestructing;
+
+ uint32_t _tLastObjectLookup;
+
+ // hide the copy constructor because we're not copyable
+ WebServiceSession(const WebServiceSession &copyFrom);
+
+ public:
+ WebServiceSession();
+
+ ~WebServiceSession();
+
+ int authenticate(const char *pcszUsername,
+ const char *pcszPassword,
+ IVirtualBox **ppVirtualBox);
+
+ ManagedObjectRef* findRefFromPtr(const IUnknown *pObject);
+
+ uint64_t getID() const
+ {
+ return _uWebsessionID;
+ }
+
+ uint64_t createObjectID()
+ {
+ uint64_t id = ASMAtomicIncU64(&_uNextObjectID);
+ return id - 1;
+ }
+
+ void touch();
+
+ uint32_t getLastObjectLookup() const
+ {
+ return _tLastObjectLookup;
+ }
+
+ static WebServiceSession* findWebsessionFromRef(const WSDLT_ID &id);
+
+ size_t CountRefs();
+};
+
+/**
+ * ManagedObjectRef is used to map COM pointers to object IDs
+ * within a websession. Such object IDs are 64-bit integers.
+ *
+ * When a webservice method call is invoked on an object, it
+ * has an opaque string called a "managed object reference". Such
+ * a string consists of a websession ID combined with an object ID.
+ *
+ */
+class ManagedObjectRef
+{
+ protected:
+ // owning websession:
+ WebServiceSession &_websession;
+
+
+ IUnknown *_pobjUnknown; // pointer to IUnknown interface for this MOR
+
+ void *_pobjInterface; // pointer to COM interface represented by _guidInterface, for which this MOR
+ // was created; this may be an IUnknown or something more specific
+ com::Guid _guidInterface; // the interface which _pvObj represents
+
+ const char *_pcszInterface; // string representation of that interface (e.g. "IMachine")
+
+ // keys:
+ uint64_t _id;
+ uintptr_t _ulp;
+
+ // long ID as string
+ WSDLT_ID _strID;
+
+ public:
+ ManagedObjectRef(WebServiceSession &websession,
+ IUnknown *pobjUnknown,
+ void *pobjInterface,
+ const com::Guid &guidInterface,
+ const char *pcszInterface);
+ ~ManagedObjectRef();
+
+ uint64_t getID()
+ {
+ return _id;
+ }
+
+ /**
+ * Returns the contained COM pointer and the UUID of the COM interface
+ * which it supports.
+ * @param ppobjInterface
+ * @param ppobjUnknown
+ * @return
+ */
+ const com::Guid& getPtr(void **ppobjInterface,
+ IUnknown **ppobjUnknown)
+ {
+ *ppobjInterface = _pobjInterface;
+ *ppobjUnknown = _pobjUnknown;
+ return _guidInterface;
+ }
+
+ /**
+ * Returns the ID of this managed object reference to string
+ * form, for returning with SOAP data or similar.
+ *
+ * @return The ID in string form.
+ */
+ const WSDLT_ID& getWSDLID() const
+ {
+ return _strID;
+ }
+
+ const char* getInterfaceName() const
+ {
+ return _pcszInterface;
+ }
+
+ static int findRefFromId(const WSDLT_ID &id,
+ ManagedObjectRef **pRef,
+ bool fNullAllowed);
+};
+
+/**
+ * Template function that resolves a managed object reference to a COM pointer
+ * of the template class T.
+ *
+ * This gets called only from tons of generated code in methodmaps.cpp to
+ * resolve objects in *input* parameters to COM methods (i.e. translate
+ * MOR strings to COM objects which should exist already).
+ *
+ * This is a template function so that we can support ComPtr's for arbitrary
+ * interfaces and automatically verify that the managed object reference on
+ * the internal stack actually is of the expected interface. We also now avoid
+ * calling QueryInterface for the case that the interface desired by the caller
+ * is the same as the interface for which the MOR was originally created. In
+ * that case, the lookup is very fast.
+ *
+ * @param soap
+ * @param id in: integer managed object reference, as passed in by web service client
+ * @param pComPtr out: reference to COM pointer object that receives the com pointer,
+ * if SOAP_OK is returned
+ * @param fNullAllowed in: if true, then this func returns a NULL COM pointer if an
+ * empty MOR is passed in (i.e. NULL pointers are allowed). If false,
+ * then this fails; this will be false when called for the "this"
+ * argument of method calls, which really shouldn't be NULL.
+ * @return error code or SOAP_OK if no error
+ */
+template <class T>
+int findComPtrFromId(struct soap *soap,
+ const WSDLT_ID &id,
+ ComPtr<T> &pComPtr,
+ bool fNullAllowed)
+{
+ // findRefFromId requires thelock
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
+ int rc;
+ ManagedObjectRef *pRef;
+ if ((rc = ManagedObjectRef::findRefFromId(id, &pRef, fNullAllowed)))
+ // error:
+ RaiseSoapInvalidObjectFault(soap, id);
+ else
+ {
+ if (fNullAllowed && pRef == NULL)
+ {
+ WEBDEBUG((" %s(): returning NULL object as permitted\n", __FUNCTION__));
+ pComPtr.setNull();
+ return 0;
+ }
+
+ const com::Guid &guidCaller = COM_IIDOF(T);
+
+ // pRef->getPtr returns both a void* for its specific interface pointer as well as a generic IUnknown*
+ void *pobjInterface;
+ IUnknown *pobjUnknown;
+ const com::Guid &guidInterface = pRef->getPtr(&pobjInterface, &pobjUnknown);
+
+ if (guidInterface == guidCaller)
+ {
+ // same interface: then no QueryInterface needed
+ WEBDEBUG((" %s(): returning original %s*=0x%lX (IUnknown*=0x%lX)\n", __FUNCTION__, pRef->getInterfaceName(), pobjInterface, pobjUnknown));
+ pComPtr = (T*)pobjInterface; // this calls AddRef() once
+ return 0;
+ }
+
+ // QueryInterface tests whether p actually supports the templated T interface desired by caller
+ T *pT;
+ pobjUnknown->QueryInterface(guidCaller.ref(), (void**)&pT); // this adds a reference count
+ if (pT)
+ {
+ // assign to caller's ComPtr<T>; use asOutParam() to avoid adding another reference, QueryInterface() already added one
+ WEBDEBUG((" %s(): returning pointer 0x%lX for queried interface %RTuuid (IUnknown*=0x%lX)\n", __FUNCTION__, pT, guidCaller.raw(), pobjUnknown));
+ *(pComPtr.asOutParam()) = pT;
+ return 0;
+ }
+
+ WEBDEBUG((" Interface not supported for object reference %s, which is of class %s\n", id.c_str(), pRef->getInterfaceName()));
+ rc = VERR_WEB_UNSUPPORTED_INTERFACE;
+ RaiseSoapInvalidObjectFault(soap, id); // @todo better message
+ }
+
+ return rc;
+}
+
+/**
+ * Creates a new managed object reference for the given COM pointer. If one
+ * already exists for the given pointer, then that reference's ID is returned.
+ *
+ * This gets called from tons of generated code in methodmaps.cpp to resolve
+ * objects *returned* from COM methods (i.e. create MOR strings from COM
+ * objects which might have been newly created).
+ *
+ * @param idParent managed object reference of calling object; used to extract
+ * websession ID
+ * @param pcszInterface
+ * @param pc COM object for which to create a reference
+ * @return existing or new managed object reference
+ */
+template <class T>
+const WSDLT_ID& createOrFindRefFromComPtr(const WSDLT_ID &idParent,
+ const char *pcszInterface,
+ const ComPtr<T> &pc)
+{
+ // NULL comptr should return NULL MOR
+ if (pc.isNull())
+ {
+ WEBDEBUG((" createOrFindRefFromComPtr(): returning empty MOR for NULL COM pointer\n"));
+ return g_EmptyWSDLID;
+ }
+
+ util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+ WebServiceSession *pWebsession;
+ if ((pWebsession = WebServiceSession::findWebsessionFromRef(idParent)))
+ {
+ ManagedObjectRef *pRef;
+
+ // we need an IUnknown pointer for the MOR
+ ComPtr<IUnknown> pobjUnknown = pc;
+
+ if ( ((pRef = pWebsession->findRefFromPtr(pobjUnknown)))
+ || ((pRef = new ManagedObjectRef(*pWebsession,
+ pobjUnknown, // IUnknown *pobjUnknown
+ pc, // void *pobjInterface
+ COM_IIDOF(T),
+ pcszInterface)))
+ )
+ return pRef->getWSDLID();
+ }
+
+ // websession has expired, return an empty MOR instead of allocating a
+ // new reference which couldn't be used anyway.
+ return g_EmptyWSDLID;
+}
+
+#endif /* !MAIN_INCLUDED_SRC_webservice_vboxweb_h */
+
diff --git a/src/VBox/Main/webservice/websrv-cpp.xsl b/src/VBox/Main/webservice/websrv-cpp.xsl
new file mode 100644
index 00000000..f86dbf1a
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-cpp.xsl
@@ -0,0 +1,1507 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-cpp.xsl:
+ XSLT stylesheet that generates methodmaps.cpp from
+ VirtualBox.xidl. This generated C++ code contains
+ all the service implementations that one would
+ normally have to implement manually to create a
+ web service; our generated code automatically maps
+ all SOAP calls into COM/XPCOM method calls.
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2007-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl">
+
+ <xsl:output method="text"/>
+
+ <xsl:strip-space elements="*"/>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ global XSLT variables
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-cpp.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- collect all interfaces with "wsmap='suppress'" in a global variable for
+ quick lookup -->
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ Keys for more efficiently looking up of types.
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:key name="G_keyEnumsByName" match="//enum[@name]" use="@name"/>
+<xsl:key name="G_keyInterfacesByName" match="//interface[@name]" use="@name"/>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ root match
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="/idl">
+ <xsl:text><![CDATA[
+/* DO NOT EDIT! This is a generated file.
+ * Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML)
+ * Generator: src/VBox/Main/webservice/websrv-cpp.xsl
+ */
+
+// shared webservice header
+#include "vboxweb.h"
+
+// vbox headers
+#include <VBox/com/com.h>
+#include <VBox/com/array.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/VBoxAuth.h>
+
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+
+// gSOAP headers (must come after vbox includes because it checks for conflicting defs)
+#include "soapH.h"
+
+// standard headers
+#include <map>
+#include <iprt/sanitized/sstream>
+
+// shared strings for debug output
+const char *g_pcszCallingComMethod = " calling COM method %s\n";
+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: %#lx (%d)\n";
+
+// generated string constants for all interface names
+const char *g_pcszIUnknown = "IUnknown";
+]]></xsl:text>
+
+ <xsl:for-each select="//interface">
+ <xsl:variable name="ifname" select="@name" />
+ <xsl:value-of select="concat('const char *g_pcsz', $ifname, ' = &quot;', $ifname, '&quot;;')" />
+ <xsl:call-template name="emitNewline" />
+ </xsl:for-each>
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ if
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+ * ignore all |if|s except those for WSDL target
+-->
+<xsl:template match="if">
+ <xsl:if test="@target='wsdl'">
+ <xsl:apply-templates/>
+ </xsl:if>
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ cpp
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="cpp">
+<!-- ignore this -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ library
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="library">
+ <xsl:text>
+/****************************************************************************
+ *
+ * types: enum converter helper functions
+ *
+ ****************************************************************************/
+ </xsl:text>
+ <!--
+ enum converter functions at top of file
+ -->
+ <xsl:for-each select="//enum">
+ <xsl:variable name="enumname" select="@name" />
+ <!-- generate enum converter for COM-to-SOAP -->
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('vbox__', $enumname, ' ', $G_funcPrefixOutputEnumConverter, $enumname, '(', $enumname, '_T e)')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' vbox__', $enumname, ' v;')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> switch(e)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> {</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:for-each select="const[not(@wsmap='suppress')]">
+ <xsl:variable name="enumconst" select="@name" />
+ <xsl:value-of select="concat(' case ', $enumname, '_', $enumconst, ':')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' v = vbox__', $enumname, '__')" />
+ <!-- escape all "_" in $enumconst -->
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="$enumconst" />
+ </xsl:call-template>
+ <xsl:value-of select="';'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>break;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ </xsl:for-each>
+ <!-- Add a default case so gcc gives us a rest, esp. on darwin. -->
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>default:</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> AssertMsgFailed(("e=%d\n", (int)e));</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' v = (vbox__', $enumname, ')0x7fffdead;')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>break; </xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> }</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> return v;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>}</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <!-- generate enum converter for SOAP-to-COM -->
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat($enumname, '_T ', $G_funcPrefixInputEnumConverter, $enumname, '(vbox__', $enumname, ' v)')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' ', $enumname, '_T e;')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> switch(v)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> {</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:for-each select="const[not(@wsmap='suppress')]">
+ <xsl:variable name="enumconst" select="@name" />
+ <xsl:value-of select="concat(' case vbox__', $enumname, '__')" />
+ <!-- escape all "_" in $enumconst -->
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="$enumconst" />
+ </xsl:call-template>
+ <xsl:value-of select="':'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' e = ', $enumname, '_', $enumconst, ';')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>break;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ </xsl:for-each>
+ <!-- Insert a default case so gcc gives us a rest, esp. on darwin. -->
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>default:</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> AssertMsgFailed(("v=%d\n", (int)v));</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' e = (', $enumname, '_T)0x7fffbeef;')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>break; </xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> }</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> return e;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>}</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ </xsl:for-each>
+
+ <xsl:text>
+/****************************************************************************
+ *
+ * types: struct converter helper functions
+ *
+ ****************************************************************************/
+ </xsl:text>
+
+ <xsl:for-each select="//interface[@wsmap='struct']">
+ <xsl:variable name="structname" select="@name" />
+
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('// ', $structname, ' converter: called from method mappers to convert data from')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('// COM interface ', $structname, ', which has wsmap=&quot;struct&quot;, to SOAP structures')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('vbox__', $structname, '* ', $G_funcPrefixOutputStructConverter, $structname, '(')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="' struct soap *soap,'" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="' const WSDLT_ID &amp;idThis,'" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="' HRESULT &amp;rc,'" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' ComPtr&lt;', $structname, '&gt; &amp;in)')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:value-of select="concat(' vbox__', $structname, ' *resp = NULL;')" />
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:call-template name="emitPrologue"><xsl:with-param name="fSkipHRESULT" select="'1'"/></xsl:call-template>
+
+ <xsl:value-of select="concat(' resp = soap_new_vbox__', $structname, '(soap, -1);')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> if (!in)&#10;</xsl:text>
+ <xsl:text> {&#10;</xsl:text>
+ <xsl:text> // @todo ambiguous. Problem is the MOR for the object converted to struct&#10;</xsl:text>
+ <xsl:text> RaiseSoapInvalidObjectFault(soap, "");&#10;</xsl:text>
+ <xsl:text> break;&#10;</xsl:text>
+ <xsl:text> }&#10;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:for-each select="key('G_keyInterfacesByName', $structname)/attribute">
+ <xsl:if test="not(@wsmap = 'suppress')">
+ <xsl:value-of select="concat(' // -- ', $structname, '.', @name)" />
+ <xsl:call-template name="emitNewline" />
+ <!-- recurse! -->
+ <xsl:call-template name="emitGetAttributeComCall">
+ <xsl:with-param name="ifname" select="$structname" />
+ <xsl:with-param name="object" select="'in'" />
+ <xsl:with-param name="attrname" select="@name" />
+ <xsl:with-param name="attrtype" select="@type" />
+ <xsl:with-param name="callerprefix" select="concat('out', '.')" />
+ </xsl:call-template>
+ <xsl:call-template name="emitNewline" />
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:call-template name="emitEpilogue"><xsl:with-param name="fSkipHRESULT" select="'1'"/></xsl:call-template>
+
+ </xsl:for-each>
+
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ class
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="module/class">
+<!-- TODO swallow for now -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ enum
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="enum">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ const
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+<xsl:template match="const">
+ <xsl:apply-templates />
+</xsl:template>
+-->
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ desc
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="desc">
+<!-- TODO swallow for now -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ note
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="note">
+<!-- TODO -->
+ <xsl:apply-templates />
+</xsl:template>
+
+<!--
+ emitBeginOfFunctionHeader:
+-->
+
+<xsl:template name="emitBeginOfFunctionHeader">
+ <xsl:param name="ifname" />
+ <xsl:param name="method" />
+
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('int __vbox__', $ifname, '_USCORE', $method, '(')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> struct soap *soap</xsl:text>
+</xsl:template>
+
+<!--
+ emitCppTypeForIDLType:
+ emits the C++ type that corresponds to the given WSDL type in $type.
+ -->
+<xsl:template name="emitCppTypeForIDLType">
+ <xsl:param name="method" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="varprefix" /> <!-- only with nested get-attribute calls -->
+ <xsl:param name="inptr" /> <!-- whether to add INPTR to BSTR (Dmitry template magic) -->
+
+ <!-- look up C++ glue type from IDL type from table array in typemap-shared.inc.xsl -->
+ <xsl:variable name="gluetypefield" select="exsl:node-set($G_aSharedTypes)/type[@idlname=$type]/@gluename" />
+
+ <xsl:choose>
+ <xsl:when test="$type='wstring' or $type='uuid'">
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:choose>
+ <xsl:when test="$inptr='yes'">
+ <xsl:value-of select="'com::SafeArray&lt;IN_BSTR&gt;'" /> <!-- input string arrays must use IN_BSTR (see com/array.h) -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'com::SafeArray&lt;BSTR&gt;'" /> <!-- output string arrays use raw BSTR -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'com::Bstr'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <!-- if above lookup in table succeeded, use that type -->
+ <xsl:when test="string-length($gluetypefield)">
+ <xsl:call-template name="emitTypeOrArray">
+ <xsl:with-param name="type" select="$gluetypefield"/>
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0">
+ <xsl:call-template name="emitTypeOrArray">
+ <xsl:with-param name="type" select="concat($type, '_T ')"/>
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='$unknown'">
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="'com::SafeIfaceArray&lt;IUnknown&gt;'" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'ComPtr&lt;IUnknown&gt;'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <xsl:variable name="thatif" select="key('G_keyInterfacesByName', $type)" />
+ <xsl:variable name="thatifname" select="$thatif/@name" />
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="concat('com::SafeIfaceArray&lt;', $thatifname, '&gt;')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('ComPtr&lt;', $thatifname, '&gt;')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitCppTypeForIDLType: Type &quot;', $type, '&quot; in method &quot;', $method, '&quot; is not supported.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ emitDocumentStyleArgStructs:
+ with WSDL "document" style only, emits those lengthy structs for
+ the input and output argument in the function header.
+-->
+<xsl:template name="emitDocumentStyleArgStructs">
+ <xsl:param name="ifname" />
+ <xsl:param name="methodname" />
+ <xsl:param name="fOutputs" /> <!-- if 1, emit output struct as well -->
+
+ <xsl:text>,</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' _vbox__', $ifname, '_USCORE', $methodname, $G_requestMessageElementSuffix, ' *', $G_requestElementVarName)" />
+ <xsl:if test="$fOutputs">
+ <xsl:text>,</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' _vbox__', $ifname, '_USCORE', $methodname, $G_responseMessageElementSuffix, ' *', $G_responseElementVarName)" />
+ <!-- <xsl:value-of select="concat(' struct ', $ifname, '__', $methodname, 'Response &amp;', $G_result)" /> -->
+ </xsl:if>
+
+</xsl:template>
+
+<!--
+ emitPrologue:
+ emits the closing ")" for the parameter list and the beginning
+ of the function body.
+ -->
+<xsl:template name="emitPrologue">
+ <xsl:text> WEBDEBUG((g_pcszEntering, __FUNCTION__));
+
+ do {</xsl:text>
+ <xsl:call-template name="emitNewline" />
+</xsl:template>
+
+<!--
+ emitEpilogue
+ -->
+<xsl:template name="emitEpilogue">
+ <xsl:param name="fSkipHRESULT" />
+
+ <xsl:text> } while (0);</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> WEBDEBUG((g_pcszLeaving, __FUNCTION__, rc, rc));</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:if test="not($fSkipHRESULT)">
+ <xsl:text>
+ if (FAILED(rc))
+ return SOAP_FAULT;
+ return SOAP_OK;</xsl:text>
+ </xsl:if>
+ <xsl:if test="$fSkipHRESULT">
+ <xsl:text> return resp;</xsl:text>
+ </xsl:if>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>}</xsl:text>
+ <xsl:call-template name="emitNewline" />
+</xsl:template>
+
+<!--
+ emitObjForMethod:
+ after the function prologue, emit a "pObj" object that
+ specifies the object upon which the method should be invoked.
+-->
+<xsl:template name="emitObjForMethod">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+ <xsl:param name="structprefix" /> <!-- with WSDL document style: req element prefix, like "vbox__IVirtualBox_USCOREcreateMachineRequestElement->" -->
+
+ <xsl:choose>
+ <xsl:when test="$wsmap='global'">
+ <xsl:choose>
+ <xsl:when test="$ifname='IVirtualBox'">
+ <xsl:text> // invoke method on global IVirtualBox instance</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>ComPtr&lt;IVirtualBox&gt; pObj = G_pVirtualBox;</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitObjForMethod: Unknown interface &quot;', $ifname, '&quot; with wsmap=global in XIDL.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="($wsmap='managed')">
+ <xsl:text> // look up managed object reference for method call&#10;</xsl:text>
+ <xsl:value-of select="concat(' ComPtr&lt;', $ifname, '&gt; pObj;&#10;')" />
+ <xsl:value-of select="concat(' if (!', $G_requestElementVarName, ')&#10;')" />
+ <xsl:text> {&#10;</xsl:text>
+ <xsl:text> RaiseSoapInvalidObjectFault(soap, "");&#10;</xsl:text>
+ <xsl:text> break;&#10;</xsl:text>
+ <xsl:text> }&#10;</xsl:text>
+ <xsl:value-of select="concat(' const WSDLT_ID &amp;idThis = ', $structprefix, $G_nameObjectRefEncoded, ';&#10;')" />
+ <xsl:value-of select="' if ((rc = findComPtrFromId(soap, idThis, pObj, false)) != S_OK)&#10;'" />
+ <xsl:text> break;&#10;</xsl:text>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ emitInputArgConverter:
+ another type converter (from wsdl type to COM types),
+ that generates temporary variables on the stack with
+ the WSDL input parameters converted to the COM types,
+ so we can then pass them to the actual COM method call.
+-->
+<xsl:template name="emitInputArgConverter">
+ <xsl:param name="ifname" />
+ <xsl:param name="object" /> <!-- normally "pObj" -->
+ <xsl:param name="method" />
+ <xsl:param name="methodname" />
+ <xsl:param name="structprefix" /> <!-- with WSDL document style: req element prefix, like "vbox__IVirtualBox_USCOREcreateMachineRequestElement->" -->
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+
+ <xsl:value-of select="concat(' // convert input arg ', $name, '(safearray: ', $safearray, ')')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+
+ <xsl:choose>
+ <xsl:when test="$safearray='yes' and $type='octet'">
+ <xsl:value-of select="concat('com::SafeArray&lt;BYTE&gt; comcall_',$name, ';')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('Base64DecodeByteArray(soap, ',$structprefix,$name,', ComSafeArrayAsOutParam(comcall_',$name, '), idThis, &quot;', $ifname, '::', $methodname, '&quot;, ', $object, ', COM_IIDOF(', $ifname, '));')" />
+ </xsl:when>
+
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="concat('size_t c', $name, ' = ', $structprefix, $name, '.size();')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:call-template name="emitCppTypeForIDLType">
+ <xsl:with-param name="method" select="$method"/>
+ <xsl:with-param name="type" select="$type"/>
+ <xsl:with-param name="safearray" select="$safearray"/>
+ <xsl:with-param name="inptr" select="'yes'"/>
+ </xsl:call-template>
+ <xsl:value-of select="concat(' comcall_', $name, '(c', $name, ');')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('for (size_t i = 0; i &lt; c', $name, '; ++i)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="'{'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:choose>
+ <xsl:when test="$type='$unknown'">
+ <xsl:value-of select="' ComPtr&lt;IUnknown&gt; tmpObject;'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' if ((rc = findComPtrFromId(soap, ', $structprefix, $name, '[i], tmpObject, true)) != S_OK)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> break;</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' IUnknown *tmpObject2(tmpObject); tmpObject2->AddRef(); comcall_', $name, '[i] = tmpObject;')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <xsl:value-of select="concat(' ComPtr&lt;', $type, '&gt; tmpObject;')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' if ((rc = findComPtrFromId(soap, ', $structprefix, $name, '[i], tmpObject, true)) != S_OK)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> break;</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' ', $type, ' *tmpObject2(tmpObject); tmpObject2->AddRef(); comcall_', $name, '[i] = tmpObject;')" />
+ </xsl:when>
+ <xsl:when test="$type='wstring'">
+ <xsl:value-of select="concat(' com::Bstr tmpObject(', $structprefix, $name, '[i].c_str());')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="' BSTR tmpObjectB;'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="' tmpObject.detachTo(&amp;tmpObjectB);'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' comcall_', $name, '[i] = tmpObjectB;')" />
+ </xsl:when>
+ <xsl:when test="$type='long'">
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' comcall_', $name, '[i] = ', $structprefix, $name, '[i];')" />
+ </xsl:when>
+ <xsl:when test="$type='long long'">
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' comcall_', $name, '[i] = ', $structprefix, $name, '[i];')" />
+ </xsl:when>
+ <xsl:when test="$type='boolean'">
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' comcall_', $name, '[i] = ', $structprefix, $name, '[i];')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0">
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' comcall_', $name, '[i] = ', $G_funcPrefixInputEnumConverter, $type, '(', $structprefix, $name, '[i]);')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitInputArgConverter Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $method, '&quot; is not yet supported in safearrays.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="'}'" />
+ <xsl:call-template name="emitNewline" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitCppTypeForIDLType">
+ <xsl:with-param name="method" select="$method"/>
+ <xsl:with-param name="type" select="$type"/>
+ <xsl:with-param name="safearray" select="$safearray"/>
+ <xsl:with-param name="inptr" select="'yes'"/>
+ </xsl:call-template>
+ <xsl:choose>
+ <xsl:when test="$type='wstring' or $type='uuid'">
+ <xsl:value-of select="concat(' comcall_', $name, '(', $structprefix, $name, '.c_str())')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0">
+ <xsl:value-of select="concat(' comcall_', $name, ' = ', $G_funcPrefixInputEnumConverter, $type, '(', $structprefix, $name, ')')" />
+ </xsl:when>
+ <xsl:when test="$type='$unknown'">
+ <xsl:value-of select="concat(' comcall_', $name, ';')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('if ((rc = findComPtrFromId(soap, ', $structprefix, $name, ', comcall_', $name,', true)) != S_OK)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> break</xsl:text>
+ </xsl:when>
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <!-- the type is one of our own interfaces: then it must have a wsmap attr -->
+ <xsl:variable name="thatif" select="key('G_keyInterfacesByName', $type)" />
+ <xsl:variable name="wsmap" select="$thatif/@wsmap" />
+ <xsl:variable name="thatifname" select="$thatif/@name" />
+ <xsl:choose>
+ <xsl:when test="not($wsmap)">
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitInputArgConverter: Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $method, '&quot; lacks wsmap attribute in XIDL.')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="($wsmap='managed')">
+ <xsl:value-of select="concat(' comcall_', $name, ';')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('if ((rc = findComPtrFromId(soap, ', $structprefix, $name, ', comcall_', $name,', true)) != S_OK)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> break</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitInputArgConverter: Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $method, '&quot; has unsupported wsmap attribute value &quot;', $wsmap, '&quot; in XIDL.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat(' comcall_', $name, ' = ', $structprefix, $name)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>;
+</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<!--
+ emitTypeOrArray
+-->
+
+<xsl:template name="emitTypeOrArray">
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="concat('com::SafeArray&lt;', $type, '&gt;')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$type" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ emitOutputArgBuffer:
+ another type converter (from wsdl type to COM types)
+ that generates a buffer variable which receives the
+ data from 'out' and 'return' parameters of the COM method call.
+-->
+<xsl:template name="emitOutputArgBuffer">
+ <xsl:param name="method" />
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="varprefix" /> <!-- only with nested get-attribute calls -->
+
+ <xsl:text> // com output arg for </xsl:text><xsl:value-of select="concat($name, ' (safearray: ', $safearray, ')')" /><xsl:text>
+ </xsl:text>
+ <xsl:call-template name="emitCppTypeForIDLType">
+ <xsl:with-param name="method" select="$method" />
+ <xsl:with-param name="type" select="$type" />
+ <xsl:with-param name="safearray" select="$safearray" />
+ </xsl:call-template>
+ <xsl:value-of select="concat(' comcall_', $varprefix, $name, ';')" />
+ <xsl:call-template name="emitNewline" />
+</xsl:template>
+
+<!--
+ emitInParam:
+-->
+<xsl:template name="emitInParam">
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="varprefix" /> <!-- only with nested set-attribute calls -->
+
+ <xsl:variable name="varname" select="concat('comcall_', $varprefix, $name)" />
+
+ <xsl:choose>
+ <xsl:when test="@safearray='yes'">
+ <xsl:value-of select="concat('ComSafeArrayAsInParam(', $varname, ')')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$varname" />
+ <xsl:if test="@type='wstring' or @type='uuid'">
+ <xsl:text>.raw()</xsl:text>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ emitOutParam:
+-->
+<xsl:template name="emitOutParam">
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="varprefix" /> <!-- only with nested get-attribute calls -->
+
+ <xsl:variable name="varname" select="concat('comcall_', $varprefix, $name)" />
+
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="concat('ComSafeArrayAsOutParam(', $varname, ')')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test=" ($type='boolean')
+ or ($type='short')
+ or ($type='unsigned short')
+ or ($type='long')
+ or ($type='unsigned long')
+ or ($type='long long')
+ or ($type='unsigned long long')
+ or ($type='result')
+ or (count(key('G_keyEnumsByName', $type)) > 0)">
+ <xsl:text>&amp;</xsl:text><xsl:value-of select="$varname" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$varname" /><xsl:text>.asOutParam()</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ emitComCall:
+ emits the actual method call with the arguments.
+-->
+<xsl:template name="emitComCall">
+ <xsl:param name="ifname" />
+ <xsl:param name="object" /> <!-- normally "pObj" -->
+ <xsl:param name="methodname" />
+ <xsl:param name="attrname" /> <!-- with attributes only -->
+ <xsl:param name="attrtype" /> <!-- with attributes only -->
+ <xsl:param name="attrsafearray" /> <!-- with attributes only -->
+ <xsl:param name="attrdir" /> <!-- with attributes only: "in" or "return" -->
+ <xsl:param name="varprefix" /> <!-- only with nested get-attribute calls -->
+
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('WEBDEBUG((g_pcszCallingComMethod, &quot;', $methodname, '&quot;));')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('rc = ', $object, '-&gt;', $methodname, '(')" />
+ <xsl:if test="$attrtype">
+ <xsl:choose>
+ <xsl:when test="$attrdir='in'">
+ <xsl:call-template name="emitInParam">
+ <xsl:with-param name="name" select="$attrname" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="safearray" select="$attrsafearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$attrdir='return'">
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="name" select="$attrname" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="safearray" select="$attrsafearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+ <xsl:for-each select="param">
+ <xsl:if test="position()=1">
+ <xsl:call-template name="emitNewline" />
+ </xsl:if>
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ </xsl:if>
+ <xsl:text> </xsl:text>
+ <xsl:choose>
+ <xsl:when test="@dir='in'">
+ <xsl:call-template name="emitInParam">
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@dir='out'">
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="@dir='return'">
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="name" select="$G_result" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text>);</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>if (FAILED(rc))</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' RaiseSoapRuntimeFault(soap, idThis, &quot;', $ifname, '::', $methodname,'&quot;, rc, ', $object, ', COM_IIDOF(', $ifname, '));')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text> break;</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>}</xsl:text>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:text>WEBDEBUG((g_pcszDoneCallingComMethod));</xsl:text>
+ <xsl:call-template name="emitNewline" />
+</xsl:template>
+
+<!--
+ emitOutputArgBackConverter2: implementation details of emitOutputArgBackConverter.
+ -->
+
+<xsl:template name="emitOutputArgBackConverter2">
+ <xsl:param name="name" />
+ <xsl:param name="varname" />
+ <xsl:param name="type" />
+ <xsl:param name="callerprefix" />
+
+ <xsl:choose>
+ <xsl:when test="$type='wstring' or $type='uuid'">
+ <xsl:value-of select="concat('ConvertComString(', $varname, ')')" />
+ </xsl:when>
+ <xsl:when test="$type='boolean'">
+ <!-- the "!!" avoids a microsoft compiler warning -->
+ <xsl:value-of select="concat('!!', $varname)" />
+ </xsl:when>
+ <xsl:when test=" ($type='octet')
+ or ($type='short')
+ or ($type='unsigned short')
+ or ($type='long')
+ or ($type='unsigned long')
+ or ($type='long long')
+ or ($type='unsigned long long')
+ or ($type='result')">
+ <xsl:value-of select="$varname" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0">
+ <xsl:value-of select="concat($G_funcPrefixOutputEnumConverter, $type, '(', $varname, ')')" />
+ </xsl:when>
+ <xsl:when test="$type='$unknown'">
+ <xsl:value-of select="concat('createOrFindRefFromComPtr(idThis, g_pcszIUnknown, ', $varname, ')')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <!-- the type is one of our own interfaces: then it must have a wsmap attr -->
+ <xsl:variable name="thatif" select="key('G_keyInterfacesByName', $type)" />
+ <xsl:variable name="wsmap" select="$thatif/@wsmap" />
+ <xsl:variable name="thatifname" select="$thatif/@name" />
+ <xsl:choose>
+ <xsl:when test=" ($wsmap='managed') or ($wsmap='global')">
+ <xsl:value-of select="concat('createOrFindRefFromComPtr(idThis, g_pcsz', $thatifname, ', ', $varname, ')')" />
+ </xsl:when>
+ <xsl:when test="$wsmap='struct'">
+ <!-- prevent infinite recursion -->
+ <!-- <xsl:call-template name="fatalError"><xsl:with-param name="msg" select="concat('emitOutputArgBackConverter2: attempted infinite recursion for type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $ifname, '::', $method)" /></xsl:call-template> -->
+ <xsl:if test="not($callerprefix)">
+ <xsl:value-of select="concat('/* convert COM interface to struct */ ', $G_funcPrefixOutputStructConverter, $type, '(soap, idThis, rc, ', $varname, ')')" />
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitOutputArgBackConverter2: Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $thatifname, '::', $method, '&quot; has invalid wsmap attribute value &quot;', $wsmap, '&quot; in XIDL.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitOutputArgBackConverter2: Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $method, '&quot; is not supported.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<!--
+ emitOutputArgBackConverter:
+ another type converter (from COM type back to WSDL)
+ which converts the output argument from the COM
+ method call back to the WSDL type passed in by the
+ caller.
+-->
+<xsl:template name="emitOutputArgBackConverter">
+ <xsl:param name="ifname" />
+ <xsl:param name="method" />
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="varprefix" /> <!-- only when called recursively from emitGetAttributeComCall -->
+ <xsl:param name="callerprefix" /> <!-- only for out params or when called recursively from emitGetAttributeComCall -->
+
+ <xsl:variable name="topname" select="$name" />
+ <xsl:variable name="varname" select="concat('comcall_', $varprefix, $name)" />
+
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat('WEBDEBUG((g_pcszConvertComOutputBack, &quot;', $name, '&quot;));')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+
+ <xsl:variable name="receiverVariable">
+ <xsl:choose>
+ <xsl:when test="(not($varprefix))">
+ <xsl:choose>
+ <xsl:when test="$callerprefix"> <!-- callerprefix set but varprefix not: then this is an out parameter :-) -->
+ <xsl:value-of select="concat($G_responseElementVarName, '-&gt;', $name)" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat($G_responseElementVarName, '-&gt;', $G_result)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat($callerprefix, $G_result, '-&gt;', $name)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="$safearray='yes' and $type='octet'">
+ <xsl:value-of select="concat($receiverVariable, ' = Base64EncodeByteArray(ComSafeArrayAsInParam(', $varname,'));')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ </xsl:when>
+
+ <xsl:when test="$safearray='yes'">
+ <xsl:value-of select="concat('for (size_t i = 0; i &lt; ', $varname, '.size(); ++i)')" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="'{'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <!-- look up C++ glue type from IDL type from table array in typemap-shared.inc.xsl -->
+ <xsl:variable name="gluetypefield" select="exsl:node-set($G_aSharedTypes)/type[@idlname=$type]/@gluename" />
+ <xsl:choose>
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <xsl:value-of select="concat(' ComPtr&lt;', $type, '&gt; tmpObject(', $varname, '[i]);')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0">
+ <xsl:value-of select="concat(' ', $type, '_T tmpObject(', $varname, '[i]);')" />
+ </xsl:when>
+ <xsl:when test="$type='$unknown'">
+ <xsl:value-of select="concat(' ComPtr&lt;IUnknown&gt; tmpObject(', $varname, '[i]);')" />
+ </xsl:when>
+ <xsl:when test="$type='wstring' or $type='uuid'">
+ <xsl:value-of select="concat(' com::Bstr tmpObject(', $varname, '[i]);')" />
+ </xsl:when>
+ <xsl:when test="$gluetypefield">
+ <xsl:value-of select="concat(' ', $gluetypefield, ' tmpObject(', $varname, '[i]);')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitOutputArgBackConverter (1): Type &quot;', $type, '&quot; in arg &quot;', $name, '&quot; of method &quot;', $method, '&quot; is not yet supported in safearrays.')" />
+ </xsl:call-template>
+
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="concat(' ', $receiverVariable, '.push_back(')" />
+ <xsl:call-template name="emitOutputArgBackConverter2">
+ <xsl:with-param name="name" select="$name"/>
+ <xsl:with-param name="varname" select="'tmpObject'"/>
+ <xsl:with-param name="type" select="$type"/>
+ <xsl:with-param name="callerprefix" select="$callerprefix"/>
+ </xsl:call-template>
+ <xsl:value-of select="');'" />
+ <xsl:call-template name="emitNewlineIndent8" />
+ <xsl:value-of select="'}'" />
+ <xsl:call-template name="emitNewline" />
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- emit variable name: "resp->retval = " -->
+ <xsl:value-of select="$receiverVariable" />
+
+ <xsl:value-of select="' = '" />
+ <xsl:call-template name="emitOutputArgBackConverter2">
+ <xsl:with-param name="name" select="$name"/>
+ <xsl:with-param name="varname" select="$varname"/>
+ <xsl:with-param name="type" select="$type"/>
+ <xsl:with-param name="callerprefix" select="$callerprefix"/>
+ </xsl:call-template>
+ <xsl:value-of select="';'" />
+ <xsl:call-template name="emitNewline" />
+
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:value-of select="concat(' WEBDEBUG((g_pcszDoneConvertingComOutputBack, &quot;', $name, '&quot;));')" />
+ <xsl:call-template name="emitNewline" />
+</xsl:template>
+
+<!--
+ emitGetAttributeComCall
+ -->
+<xsl:template name="emitGetAttributeComCall">
+ <xsl:param name="ifname" />
+ <xsl:param name="object" /> <!-- normally "pObj->" -->
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:param name="varprefix" /> <!-- only when called recursively from emitOutputArgBackConverter-->
+ <xsl:param name="callerprefix" /> <!-- only when called recursively from emitOutputArgBackConverter-->
+
+ <xsl:variable name="gettername"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="emitOutputArgBuffer">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="method"><xsl:value-of select="$gettername" /></xsl:with-param>
+ <xsl:with-param name="name" select="$attrname" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="safearray" select="$attrsafearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ <xsl:variable name="upperattrname"><xsl:call-template name="capitalize"><xsl:with-param name="str" select="$attrname" /></xsl:call-template></xsl:variable>
+ <!-- actual COM method call -->
+ <xsl:call-template name="emitComCall">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="concat('COMGETTER(', $upperattrname, ')')" />
+ <xsl:with-param name="object" select="$object" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ <xsl:with-param name="attrdir" select="'return'" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ </xsl:call-template>
+ <!-- convert back the output data -->
+ <xsl:call-template name="emitOutputArgBackConverter">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="method"><xsl:value-of select="$gettername" /></xsl:with-param>
+ <xsl:with-param name="name" select="$attrname" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="safearray" select="$attrsafearray" />
+ <xsl:with-param name="varprefix" select="$varprefix" />
+ <xsl:with-param name="callerprefix" select="$callerprefix" />
+ </xsl:call-template>
+</xsl:template>
+
+<!--
+ emitSetAttributeComCall
+ -->
+<xsl:template name="emitSetAttributeComCall">
+ <xsl:param name="ifname" />
+ <xsl:param name="object" /> <!-- normally "pObj->" -->
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:param name="callerprefix" /> <!-- only when called recursively from emitOutputArgBackConverter-->
+
+ <xsl:variable name="settername"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:variable name="upperattrname"><xsl:call-template name="capitalize"><xsl:with-param name="str" select="$attrname" /></xsl:call-template></xsl:variable>
+
+ <xsl:call-template name="emitInputArgConverter">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="method" select="concat($ifname, '::', $settername)" />
+ <xsl:with-param name="methodname" select="concat('COMSETTER(', $upperattrname, ')')" />
+ <xsl:with-param name="object" select="$object" />
+ <xsl:with-param name="name" select="$attrname" />
+ <xsl:with-param name="structprefix" select="concat($G_requestElementVarName, '-&gt;')" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="safearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <xsl:call-template name="emitComCall">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="concat('COMSETTER(', $upperattrname, ')')" />
+ <xsl:with-param name="object" select="$object" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ <xsl:with-param name="attrdir" select="'in'" />
+ </xsl:call-template>
+</xsl:template>
+
+<!--
+ emitGetAttributeMapper
+ -->
+<xsl:template name="emitGetAttributeMapper">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrreadonly" />
+ <xsl:param name="attrsafearray" />
+
+ <xsl:variable name="gettername"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+
+ <xsl:call-template name="emitBeginOfFunctionHeader">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="method" select="$gettername" />
+ </xsl:call-template>
+
+ <xsl:call-template name="emitDocumentStyleArgStructs">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$gettername" />
+ <xsl:with-param name="fOutputs" select="$attrtype" />
+ </xsl:call-template>
+
+ <xsl:text>)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:value-of select="' HRESULT rc = S_OK;'" />
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:call-template name="emitPrologue" />
+
+ <!-- actual COM method call -->
+ <!-- <xsl:choose>
+ array attributes/parameters are not supported yet...
+ <xsl:when test="@array or @safearray='yes'">
+ <xsl:call-template name="warning"><xsl:with-param name="msg" select="concat('emitComCall: SKIPPING ATTRIBUTE IMPLEMENTATION for &quot;', $attrname, '&quot; because it has array type. THIS SOAP METHOD WILL NOT DO ANYTHING!')" /></xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise> -->
+ <xsl:call-template name="emitObjForMethod">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="wsmap"><xsl:value-of select="$wsmap" /></xsl:with-param>
+ <xsl:with-param name="structprefix" select="concat($G_requestElementVarName, '-&gt;')" />
+ </xsl:call-template>
+
+ <xsl:call-template name="emitGetAttributeComCall">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="object" select='"pObj"' />
+ <xsl:with-param name="attrname"><xsl:value-of select="$attrname" /></xsl:with-param>
+ <xsl:with-param name="attrtype"><xsl:value-of select="$attrtype" /></xsl:with-param>
+ <xsl:with-param name="attrsafearray"><xsl:value-of select="$attrsafearray" /></xsl:with-param>
+ </xsl:call-template>
+ <!-- </xsl:otherwise>
+ </xsl:choose> -->
+
+ <xsl:call-template name="emitEpilogue" />
+</xsl:template>
+
+<!--
+ emitSetAttributeMapper:
+ -->
+<xsl:template name="emitSetAttributeMapper">
+ <xsl:param name="ifname" select="$ifname" />
+ <xsl:param name="wsmap" select="$wsmap" />
+ <xsl:param name="attrname" select="$attrname" />
+ <xsl:param name="attrtype" select="$attrtype" />
+ <xsl:param name="attrreadonly" select="$attrreadonly" />
+ <xsl:param name="attrsafearray" select="$attrsafearray" />
+
+ <xsl:variable name="settername"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+
+ <xsl:call-template name="emitBeginOfFunctionHeader">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="method" select="$settername" />
+ </xsl:call-template>
+
+ <xsl:call-template name="emitDocumentStyleArgStructs">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$settername" />
+ <xsl:with-param name="fOutputs" select="1" />
+ </xsl:call-template>
+
+ <xsl:text>)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="' HRESULT rc = S_OK;'" />
+ <xsl:value-of select="concat(concat(' NOREF(', $G_responseElementVarName),');')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitPrologue" />
+
+ <!-- actual COM method call -->
+ <!-- <xsl:choose>
+ array attributes/parameters are not supported yet...
+ <xsl:when test="@array or @safearray='yes'">
+ <xsl:call-template name="warning"><xsl:with-param name="msg" select="concat('emitComCall: SKIPPING ATTRIBUTE IMPLEMENTATION for &quot;', $attrname, '&quot; because it has array type. THIS SOAP METHOD WILL NOT DO ANYTHING!')" /></xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise> -->
+ <xsl:call-template name="emitObjForMethod">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="wsmap"><xsl:value-of select="$wsmap" /></xsl:with-param>
+ <xsl:with-param name="structprefix" select="concat($G_requestElementVarName, '-&gt;')" />
+ </xsl:call-template>
+ <xsl:call-template name="emitSetAttributeComCall">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="object" select='"pObj"' />
+ <xsl:with-param name="attrname"><xsl:value-of select="$attrname" /></xsl:with-param>
+ <xsl:with-param name="attrtype"><xsl:value-of select="$attrtype" /></xsl:with-param>
+ <xsl:with-param name="attrsafearray"><xsl:value-of select="$attrsafearray" /></xsl:with-param>
+ </xsl:call-template>
+ <!-- </xsl:otherwise>
+ </xsl:choose> -->
+
+ <xsl:call-template name="emitEpilogue" />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ interface
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="interface">
+ <!-- remember the interface name in local variables -->
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+ <xsl:variable name="wscpp"><xsl:value-of select="@wscpp" /></xsl:variable>
+
+ <!-- we can save ourselves verifying the interface here as it's already
+ done in the WSDL converter -->
+
+ <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") or ($wscpp="hardcoded") )'>
+ <xsl:text>
+/****************************************************************************
+ *
+ * interface </xsl:text>
+<xsl:copy-of select="$ifname" />
+<xsl:text>
+ *
+ ****************************************************************************/</xsl:text>
+ <xsl:call-template name="xsltprocNewlineOutputHack"/>
+
+ <!--
+ here come the attributes
+ -->
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="attrtype"><xsl:value-of select="@type" /></xsl:variable>
+ <xsl:variable name="attrreadonly"><xsl:value-of select="@readonly" /></xsl:variable>
+ <xsl:variable name="attrsafearray"><xsl:value-of select="@safearray" /></xsl:variable>
+ <xsl:call-template name="emitNewline" />
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:value-of select="concat('// Skipping attribute ', $attrname, ' for it is of suppressed type ', $attrtype)" />
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:value-of select="concat('// Skipping attribute ', $attrname, ' for it is suppressed')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:value-of select="concat('// read-only attribute ', $ifname, '::', $attrname, ' of type ', $attrtype)" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('// read/write attribute ', $ifname, '::', $attrname, ' of type ', $attrtype)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="concat(' (safearray: ', $attrsafearray, ')')" />
+ <!-- emit getter method -->
+ <xsl:call-template name="emitGetAttributeMapper">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrreadonly" select="$attrreadonly" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <!-- for read-write attributes, emit setter method -->
+ <xsl:if test="not(@readonly='yes')">
+ <xsl:call-template name="emitSetAttributeMapper">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrreadonly" select="$attrreadonly" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise> <!-- not wsmap=suppress -->
+ </xsl:choose>
+ </xsl:for-each>
+
+ <!--
+ here come the real methods
+ -->
+
+ <xsl:for-each select="method">
+ <xsl:variable name="methodname"><xsl:value-of select="@name" /></xsl:variable>
+ <!-- method header: return value "int", method name, soap arguments -->
+ <!-- skip this method if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test=" (param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr'])" >
+ <xsl:comment><xsl:value-of select="concat('Skipping method ', $methodname, ' for it has parameters with suppressed types')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('Skipping method ', $methodname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="fHasReturnParms" select="param[@dir='return']" />
+ <xsl:variable name="fHasOutParms" select="param[@dir='out']" />
+
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat('/* method ', $ifname, '::', $methodname, '(')" />
+ <xsl:for-each select="param">
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="concat(' [', @dir, '] ', @type, ' ', @name)" />
+ <xsl:if test="@safearray='yes'">
+ <xsl:text>[]</xsl:text>
+ </xsl:if>
+ <xsl:if test="not(position()=last())">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text> */</xsl:text>
+
+ <xsl:call-template name="emitBeginOfFunctionHeader">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="method" select="$methodname" />
+ </xsl:call-template>
+
+ <xsl:call-template name="emitDocumentStyleArgStructs">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$methodname" />
+ <xsl:with-param name="fOutputs" select="1" />
+ </xsl:call-template>
+ <xsl:text>)</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:text>{</xsl:text>
+ <xsl:call-template name="emitNewline" />
+ <xsl:value-of select="' HRESULT rc = S_OK;'" />
+ <xsl:value-of select="concat(concat(' NOREF(', $G_responseElementVarName),');')" />
+ <xsl:call-template name="emitNewline" />
+ <xsl:call-template name="emitPrologue" />
+
+ <xsl:choose>
+ <xsl:when test="param[@array]">
+ <xsl:call-template name="warning"><xsl:with-param name="msg" select="concat('emitComCall: SKIPPING METHOD IMPLEMENTATION for &quot;', $methodname, '&quot; because it has arguments with &quot;array&quot; types. THIS SOAP METHOD WILL NOT DO ANYTHING!')" /></xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- emit the object upon which to invoke the method -->
+ <xsl:call-template name="emitObjForMethod">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="wsmap"><xsl:value-of select="$wsmap" /></xsl:with-param>
+ <xsl:with-param name="structprefix" select="concat($G_requestElementVarName, '-&gt;')" />
+ </xsl:call-template>
+ <!-- next, emit storage variables to convert the SOAP/C++ arguments to COM types -->
+ <xsl:for-each select="param">
+ <xsl:variable name="dir" select="@dir" />
+ <xsl:choose>
+ <xsl:when test="$dir='in'">
+ <xsl:call-template name="emitInputArgConverter">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="method" select="concat($ifname, '::', $methodname)" />
+ <xsl:with-param name="methodname">
+ <xsl:call-template name="capitalize">
+ <xsl:with-param name="str" select="$methodname" />
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="object" select='"pObj"' />
+ <xsl:with-param name="structprefix" select="concat($G_requestElementVarName, '-&gt;')" />
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$dir='out'">
+ <xsl:call-template name="emitOutputArgBuffer">
+ <xsl:with-param name="method" select="concat($ifname, '::', $methodname)" />
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$dir='return'">
+ <xsl:call-template name="emitOutputArgBuffer">
+ <xsl:with-param name="method" select="concat($ifname, '::', $methodname)" />
+ <xsl:with-param name="name" select="$G_result" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ </xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ <!-- actual COM method call -->
+ <xsl:call-template name="emitComCall">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="object" select='"pObj"' />
+ <xsl:with-param name="methodname">
+ <xsl:call-template name="capitalize">
+ <xsl:with-param name="str" select="$methodname" />
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ <!-- convert back the output data -->
+ <xsl:for-each select="param">
+ <xsl:variable name="dir" select="@dir" />
+ <xsl:if test="$dir='out'">
+ <xsl:call-template name="emitOutputArgBackConverter">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="method" select="$methodname" />
+ <xsl:with-param name="name"><xsl:value-of select="@name" /></xsl:with-param>
+ <xsl:with-param name="type"><xsl:value-of select="@type" /></xsl:with-param>
+ <xsl:with-param name="safearray"><xsl:value-of select="@safearray" /></xsl:with-param>
+ <xsl:with-param name="callerprefix" select="'outparms.'"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$dir='return'">
+ <!-- return values _normally_ should convert to the input arg from the function prototype,
+ except when there are both return and out params; in that case gsoap squeezes them all
+ into the output args structure and the return thing is called "retval" -->
+ <xsl:choose>
+ <xsl:when test="$fHasOutParms">
+ <xsl:call-template name="emitOutputArgBackConverter">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="method" select="$methodname" />
+ <xsl:with-param name="name"><xsl:value-of select="$G_result" /></xsl:with-param>
+ <xsl:with-param name="type"><xsl:value-of select="@type" /></xsl:with-param>
+ <xsl:with-param name="safearray"><xsl:value-of select="@safearray" /></xsl:with-param>
+ <xsl:with-param name="callerprefix" select="'outparms.'"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitOutputArgBackConverter">
+ <xsl:with-param name="ifname"><xsl:value-of select="$ifname" /></xsl:with-param>
+ <xsl:with-param name="method" select="$methodname" />
+ <xsl:with-param name="name"><xsl:value-of select="$G_result" /></xsl:with-param>
+ <xsl:with-param name="type"><xsl:value-of select="@type" /></xsl:with-param>
+ <xsl:with-param name="safearray"><xsl:value-of select="@safearray" /></xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:call-template name="emitEpilogue" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:if>
+
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-nsmap.xsl b/src/VBox/Main/webservice/websrv-nsmap.xsl
new file mode 100644
index 00000000..ddf349e4
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-nsmap.xsl
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-nsmap.xsl:
+ XSLT stylesheet that generates a vboxweb.nsmap file from
+ VirtualBox.xidl, which gets included from C++ client and
+ server code.
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsl:output method="text"/>
+
+ <xsl:strip-space elements="*"/>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ global XSLT variables
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-typemap.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ root match
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="/idl">
+ <xsl:text><![CDATA[
+/* DO NOT EDIT! This is a generated file.
+ * Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML)
+ * Generator: src/VBox/Main/webservice/websrv-nsmap.xsl */
+
+#include "soapH.h"
+SOAP_NMAC struct Namespace namespaces[] =
+{
+ {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
+ {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},
+ {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
+ {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
+]]></xsl:text>
+
+ <xsl:value-of select="concat(' {&quot;vbox&quot;, &quot;', $G_targetNamespace, $G_targetNamespaceSeparator, '&quot;, NULL, NULL},')" />
+ <xsl:call-template name="emitNewline" />
+
+ <xsl:text><![CDATA[
+ {NULL, NULL, NULL, NULL}
+};
+
+]]></xsl:text>
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ if
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+ * ignore all |if|s except those for WSDL target
+-->
+<xsl:template match="if">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ cpp
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="cpp">
+<!-- ignore this -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ library
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="library">
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ class
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="module/class">
+<!-- TODO swallow for now -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ enum
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="enum">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ const
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+<xsl:template match="const">
+ <xsl:apply-templates />
+</xsl:template>
+-->
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ desc
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="desc">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ note
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="note">
+ <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="interface | collection">
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-php.xsl b/src/VBox/Main/webservice/websrv-php.xsl
new file mode 100644
index 00000000..a6c503a6
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-php.xsl
@@ -0,0 +1,647 @@
+<xsl:stylesheet version = '1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+ xmlns:vbox="http://www.virtualbox.org/">
+
+<!--
+ websrv-php.xsl:
+ XSLT stylesheet that generates vboxServiceWrappers.php from
+ VirtualBox.xidl. This PHP file represents our
+ web service API. Depends on WSDL file for actual SOAP bindings.
+
+ Contributed by James Lucas (mjlucas at eng.uts.edu.au).
+-->
+<!--
+ Copyright (C) 2008-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+
+<xsl:output
+ method="text"
+ version="1.0"
+ encoding="utf-8"
+ indent="no"/>
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+<xsl:key name="G_keyInterfacesByName" match="//interface[@name]" use="@name"/>
+
+<xsl:template name="emitOutParam">
+ <xsl:param name="type" />
+ <xsl:param name="value" />
+ <xsl:param name="safearray" />
+
+ <xsl:choose>
+ <xsl:when test="$type='wstring' or $type='uuid'">
+ <xsl:call-template name="emitPrimitive">
+ <xsl:with-param name="type">string</xsl:with-param>
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='boolean'">
+ <xsl:call-template name="emitPrimitive">
+ <xsl:with-param name="type">bool</xsl:with-param>
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='short' or $type='unsigned short' or $type='long' or $type='octet'">
+ <xsl:call-template name="emitPrimitive">
+ <xsl:with-param name="type">int</xsl:with-param>
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='double' or $type='float' or $type='unsigned long' or $type='long long' or $type='unsigned long long'">
+ <xsl:call-template name="emitPrimitive">
+ <xsl:with-param name="type">float</xsl:with-param>
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='$unknown'">
+ <xsl:call-template name="emitObject">
+ <xsl:with-param name="type">VBox_ManagedObject</xsl:with-param>
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitObject">
+ <xsl:with-param name="type" select="$type" />
+ <xsl:with-param name="value" select="$value" />
+ <xsl:with-param name="safearray" select="$safearray"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="emitObject">
+ <xsl:param name="type" />
+ <xsl:param name="value" />
+ <xsl:param name="safearray" />
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:text>new </xsl:text><xsl:value-of select="$type" />Collection ($this->connection, (array)<xsl:value-of select="$value"/><xsl:text>)</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>new </xsl:text><xsl:value-of select="$type" /> ($this->connection, <xsl:value-of select="$value"/><xsl:text>)</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="emitPrimitive">
+ <xsl:param name="type" />
+ <xsl:param name="value" />
+ <xsl:param name="safearray" />
+ <xsl:choose>
+ <xsl:when test="$safearray='yes'">
+ <xsl:text>(array)</xsl:text><xsl:value-of select="$value"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>(</xsl:text><xsl:value-of select="$type" /><xsl:text>)</xsl:text><xsl:value-of select="$value"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="emitGetAttribute">
+ <xsl:param name="ifname" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:variable name="fname"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname"/></xsl:call-template> </xsl:variable>
+ public function <xsl:value-of select="$fname"/>()
+ {
+ $request = new stdClass();
+ $request->_this = $this->handle;
+ $response = $this->connection->__soapCall('<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>', array((array)$request));
+ <xsl:text>return </xsl:text>
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="value" select="concat('$response->','returnval')" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template><xsl:text>;</xsl:text>
+ }
+</xsl:template>
+
+<xsl:template name="emitSetAttribute">
+ <xsl:param name="ifname" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:variable name="fname"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname"/></xsl:call-template></xsl:variable>
+ public function <xsl:value-of select="$fname"/>($value)
+ {
+ $request = new stdClass();
+ $request->_this = $this->handle;
+<xsl:choose>
+<xsl:when test="$attrsafearray='yes'"> if (is_array($value) || is_null($value) || is_scalar($value))</xsl:when>
+<xsl:otherwise> if (is_null($value) || is_scalar($value))</xsl:otherwise>
+</xsl:choose>
+ {
+ $request-><xsl:value-of select="$attrname"/> = $value;
+ }
+ else
+ {
+ $request-><xsl:value-of select="$attrname"/> = $value->handle;
+ }
+ $this->connection->__soapCall('<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>', array((array)$request));
+ }
+</xsl:template>
+
+<xsl:template name="interface">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+ <xsl:variable name="extends"><xsl:value-of select="@extends" /></xsl:variable>
+ <xsl:text>
+/**
+ * Generated VBoxWebService Interface Wrapper
+ */
+</xsl:text>
+ <xsl:choose>
+ <xsl:when test="($extends = '$unknown') or ($extends = '$errorinfo')">
+ <xsl:value-of select="concat('class ', $ifname, ' extends VBox_ManagedObject&#10;{&#10;')" />
+ </xsl:when>
+ <xsl:when test="count(key('G_keyInterfacesByName', $extends)) > 0">
+ <xsl:value-of select="concat('class ', $ifname, ' extends ', $extends, '&#10;{&#10;')" />
+ </xsl:when>
+ </xsl:choose>
+ <xsl:for-each select="method">
+ <xsl:if test="not((param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr']))" >
+ <xsl:call-template name="method">
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="attrtype"><xsl:value-of select="@type" /></xsl:variable>
+ <xsl:variable name="attrreadonly"><xsl:value-of select="@readonly" /></xsl:variable>
+ <xsl:variable name="attrsafearray"><xsl:value-of select="@safearray" /></xsl:variable>
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrtype, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:comment> readonly attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:comment> read/write attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!-- aa) get method: emit request and result -->
+ <xsl:call-template name="emitGetAttribute">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <!-- bb) emit a set method if the attribute is read/write -->
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:call-template name="emitSetAttribute">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text>}
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="collection">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:text>
+/**
+ * Generated VBoxWebService Managed Object Collection
+ */</xsl:text>
+class <xsl:value-of select="$ifname"/>Collection extends VBox_ManagedObjectCollection
+{
+ protected $_interfaceName = "<xsl:value-of select="$ifname"/>";
+}
+</xsl:template>
+
+<xsl:template name="interfacestruct">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:text>
+/**
+ * Generated VBoxWebService Struct
+ */</xsl:text>
+class <xsl:value-of select="$ifname"/> extends VBox_Struct
+{
+<xsl:for-each select="attribute"> protected $<xsl:value-of select="@name"/>;
+</xsl:for-each>
+ public function __construct($connection, $values)
+ {
+ $this->connection = $connection;
+<xsl:for-each select="attribute"> $this-><xsl:value-of select="@name"/> = $values-><xsl:value-of select="@name"/>;
+</xsl:for-each> }
+
+<xsl:for-each select="attribute"> public function <xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="@name"/></xsl:call-template>()
+ {
+ <xsl:text>return </xsl:text>
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="value" select="concat('$this->',@name)" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template>;
+ }
+</xsl:for-each>}
+</xsl:template>
+
+<xsl:template name="structcollection">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:text>
+/**
+ * Generated VBoxWebService Struct Collection
+ */</xsl:text>
+class <xsl:value-of select="$ifname"/>Collection extends VBox_StructCollection
+{
+ protected $_interfaceName = "<xsl:value-of select="$ifname"/>";
+}
+</xsl:template>
+
+<xsl:template name="genreq">
+ <xsl:param name="wsmap" />
+ <xsl:text> $request = new stdClass();
+</xsl:text>
+ <xsl:if test="$wsmap='managed'"> $request->_this = $this->handle;</xsl:if>
+ <xsl:for-each select="param[@dir='in']">
+ $request-><xsl:value-of select="@name" /> = $arg_<xsl:value-of select="@name" /><xsl:text>;</xsl:text>
+ </xsl:for-each>
+ $response = $this->connection->__soapCall('<xsl:value-of select="../@name"/>_<xsl:value-of select="@name"/>', array((array)$request));
+ return <xsl:if test="param[@dir='out']">
+ <xsl:text>array(</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="param[@dir='return']">
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="value" select="concat('$response->','returnval')" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template>
+ <xsl:if test="../param[@dir='out']">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:for-each select="param[@dir='out']">
+ <xsl:if test="not(position()=1)">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="value" select="concat('$response->',@name)" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ <xsl:if test="param[@dir='out']">
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+ <xsl:text>;&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template name="method" >
+ <xsl:param name="wsmap" />
+ public function <xsl:value-of select="@name"/><xsl:text>(</xsl:text>
+ <xsl:for-each select="param[@dir='in']">
+ <xsl:if test="not(position()=1)">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ <xsl:value-of select="concat('$arg_',@name)"/>
+ </xsl:for-each> <xsl:text>)&#10; {&#10;</xsl:text>
+ <xsl:call-template name="genreq"><xsl:with-param name="wsmap" select="$wsmap" /></xsl:call-template>
+ <xsl:text> }&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template name="enum">
+ <xsl:text>
+/**
+ * Generated VBoxWebService ENUM
+ */</xsl:text>
+class <xsl:value-of select="@name"/> extends VBox_Enum
+{
+ public $NameMap = array(<xsl:for-each select="const"><xsl:if test="not(@wsmap='suppress')"><xsl:value-of select="@value"/> => '<xsl:value-of select="@name"/>'<xsl:if test="not(position()=last())">, </xsl:if></xsl:if></xsl:for-each>);
+ public $ValueMap = array(<xsl:for-each select="const"><xsl:if test="not(@wsmap='suppress')">'<xsl:value-of select="@name"/>' => <xsl:value-of select="@value"/><xsl:if test="not(position()=last())">, </xsl:if></xsl:if></xsl:for-each>);
+}
+</xsl:template>
+
+<xsl:template name="enumcollection">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:text>
+/**
+ * Generated VBoxWebService Enum Collection
+ */</xsl:text>
+class <xsl:value-of select="$ifname"/>Collection extends VBox_EnumCollection
+{
+ protected $_interfaceName = "<xsl:value-of select="$ifname"/>";
+}
+</xsl:template>
+
+<xsl:template name="comResultCodes">
+ const <xsl:value-of select="@name"/> = <xsl:value-of select="@value"/>;
+</xsl:template>
+
+<xsl:template match="/">
+<xsl:text>&lt;?php
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * 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.LIB" 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.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+/*
+ * This file is autogenerated from VirtualBox.xidl, DO NOT EDIT!
+ */
+
+class VBox_ManagedObject
+{
+ protected $connection;
+ protected $handle;
+
+ public function __construct($soap, $handle = null)
+ {
+ $this->connection = $soap;
+ $this->handle = $handle;
+ }
+
+ public function __toString()
+ {
+ return (string)$this->handle;
+ }
+
+ public function __set($attr, $value)
+ {
+ $methodName = "set" . $attr;
+ if (method_exists($this, $methodName))
+ $this->$methodName($value);
+ else
+ throw new Exception("Attribute does not exist");
+ }
+
+ public function __get($attr)
+ {
+ $methodName = "get" . $attr;
+ if (method_exists($this, $methodName))
+ return $this->$methodName();
+ else
+ 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)
+ {
+ }
+ }
+}
+
+abstract class VBox_Collection implements ArrayAccess, Iterator, Countable
+{
+ protected $_connection;
+ protected $_values;
+ protected $_objects;
+ protected $_interfaceName;
+
+ public function __construct($soap, array $values = array())
+ {
+ $this->_connection = $soap;
+ $this->_values = $values;
+ $this->_soapToObject();
+ }
+
+ protected function _soapToObject()
+ {
+ $this->_objects = array();
+ foreach($this->_values as $value)
+ {
+ $this->_objects[] = new $this->_interfaceName($this->_connection, $value);
+ }
+ }
+
+ /** ArrayAccess Functions **/
+ public function offsetSet($offset, $value)
+ {
+ if ($value instanceof $this->_interfaceName)
+ {
+ if ($offset)
+ {
+ $this->_objects[$offset] = $value;
+ }
+ else
+ {
+ $this->_objects[] = $value;
+ }
+ }
+ else
+ {
+ throw new Exception("Value must be a instance of " . $this->_interfaceName);
+ }
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->_objects[$offset]);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->_objects[$offset]);
+ }
+
+ public function offsetGet($offset)
+ {
+ return isset($this->_objects[$offset]) ? $this->_objects[$offset] : null;
+ }
+
+ /** Iterator Functions **/
+ public function rewind()
+ {
+ reset($this->_objects);
+ }
+
+ public function current()
+ {
+ return current($this->_objects);
+ }
+
+ public function key()
+ {
+ return key($this->_objects);
+ }
+
+ public function next()
+ {
+ return next($this->_objects);
+ }
+
+ public function valid()
+ {
+ return ($this->current() !== false);
+ }
+
+ /** Countable Functions **/
+ public function count()
+ {
+ return count($this->_objects);
+ }
+}
+
+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();
+ }
+}
+
+abstract class VBox_Struct
+{
+ protected $connection;
+
+ public function __get($attr)
+ {
+ $methodName = "get" . $attr;
+ if (method_exists($this, $methodName))
+ return $this->$methodName();
+ else
+ throw new Exception("Attribute does not exist");
+ }
+}
+
+abstract class VBox_StructCollection extends VBox_Collection
+{
+
+ public function __construct($soap, array $values = array())
+ {
+ if (!(array_values($values) === $values))
+ {
+ $values = array((object)$values); //Fix for when struct return value only contains one list item (e.g. one medium attachment)
+ }
+ parent::__construct($soap, $values);
+ }
+}
+
+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
+{
+}
+
+</xsl:text>
+
+<xsl:text>
+/**
+ * VirtualBox COM result codes
+ */
+class VirtualBox_COM_result_codes
+{
+</xsl:text>
+ <xsl:for-each select="/idl/library/result">
+ <xsl:call-template name="comResultCodes"/>
+ </xsl:for-each>
+<xsl:text>
+}
+</xsl:text>
+ <xsl:for-each select="//interface[@wsmap='managed' or @wsmap='global']">
+ <xsl:call-template name="interface"/>
+ <xsl:call-template name="collection"/>
+ </xsl:for-each>
+ <xsl:for-each select="//interface[@wsmap='struct']">
+ <xsl:call-template name="interfacestruct"/>
+ <xsl:call-template name="structcollection"/>
+ </xsl:for-each>
+ <xsl:for-each select="//enum">
+ <xsl:call-template name="enum"/>
+ <xsl:call-template name="enumcollection"/>
+ </xsl:for-each>
+
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-python.xsl b/src/VBox/Main/webservice/websrv-python.xsl
new file mode 100644
index 00000000..7a32cb9d
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-python.xsl
@@ -0,0 +1,923 @@
+<xsl:stylesheet version = '1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+ xmlns:vbox="http://www.virtualbox.org/">
+
+<!--
+ websrv-python.xsl:
+ XSLT stylesheet that generates VirtualBox_services.py from
+ VirtualBox.xidl. This Python file represents our
+ web service API. Depends on WSDL file for actual SOAP bindings.
+-->
+<!--
+ Copyright (C) 2008-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+
+<xsl:output
+ method="text"
+ version="1.0"
+ encoding="utf-8"
+ indent="no"/>
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+<xsl:template name="emitConvertedType">
+ <xsl:param name="ifname" />
+ <xsl:param name="methodname" />
+ <xsl:param name="type" />
+ <xsl:choose>
+ <xsl:when test="$type='wstring'">String</xsl:when>
+ <xsl:when test="$type='uuid'">String</xsl:when>
+ <xsl:when test="$type='boolean'">Boolean</xsl:when>
+ <xsl:when test="$type='unsigned long'">UnsignedInt</xsl:when>
+ <xsl:when test="$type='double'">Double</xsl:when>
+ <xsl:when test="$type='float'">Float</xsl:when>
+ <xsl:when test="$type='long'">Int</xsl:when>
+ <xsl:when test="$type='long long'">Long</xsl:when>
+ <xsl:when test="$type='short'">Short</xsl:when>
+ <xsl:when test="$type='unsigned short'">UnsignedShort</xsl:when>
+ <xsl:when test="$type='unsigned long long'">UnsignedLong</xsl:when>
+ <xsl:when test="$type='result'">UnsignedInt</xsl:when>
+ <xsl:when test="$type='octet'">Octet</xsl:when>
+ <xsl:when test="$type='$unknown'">IUnknown</xsl:when>
+ <xsl:otherwise><xsl:value-of select="$type" /></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="emitOutParam">
+ <xsl:param name="ifname" />
+ <xsl:param name="methodname" />
+ <xsl:param name="type" />
+ <xsl:param name="value" />
+ <xsl:param name="safearray" />
+
+ <xsl:choose>
+ <xsl:when test="$type='octet' and $safearray">
+ <xsl:value-of select="concat('self.mgr.decodebase64(',$value,')')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitConvertedType">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$methodname" />
+ <xsl:with-param name="type" select="$type" />
+ </xsl:call-template>
+ <xsl:text>(</xsl:text>
+ <xsl:text>self.mgr,</xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:if test="$safearray='yes'">
+ <xsl:value-of select="', True'"/>
+ </xsl:if>
+ <xsl:text>)</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="emitGetAttribute">
+ <xsl:param name="ifname" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:variable name="fname"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname"/></xsl:call-template> </xsl:variable>
+ def <xsl:value-of select="$fname"/>(self):
+ req=<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>RequestMsg()
+ req._this=self.handle
+ val=self.mgr.getPort().<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>(req)
+ <xsl:text>return </xsl:text>
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="@name" />
+ <xsl:with-param name="type" select="$attrtype" />
+ <xsl:with-param name="value" select="concat('val.','_returnval')" />
+ <xsl:with-param name="safearray" select="$attrsafearray"/>
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template name="emitSetAttribute">
+ <xsl:param name="ifname" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+ <xsl:variable name="fname"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname"/></xsl:call-template> </xsl:variable>
+ def <xsl:value-of select="$fname"/>(self, value):
+ req=<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>RequestMsg()
+ req._this=self.handle
+ if type(value) in [int, bool, basestring, str<xsl:if test="$attrsafearray='yes'">, tuple, list</xsl:if>]:
+ req._<xsl:value-of select="$attrname"/> = value
+ else:
+ req._<xsl:value-of select="$attrname"/> = value.handle
+ self.mgr.getPort().<xsl:value-of select="$ifname"/>_<xsl:value-of select="$fname"/>(req)
+</xsl:template>
+
+<xsl:template name="collection">
+ <xsl:variable name="cname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="ename"><xsl:value-of select="@type" /></xsl:variable>
+class <xsl:value-of select="$cname"/>:
+ def __init__(self, mgr, array):
+ self.array = array
+ self.mgr = mgr
+
+ def __next(self):
+ return self.array.__next()
+
+ def __size(self):
+ return self.array._array.__size()
+
+ def __len__(self):
+ return self.array._array.__len__()
+
+ def __getitem__(self, index):
+ return <xsl:value-of select="$ename"/>(self.mgr, self.array._array[index])
+
+</xsl:template>
+
+
+<xsl:template name="computeExtends">
+ <xsl:param name="base" />
+
+ <xsl:choose>
+ <xsl:when test="($base = '$unknown')">
+ <xsl:value-of select="'IUnknown'"/>
+ </xsl:when>
+ <xsl:when test="($base = '$errorinfo') ">
+ <xsl:value-of select="'IUnknown'"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$base"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="interface">
+ <xsl:variable name="base">
+ <xsl:call-template name="computeExtends">
+ <xsl:with-param name="base" select="@extends" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+
+class <xsl:value-of select="$ifname"/>(<xsl:value-of select="$base" />):
+ def __init__(self, mgr, handle, isarray = False):
+ self.mgr = mgr
+ if handle is None:
+ raise Exception("bad handle: "+str(handle))
+ self.handle = handle
+ self.isarray = isarray
+ if self.isarray:
+ for strHnd in handle:
+ mgr.register(strHnd)
+ else:
+ mgr.register(self.handle)
+
+ def __del__(self):
+ self.releaseRemote()
+
+ def releaseRemote(self):
+ try:
+ if self.handle is not None:
+ if self.isarray:
+ for strHnd in self.handle:
+ self.mgr.unregister(strHnd)
+ else:
+ self.mgr.unregister(self.handle)
+ self.handle = None;
+ except:
+ pass
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return <xsl:value-of select="$ifname" />(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+ def __str__(self):
+ if self.isarray:
+ return str(self.handle)
+ else:
+ return self.handle
+
+ def isValid(self):
+ return self.handle != None and self.handle != ''
+
+ def __getattr__(self,name):
+ hndl = <xsl:value-of select="$ifname" />._Attrs_.get(name, None)
+ if hndl != None:
+ if hndl[0] != None:
+ return hndl[0](self)
+ else:
+ raise AttributeError
+ else:
+ return <xsl:value-of select="$base" />.__getattr__(self, name)
+
+ def __setattr__(self, name, val):
+ hndl = <xsl:value-of select="$ifname" />._Attrs_.get(name, None)
+ if (hndl != None and hndl[1] != None):
+ hndl[1](self,val)
+ else:
+ self.__dict__[name] = val
+
+ <xsl:for-each select="method">
+ <xsl:call-template name="method"/>
+ </xsl:for-each>
+
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="attrtype"><xsl:value-of select="@type" /></xsl:variable>
+ <xsl:variable name="attrreadonly"><xsl:value-of select="@readonly" /></xsl:variable>
+ <xsl:variable name="attrsafearray"><xsl:value-of select="@safearray" /></xsl:variable>
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrtype, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:comment> readonly attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:comment> read/write attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!-- aa) get method: emit request and result -->
+ <xsl:call-template name="emitGetAttribute">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <!-- bb) emit a set method if the attribute is read/write -->
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:call-template name="emitSetAttribute">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+
+ _Attrs_=<xsl:text>{</xsl:text>
+ <xsl:for-each select="attribute">
+ <xsl:if test="not( @type=($G_setSuppressedInterfaces/@name) )">
+ <xsl:text> </xsl:text>'<xsl:value-of select="@name"/>'<xsl:text>:[</xsl:text>
+ <xsl:call-template name="makeGetterName">
+ <xsl:with-param name="attrname" select="@name"/>
+ </xsl:call-template>
+ <xsl:text>,</xsl:text>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:text>None</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="makeSetterName">
+ <xsl:with-param name="attrname" select="@name"/>
+ </xsl:call-template>,
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>]</xsl:text>
+ <xsl:if test="not(position()=last())"><xsl:text>,&#10;</xsl:text></xsl:if>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>}</xsl:text>
+</xsl:template>
+
+<xsl:template name="interfacestruct">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+class <xsl:value-of select="$ifname"/>:
+ def __init__(self, mgr, handle, isarray = False):
+ self.mgr = mgr
+ self.isarray = isarray
+ if isarray:
+ self.handle = handle
+ else:
+<xsl:for-each select="attribute">
+ self.<xsl:value-of select="@name"/> = <xsl:call-template name="emitConvertedType">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="''" />
+ <xsl:with-param name="type" select="@type" />
+ </xsl:call-template>(self.mgr, handle._<xsl:value-of select="@name"/>)
+ </xsl:for-each>
+ pass
+
+ <!-- also do getters/setters -->
+ <xsl:for-each select="attribute">
+ def <xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="@name"/></xsl:call-template>(self):
+ return self.<xsl:value-of select="@name"/>
+
+ def <xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="@name"/></xsl:call-template>(self):
+ raise Error('setters not supported')
+ </xsl:for-each>
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return <xsl:value-of select="$ifname" />(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+<xsl:call-template name="xsltprocNewlineOutputHack"/>
+</xsl:template>
+
+<xsl:template name="convertInParam">
+ <xsl:param name="type" />
+ <xsl:param name="safearray" />
+ <xsl:param name="arg" />
+
+ <xsl:choose>
+ <xsl:when test="$type='octet' and $safearray">
+ <xsl:value-of select="concat('self.mgr.encodebase64(',$arg,')')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$arg" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="genreq">
+ <xsl:text>req=</xsl:text><xsl:value-of select="../@name"/>_<xsl:value-of select="@name"/>RequestMsg()
+ req._this=self.handle
+ <xsl:for-each select="param[@dir='in']">
+ req._<xsl:value-of select="@name" />=<xsl:call-template name="convertInParam">
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="arg" select="concat('_arg_', @name)" />
+ </xsl:call-template>
+ </xsl:for-each>
+ val=self.mgr.getPort().<xsl:value-of select="../@name"/>_<xsl:value-of select="@name"/>(req)
+ <!-- return needs to be the first one -->
+ return <xsl:for-each select="param[@dir='return']">
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="ifname" select="../@name" />
+ <xsl:with-param name="methodname" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="value" select="concat('val.','_returnval')" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template>
+ <xsl:if test="../param[@dir='out']">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:for-each select="param[@dir='out']">
+ <xsl:if test="not(position()=1)">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ <xsl:call-template name="emitOutParam">
+ <xsl:with-param name="ifname" select="../@name" />
+ <xsl:with-param name="methodname" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="value" select="concat('val._',@name)" />
+ <xsl:with-param name="safearray" select="@safearray"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ <xsl:text>&#10;&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template name="method" >
+ def <xsl:value-of select="@name"/><xsl:text>(self</xsl:text>
+ <xsl:for-each select="param[@dir='in']">
+ <xsl:text>, </xsl:text>
+ <xsl:value-of select="concat('_arg_',@name)"/>
+ </xsl:for-each><xsl:text>):&#10; </xsl:text>
+ <xsl:call-template name="genreq"/>
+</xsl:template>
+
+<xsl:template name="makeConstantName" >
+ <xsl:choose>
+ <!-- special case for reserved word, maybe will need more in the future -->
+ <xsl:when test="@name='None'">
+ <xsl:text>_None</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="enum">
+class <xsl:value-of select="@name"/>:
+ def __init__(self,mgr,handle):
+ self.mgr=mgr
+ if isinstance(handle,basestring):
+ self.handle=<xsl:value-of select="@name"/>._ValueMap[handle]
+ else:
+ self.handle=handle
+
+ def __eq__(self,other):
+ if isinstance(other,<xsl:value-of select="@name"/>):
+ return self.handle == other.handle
+ if isinstance(other,int):
+ return self.handle == other
+ if isinstance(other,basestring):
+ return str(self) == other
+ return False
+
+ def __ne__(self,other):
+ if isinstance(other,<xsl:value-of select="@name"/>):
+ return self.handle != other.handle
+ if isinstance(other,int):
+ return self.handle != other
+ if isinstance(other,basestring):
+ return str(self) != other
+ return True
+
+ def __str__(self):
+ return <xsl:value-of select="@name"/>._NameMap[self.handle]
+
+ def __int__(self):
+ return self.handle
+
+ _NameMap={<xsl:for-each select="const">
+ <xsl:value-of select="@value"/>:'<xsl:value-of select="@name"/>'<xsl:if test="not(position()=last())">,</xsl:if>
+ </xsl:for-each>}
+ _ValueMap={<xsl:for-each select="const">
+ '<xsl:value-of select="@name"/>':<xsl:value-of select="@value"/><xsl:if test="not(position()=last())">,</xsl:if>
+ </xsl:for-each>}
+
+<xsl:for-each select="const"><xsl:text> </xsl:text><xsl:call-template name="makeConstantName"><xsl:with-param name="name" select="@name"/></xsl:call-template>=<xsl:value-of select="@value"/><xsl:text>&#xa;</xsl:text>
+</xsl:for-each>
+</xsl:template>
+
+<xsl:template match="/">
+<xsl:text># Copyright (C) 2008-2022 Oracle and/or its affiliates.
+#
+# 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.LIB" 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.
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+
+#
+# This file is autogenerated from VirtualBox.xidl, DO NOT EDIT!
+#
+
+# Works only with ZSI 2.0 generated stubs (part of the VirtualBox SDK).
+from VirtualBox_client import *
+
+class ObjectRefManager:
+ def __init__(self, sessionmgr):
+ self.map = {}
+ self.sessionmgr = sessionmgr
+
+ def register(self, handle):
+ if handle == None:
+ return
+ c = self.map.get(handle,0)
+ c = c + 1
+ self.map[handle]=c
+
+ def unregister(self, handle):
+ if handle == None:
+ return
+ c = self.map.get(handle,-1)
+ if c == -1:
+ raise Error('wrong refcount')
+ c = c - 1
+ if c == 0:
+ try:
+ req=IManagedObjectRef_releaseRequestMsg()
+ req._this=handle
+ self.sessionmgr.getPort().IManagedObjectRef_release(req)
+ except:
+ pass
+ del self.map[handle]
+ else:
+ self.map[handle] = c
+
+class String:
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return String(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+ def __str__(self):
+ return str(self.handle)
+
+ def __eq__(self,other):
+ if self.isarray:
+ return isinstance(other,String) and self.handle == other.handle
+ if isinstance(other,String):
+ return self.handle == other.handle
+ if isinstance(other,basestring):
+ return self.handle == other
+ return False
+
+ def __ne__(self,other):
+ if self.isarray:
+ return not isinstance(other,String) or self.handle != other.handle
+ if isinstance(other,String):
+ return self.handle != other.handle
+ if isinstance(other,basestring):
+ return self.handle != other
+ return True
+
+ def __add__(self,other):
+ return str(self.handle)+str(other)
+
+
+class Boolean:
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ if self.handle == "false":
+ self.handle = None
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __str__(self):
+ if self.handle:
+ return "true"
+ else:
+ return "false"
+
+ def __eq__(self,other):
+ if isinstance(other,Bool):
+ return self.handle == other.value
+ if isinstance(other,bool):
+ return self.handle == other
+ return False
+
+ def __ne__(self,other):
+ if isinstance(other,Bool):
+ return self.handle != other.handle
+ if isinstance(other,bool):
+ return self.handle != other
+ return True
+
+ def __int__(self):
+ if self.handle:
+ return 1
+ else:
+ return 0
+
+ def __long__(self):
+ if self.handle:
+ return 1
+ else:
+ return 0
+
+ def __nonzero__(self):
+ if self.handle:
+ return True
+ else:
+ return False
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Boolean(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class Number:
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __str__(self):
+ return str(self.handle)
+
+ def __int__(self):
+ return int(self.handle)
+
+ def __long__(self):
+ return long(self.handle)
+
+ def __float__(self):
+ return float(self.handle)
+
+ def __lt__(self, other):
+ if self.isarray:
+ return NotImplemented
+ else:
+ return self.handle &lt; other
+
+ def __le__(self, other):
+ if self.isarray:
+ return NotImplemented
+ else:
+ return self.handle &lt;= other
+
+ def __eq__(self, other):
+ return self.handle == other
+
+ def __ne__(self, other):
+ return self.handle != other
+
+ def __gt__(self, other):
+ if self.isarray:
+ return NotImplemented
+ else:
+ return self.handle &gt; other
+
+ def __ge__(self, other):
+ if self.isarray:
+ return NotImplemented
+ else:
+ return self.handle &gt;= other
+
+class Octet:
+ def __init__(self, mgr, handle, isarray = False):
+ self.mgr = mgr
+ self.isarray = isarray
+ if isarray:
+ self.handle = mgr.decodebase64(handle)
+ else:
+ raise TypeError("only octet arrays")
+
+ def __getitem__(self, index):
+ return self.handle[index]
+
+ def __str__(self):
+ return str(self.handle)
+
+ def __len__(self):
+ return self.handle.__len__()
+
+class UnsignedInt(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return UnsignedInt(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+
+class Int(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Int(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class UnsignedShort(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return UnsignedShort(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class Short(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Short(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class UnsignedLong(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return UnsignedLong(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class Long(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Long(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class Double(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Double(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class Float(Number):
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return Float(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+class IUnknown:
+ def __init__(self, mgr, handle, isarray = False):
+ self.handle = handle
+ self.mgr = mgr
+ self.isarray = isarray
+
+ def __nonzero__(self):
+ if self.handle != "":
+ return True
+ else:
+ return False
+
+ def __next(self):
+ if self.isarray:
+ return self.handle.__next()
+ raise TypeError("iteration over non-sequence")
+
+ def __size(self):
+ if self.isarray:
+ return self.handle.__size()
+ raise TypeError("iteration over non-sequence")
+
+ def __len__(self):
+ if self.isarray:
+ return self.handle.__len__()
+ raise TypeError("iteration over non-sequence")
+
+ def __getitem__(self, index):
+ if self.isarray:
+ return IUnknown(self.mgr, self.handle[index])
+ raise TypeError("iteration over non-sequence")
+
+ def __str__(self):
+ return str(self.handle)
+
+ def __eq__(self, other):
+ return self.handle == other
+
+ def __ne__(self, other):
+ return self.handle != other
+
+ def __getattr__(self,attr):
+ if self.__class__.__dict__.get(attr) != None:
+ return self.__class__.__dict__.get(attr)
+ if self.__dict__.get(attr) != None:
+ return self.__dict__.get(attr)
+ raise AttributeError
+
+</xsl:text>
+ <xsl:for-each select="//interface[@wsmap='managed' or @wsmap='global']">
+ <xsl:call-template name="interface"/>
+ </xsl:for-each>
+ <xsl:for-each select="//interface[@wsmap='struct']">
+ <xsl:call-template name="interfacestruct"/>
+ </xsl:for-each>
+ <xsl:for-each select="//enum">
+ <xsl:call-template name="enum"/>
+ </xsl:for-each>
+ <xsl:text>
+
+import base64
+
+class IWebsessionManager2(IWebsessionManager, ObjectRefManager):
+ def __init__(self, url):
+ self.url = url
+ self.port = None
+ self.handle = None
+ self.mgr = self
+ ObjectRefManager.__init__(self, self.mgr)
+
+ def getPort(self):
+ if self.port is None:
+ try:
+ self.port = vboxServiceLocator().getvboxPortType(self.url)
+ except:
+ self.port = vboxServiceLocator().getvboxServicePort(self.url)
+ return self.port
+
+ def decodebase64(self, str):
+ return base64.decodestring(str)
+
+ def encodebase64(self, str):
+ return base64.encodestring(str)
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-typemap.xsl b/src/VBox/Main/webservice/websrv-typemap.xsl
new file mode 100644
index 00000000..d24e6bce
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-typemap.xsl
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-typemap.xsl:
+ XSLT stylesheet that generates a typemap file from
+ VirtualBox.xidl for use with the gSOAP compilers.
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsl:output method="text"/>
+
+ <xsl:strip-space elements="*"/>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ global XSLT variables
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-typemap.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ root match
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="/idl">
+ <xsl:text><![CDATA[
+# DO NOT EDIT! This is a generated file.
+# Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML)
+# Generator: src/VBox/Main/webservice/websrv-typemap.xsl
+
+# forces typedefs:
+xsd__int = | long
+xsd__unsignedInt = | unsigned long
+
+# xsd__short =| int16_t
+# xsd__unsignedShort =| uint16_t
+# xsd__int =| int32_t
+# xsd__unsignedInt =| uint32_t
+# xsd__long =| int64_t
+# xsd__unsignedLong =| uint64_t
+
+# Main namespace (which is mapped to vbox__ prefixes):
+]]></xsl:text>
+ <xsl:value-of select="concat('vbox = &quot;', $G_targetNamespace, '&quot;')" />
+ <xsl:text>
+
+# Namespaces for the interfaces in xidl that need to be mapped according to their wsmap attribs:
+</xsl:text>
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ if
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+ * ignore all |if|s except those for WSDL target
+-->
+<xsl:template match="if">
+ <xsl:if test="@target='wsdl'">
+ <xsl:apply-templates/>
+ </xsl:if>
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ cpp
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="cpp">
+<!-- ignore this -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ library
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="library">
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ class
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="module/class">
+<!-- TODO swallow for now -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ enum
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="enum">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ const
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+<xsl:template match="const">
+ <xsl:apply-templates />
+</xsl:template>
+-->
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ desc
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="desc">
+<!-- TODO swallow for now -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ note
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="note">
+<!-- TODO -->
+ <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="interface | collection">
+ <!-- remember the interface name in local variables -->
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$wsmap='struct'" />
+ <xsl:when test="$wsmap='suppress'" />
+ <xsl:otherwise>
+ <xsl:value-of select="concat($ifname, ' = ', $G_targetNamespace, $G_targetNamespaceSeparator,
+ $ifname, $G_bindingSuffix, $G_sNewLine)" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-wsdl-service.xsl b/src/VBox/Main/webservice/websrv-wsdl-service.xsl
new file mode 100644
index 00000000..fefbb816
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-wsdl-service.xsl
@@ -0,0 +1,204 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-wsdl.xsl:
+ XSLT stylesheet that generates vboxwebService.wsdl from
+ VirtualBox.xidl. That extra WSDL file includes the big
+ vboxweb.wsdl file and adds a "service" section.
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ targetNamespace="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
+
+<xsl:param name="G_argDebug" />
+
+<xsl:output
+ method="xml"
+ version="1.0"
+ encoding="utf-8"
+ indent="yes"/>
+
+<xsl:strip-space
+ elements="*" />
+
+<!--**********************************************************************
+ *
+ * global XSLT variables
+ *
+ **********************************************************************-->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-wsdl-service.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- collect all interfaces with "wsmap='suppress'" in a global variable for
+ quick lookup -->
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+<!--**********************************************************************
+ *
+ * shared helpers
+ *
+ **********************************************************************-->
+
+
+<!--**********************************************************************
+ *
+ * matches
+ *
+ **********************************************************************-->
+
+<!--
+A WSDL document describes a web service using these major elements:
+Element Defines
+<portType> The operations performed by the web service. A portType can be thought
+ of as a class.
+<message> The messages used by the web service. A message is a function call
+ and with it come "parts", which are the parameters.
+<types> The data types used by the web service, described in XML Schema
+ syntax.
+<binding> The communication protocols used by the web service.
+
+The root tag is <definitions>.
+
+-->
+
+<xsl:template match="/idl">
+ <xsl:comment>
+ DO NOT EDIT! This is a generated file.
+ Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's generic pseudo-IDL file)
+ Generator: src/VBox/Main/webservice/websrv-wsdl-service.xsl
+</xsl:comment>
+ <xsl:apply-templates />
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ if
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+ * ignore all |if|s except those for WSDL target
+-->
+<xsl:template match="if">
+ <xsl:if test="@target='wsdl'">
+ <xsl:apply-templates/>
+ </xsl:if>
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ cpp
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="cpp">
+<!-- ignore this -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ library
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+ "library" match: we use this to emit most of the WSDL <types> section.
+ With WSDL "document" style, this requires us to go through all interfaces
+ and emit complexTypes for all method arguments and return values.
+-->
+<xsl:template match="library">
+ <definitions xmlns:interface="urn:vbox"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:vbox="http://www.virtualbox.org/"
+ name="VirtualBox"
+ xmlns="http://schemas.xmlsoap.org/wsdl/">
+ <xsl:attribute name="targetNamespace"><xsl:value-of select="concat($G_targetNamespace, 'Service')" /></xsl:attribute>
+
+ <import location="vboxweb.wsdl" namespace="urn:vbox">
+ <xsl:attribute name="namespace"><xsl:value-of select="$G_targetNamespace" /></xsl:attribute>
+ </import>
+
+ <service name="vboxService">
+ <port>
+ <xsl:attribute name="binding"><xsl:value-of select="concat('vbox:vbox', $G_bindingSuffix)" /></xsl:attribute>
+ <xsl:attribute name="name"><xsl:value-of select="concat('vbox', 'ServicePort')" /></xsl:attribute>
+ <soap:address location="http://localhost:18083/"/>
+ </port>
+ </service>
+
+ </definitions>
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ class
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="module/class">
+ <!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ enum
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="enum">
+ <!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ const
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<!--
+<xsl:template match="const">
+ <xsl:apply-templates />
+</xsl:template>
+-->
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ desc
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="desc">
+ <!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ note
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="note">
+ <!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ interface
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="interface">
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-wsdl.xsl b/src/VBox/Main/webservice/websrv-wsdl.xsl
new file mode 100644
index 00000000..86146361
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-wsdl.xsl
@@ -0,0 +1,1308 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-wsdl.xsl:
+ XSLT stylesheet that generates vboxweb.wsdl from
+ VirtualBox.xidl. This WSDL file represents our
+ web service API..
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<!--
+ A WSDL document describes a web service using these major elements:
+ Element Defines
+ <types> The data types used by the web service, described in XML Schema
+ syntax.
+ <message> The messages used by the web service. A message is a function call
+ and with it come "parts", which are the parameters.
+ <portType> The operations performed by the web service. A portType can be thought
+ of as a class or, in COM terms, as an interface.
+ <binding> The communication protocols used by the web service.
+
+ The root tag is <definitions>.
+
+ Representing COM interfaces is tricky in WSDL 1.1, which doesn't really have them.
+ WSDL only knows about "port types", which are an abstract representation
+ of a group of functions. So for each "interface", we need to emit
+ a "port type"; in the port type, we declare each "interface method"
+ as one "operation". Each operation in turn consists of at least one
+ message for the method invocation, which contains all the "in" and
+ "inout" arguments. An optional second message for the response contains
+ the return value, if one is present in the IDL (called "_return" to
+ avoid name clashes), together with all the "out" and "inout" arguments.
+ Each of these messages, however, need to be independently declared
+ using the "message" element outside of the "port type" declaration.
+
+ As an example: To create this XPCOM IDL:
+
+ void createMachine (
+ in wstring baseFolder,
+ in wstring name,
+ [retval] out IMachine machine
+ );
+
+ the following exists in the XIDL:
+
+ <interface name="ifname">
+ <method name="createMachine">
+ <param name="baseFolder" type="wstring" dir="in" />
+ <param name="name" type="wstring" dir="in" />
+ <param name="machine" type="IMachine" dir="return" />
+ </method>
+ </interface>
+
+ So, we have two "in" parameters, and one "out" parameter. The
+ operation therefore requires two messages (one for the request,
+ with the two "in" parameters, and one for the result with the
+ return value). With RPC/encoded style, we end up with this:
+
+ <message name="ifname.methodname_Request">
+ <part name="baseFolder" type="xsd:string" />
+ <part name="name" type="xsd:string" />
+ </message>
+ <message name="ifname.methodname_Result">
+ <part name="_return" type="IMachine" />
+ </message>
+ <portType name="ifname">
+ <operation name="methodname"
+ <input message="ifname.methodname_Request" />
+ <output message="ifname.methodname_Result" />
+ </operation>
+ </portType>
+
+ With document/literal style, things get even more verbose, as
+ instead of listing the arguments and return values in the messages,
+ we declare a struct-like complexType in the <types> section
+ instead and then reference that type in the messages.
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ 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"
+ extension-element-prefixes="exsl">
+
+<xsl:param name="G_argDebug" />
+
+<xsl:output
+ method="xml"
+ version="1.0"
+ encoding="utf-8"
+ indent="yes"/>
+
+<xsl:strip-space
+ elements="*" />
+
+<!--**********************************************************************
+ *
+ * global XSLT variables
+ *
+ **********************************************************************-->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-wsdl.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- collect all interfaces with "wsmap='suppress'" in a global variable for
+ quick lookup -->
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+<!-- this marker is used with WSDL document style to mark that a message
+ should have an automatic type that matches a complexType definition;
+ use a string that cannot possibly appear in an XIDL interface name -->
+<xsl:variable name="G_typeIsGlobalRequestElementMarker"
+ select="'&lt;&lt;&lt;&lt;Request'" />
+<xsl:variable name="G_typeIsGlobalResponseElementMarker"
+ select="'&lt;&lt;&lt;&lt;Response'" />
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ Keys for more efficiently looking up of types.
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:key name="G_keyEnumsByName" match="//enum[@name]" use="@name"/>
+<xsl:key name="G_keyInterfacesByName" match="//interface[@name]" use="@name"/>
+
+
+<!--**********************************************************************
+ *
+ * shared helpers
+ *
+ **********************************************************************-->
+
+<!--
+ function emitConvertedType
+ -->
+<xsl:template name="emitConvertedType">
+ <xsl:param name="ifname" />
+ <xsl:param name="methodname" />
+ <xsl:param name="type" />
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('......emitConvertedType: type=&quot;', $type, '&quot;')" /></xsl:call-template>
+ <!-- look up XML Schema type from IDL type from table array in typemap-shared.inc.xsl -->
+ <xsl:variable name="xmltypefield" select="exsl:node-set($G_aSharedTypes)/type[@idlname=$type]/@xmlname" />
+ <xsl:choose>
+ <xsl:when test="$type=$G_typeIsGlobalRequestElementMarker"><xsl:value-of select="concat('vbox:', $ifname, $G_classSeparator, $methodname, $G_requestMessageElementSuffix)" /></xsl:when>
+ <xsl:when test="$type=$G_typeIsGlobalResponseElementMarker"><xsl:value-of select="concat('vbox:', $ifname, $G_classSeparator, $methodname, $G_responseMessageElementSuffix)" /></xsl:when>
+ <!-- if above lookup in table succeeded, use that type -->
+ <xsl:when test="string-length($xmltypefield)"><xsl:value-of select="concat('xsd:', $xmltypefield)" /></xsl:when>
+ <xsl:when test="$type='$unknown'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$type='global'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$type='managed'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$type='explicit'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <!-- enums are easy, these are defined in schema at the top of the wsdl -->
+ <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0"><xsl:value-of select="concat('vbox:', $type)" /></xsl:when>
+ <!-- otherwise test for an interface with this name -->
+ <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0">
+ <!-- the type is one of our own interfaces: then it must have a wsmap attr -->
+ <xsl:variable name="wsmap" select="key('G_keyInterfacesByName', $type)/@wsmap" />
+ <xsl:choose>
+ <xsl:when test="$wsmap='struct'"><xsl:value-of select="concat('vbox:', $type)" /></xsl:when>
+ <xsl:when test="$wsmap='global'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$wsmap='managed'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$wsmap='explicit'"><xsl:value-of select="$G_typeObjectRef" /></xsl:when>
+ <xsl:when test="$wsmap='suppress'">
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitConvertedType: Type &quot;', $type, '&quot; in method &quot;', $ifname, '::', $methodname, '&quot; has wsmap=&quot;suppress&quot; attribute in XIDL. This function should have been suppressed as well.')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitConvertedType: Type &quot;', $type, '&quot; used in method &quot;', $ifname, '::', $methodname, '&quot; has unsupported wsmap attribute value &quot;', $wsmap, '&quot;')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('emitConvertedType: Unknown type &quot;', $type, '&quot; used in method &quot;', $ifname, '::', $methodname, '&quot;.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ function convertTypeAndEmitPartOrElement
+ -->
+<xsl:template name="convertTypeAndEmitPartOrElement">
+ <xsl:param name="ifname" />
+ <xsl:param name="methodname" />
+ <xsl:param name="name" />
+ <xsl:param name="type" />
+ <xsl:param name="safearray" /> <!-- "yes" if XIDL has safearray=yes -->
+ <xsl:param name="elname" /> <!-- "part" or "element" -->
+ <xsl:param name="attrname" /> <!-- attrib of part or element: <part type=...> or <part element=...> or <element type=...> -->
+
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('....convertTypeAndEmitPartOrElement: arg name: ', $name)" /></xsl:call-template>
+ <xsl:choose>
+ <xsl:when test="$safearray='yes' and $type='octet'">
+ <!-- we pass octet arrays as Base64-encoded strings. -->
+ <xsl:element name="{$elname}">
+ <xsl:attribute name="name"><xsl:value-of select="$name" /></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="'xsd:string'" /></xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+
+ <xsl:when test="$safearray='yes'">
+ <xsl:element name="{$elname}"> <!-- <part> or <element> -->
+ <xsl:attribute name="name"><xsl:value-of select="$name" /></xsl:attribute>
+ <xsl:attribute name="minOccurs"><xsl:value-of select="'0'" /></xsl:attribute>
+ <xsl:attribute name="maxOccurs"><xsl:value-of select="'unbounded'" /></xsl:attribute>
+ <xsl:attribute name="{$attrname}">
+ <xsl:call-template name="emitConvertedType">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$methodname" />
+ <xsl:with-param name="type" select="$type" />
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:element name="{$elname}"> <!-- <part> or <element> -->
+ <xsl:attribute name="name"><xsl:value-of select="$name" /></xsl:attribute>
+ <xsl:attribute name="{$attrname}">
+ <xsl:call-template name="emitConvertedType">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="methodname" select="$methodname" />
+ <xsl:with-param name="type" select="$type" />
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ function emitRequestArgs
+ -->
+<xsl:template name="emitRequestArgs">
+ <xsl:param name="_ifname" /> <!-- interface name -->
+ <xsl:param name="_wsmap" /> <!-- interface's wsmap attribute -->
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" />
+ <xsl:param name="_valuetype" /> <!-- optional, for attribute setter messages -->
+ <xsl:param name="_valuesafearray" /> <!-- optional, 'yes' if attribute of setter has safearray=yes -->
+ <xsl:param name="_elname" /> <!-- "part" or "xsd:element" -->
+ <xsl:param name="_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+
+ <!-- first parameter will be object on which method is called, depending on wsmap attribute -->
+ <xsl:choose>
+ <xsl:when test="($_wsmap='managed') or ($_wsmap='explicit')">
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="$G_nameObjectRef" />
+ <xsl:with-param name="type" select="$_wsmap" />
+ <xsl:with-param name="safearray" select="'no'" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:when>
+ </xsl:choose>
+ <!-- now for the real parameters, if any -->
+ <xsl:for-each select="$_params">
+ <!-- emit only parts for "in" parameters -->
+ <xsl:if test="@dir='in'">
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:if test="$_valuetype">
+ <!-- <part>
+ <xsl:attribute name="name">value</xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select='string($_valuetype)' /></xsl:attribute>
+ </part> -->
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="type" select="@type" />
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<!--
+ function emitResultArgs
+ -->
+<xsl:template name="emitResultArgs">
+ <xsl:param name="_ifname" />
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" /> <!-- set of parameter elements -->
+ <xsl:param name="_resulttype" /> <!-- for attribute getter methods only -->
+ <xsl:param name="_resultsafearray" /> <!-- for attribute getter methods only -->
+ <xsl:param name="_elname" /> <!-- "part" or "xsd:element" -->
+ <xsl:param name="_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+
+ <xsl:choose>
+ <xsl:when test="$_resulttype">
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $_ifname, '::', $_methodname, ': ', 'resultmsg for attr of type ', $_resulttype)" /></xsl:call-template>
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="$G_result" />
+ <xsl:with-param name="type" select="$_resulttype" />
+ <xsl:with-param name="safearray" select="$_resultsafearray" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', 'resultmsg for method: ', $_ifname, '::', $_methodname)" /></xsl:call-template>
+ <xsl:for-each select="$_params">
+ <!-- emit only parts for "out" parameters -->
+ <xsl:if test="@dir='out'">
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name"><xsl:value-of select="@name" /></xsl:with-param>
+ <xsl:with-param name="type"><xsl:value-of select="@type" /></xsl:with-param>
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="@dir='return'">
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name"><xsl:value-of select="$G_result" /></xsl:with-param>
+ <xsl:with-param name="type"><xsl:value-of select="@type" /></xsl:with-param>
+ <xsl:with-param name="safearray" select="@safearray" />
+ <xsl:with-param name="elname" select="$_elname" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="$_attrname" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--
+ function emitRequestElements:
+ for "in" parameters
+ -->
+<xsl:template name="emitRequestElements">
+ <xsl:param name="_ifname" /> <!-- interface name -->
+ <xsl:param name="_wsmap" /> <!-- interface's wsmap attribute -->
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" />
+ <xsl:param name="_valuetype" /> <!-- optional, for attribute setter messages -->
+ <xsl:param name="_valuesafearray" /> <!-- optional, 'yes' if attribute of setter has safearray=yes -->
+
+ <xsd:element>
+ <xsl:attribute name="name"><xsl:value-of select="concat($_ifname, $G_classSeparator, $_methodname, $G_requestMessageElementSuffix)" /></xsl:attribute>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsl:call-template name="emitRequestArgs">
+ <xsl:with-param name="_ifname" select="$_ifname" /> <!-- interface name -->
+ <xsl:with-param name="_wsmap" select="$_wsmap" /> <!-- interface's wsmap attribute -->
+ <xsl:with-param name="_methodname" select="$_methodname" />
+ <xsl:with-param name="_params" select="$_params" />
+ <xsl:with-param name="_valuetype" select="$_valuetype" /> <!-- optional, for attribute setter messages -->
+ <xsl:with-param name="_valuesafearray" select="$_valuesafearray" /> <!-- optional, for attribute setter messages -->
+ <xsl:with-param name="_elname" select="'xsd:element'" /> <!-- "part" or "xsd:element" -->
+ <xsl:with-param name="_attrname" select="'type'" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+</xsl:template>
+
+<!--
+ function emitResultElements:
+ for "out" and "return" parameters
+ -->
+<xsl:template name="emitResultElements">
+ <xsl:param name="_ifname" />
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" /> <!-- set of parameter elements -->
+ <xsl:param name="_resulttype" /> <!-- optional, for attribute getter methods only -->
+ <xsl:param name="_resultsafearray" /> <!-- optional, 'yes' if attribute of getter has safearray=yes -->
+
+ <xsd:element>
+ <xsl:attribute name="name"><xsl:value-of select="concat($_ifname, $G_classSeparator, $_methodname, $G_responseMessageElementSuffix)" /></xsl:attribute>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsl:call-template name="emitResultArgs">
+ <xsl:with-param name="_ifname" select="$_ifname" />
+ <xsl:with-param name="_methodname" select="$_methodname" />
+ <xsl:with-param name="_params" select="$_params" /> <!-- set of parameter elements -->
+ <xsl:with-param name="_resulttype" select="$_resulttype" /> <!-- for attribute getter methods only -->
+ <xsl:with-param name="_resultsafearray" select="$_resultsafearray" /> <!-- for attribute getter methods only -->
+ <xsl:with-param name="_elname" select="'xsd:element'" /> <!-- "part" or "xsd:element" -->
+ <xsl:with-param name="_attrname" select="'type'" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+</xsl:template>
+
+<!--
+ function emitGetAttributeElements
+ -->
+<xsl:template name="emitGetAttributeElements">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+ <xsl:param name="attrsafearray" />
+
+ <xsl:variable name="attrGetter"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $ifname, '::', $attrGetter)" /></xsl:call-template>
+ <xsl:call-template name="emitRequestElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ </xsl:call-template>
+ <xsl:call-template name="emitResultElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ <xsl:with-param name="_resultsafearray" select='$attrsafearray' />
+ </xsl:call-template>
+</xsl:template>
+
+<!--
+ function: emitRequestMessage
+ for "in" parameters
+-->
+<xsl:template name="emitRequestMessage">
+ <xsl:param name="_ifname" /> <!-- interface name -->
+ <xsl:param name="_wsmap" /> <!-- interface's wsmap attribute -->
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" />
+ <xsl:param name="_valuetype" /> <!-- optional, for attribute setter messages -->
+
+ <wsdl:message>
+ <xsl:attribute name="name"><xsl:value-of select="concat($_ifname, $G_classSeparator, $_methodname, $G_methodRequest)" /></xsl:attribute>
+
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="'parameters'" />
+ <xsl:with-param name="type" select="$G_typeIsGlobalRequestElementMarker" />
+ <xsl:with-param name="safearray" select="'no'" />
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="'element'" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </wsdl:message>
+</xsl:template>
+
+<!--
+ function: emitResultMessage
+ for "out" and "return" parameters
+-->
+<xsl:template name="emitResultMessage">
+ <xsl:param name="_ifname" />
+ <xsl:param name="_methodname" />
+ <xsl:param name="_params" /> <!-- set of parameter elements -->
+ <xsl:param name="_resulttype" /> <!-- for attribute getter methods only -->
+
+ <wsdl:message>
+ <xsl:attribute name="name"><xsl:copy-of select="$_ifname" /><xsl:value-of select="$G_classSeparator" /><xsl:value-of select="$_methodname" /><xsl:copy-of select="$G_methodResponse" /></xsl:attribute>
+
+ <!-- <xsl:variable name="cOutParams" select="count($_params[@dir='out']) + count($_params[@dir='return'])" /> -->
+ <xsl:call-template name="convertTypeAndEmitPartOrElement">
+ <xsl:with-param name="ifname" select="$_ifname" />
+ <xsl:with-param name="methodname" select="$_methodname" />
+ <xsl:with-param name="name" select="'parameters'" />
+ <xsl:with-param name="type" select="$G_typeIsGlobalResponseElementMarker" />
+ <xsl:with-param name="safearray" select="'no'" />
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ <xsl:with-param name="attrname" select="'element'" /> <!-- attrib of part of element: <part type=...> or <part element=...> or <element type=...> -->
+ </xsl:call-template>
+ </wsdl:message>
+</xsl:template>
+
+<!--
+ function emitGetAttributeMessages:
+-->
+<xsl:template name="emitGetAttributeMessages">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+ <xsl:param name="attrname" />
+ <xsl:param name="attrtype" />
+
+ <xsl:variable name="attrGetter"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $ifname, '::', $attrGetter)" /></xsl:call-template>
+ <xsl:call-template name="emitRequestMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ </xsl:call-template>
+ <xsl:call-template name="emitResultMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ </xsl:call-template>
+</xsl:template>
+
+<!--
+ function emitSetAttributeMessages
+ -->
+<xsl:template name="emitSetAttributeMessages">
+ <xsl:param name="ifname" select="$ifname" />
+ <xsl:param name="wsmap" select="$wsmap" />
+ <xsl:param name="attrname" select="$attrname" />
+ <xsl:param name="attrtype" select="$attrtype" />
+
+ <xsl:variable name="attrSetter"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $ifname, '::', $attrSetter)" /></xsl:call-template>
+ <xsl:call-template name="emitRequestMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ <xsl:with-param name="_valuetype" select="$attrtype" />
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ </xsl:call-template>
+ <xsl:call-template name="emitResultMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." /> <!-- empty set -->
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ </xsl:call-template>
+</xsl:template>
+
+<!--
+ function emitInOutOperation:
+ referencing the messages that must have been emitted previously
+-->
+<xsl:template name="emitInOutOperation">
+ <xsl:param name="_ifname" /> <!-- interface name -->
+ <xsl:param name="_methodname" /> <!-- method name -->
+ <xsl:param name="_params" />
+ <xsl:param name="_resulttype" /> <!-- for attribute getter methods only -->
+ <xsl:param name="_fSoap" />
+
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('....emitInOutOperation ', $_ifname, '::', $_methodname)" /></xsl:call-template>
+
+ <wsdl:operation>
+ <xsl:attribute name="name">
+ <xsl:value-of select="concat($_ifname, '_', $_methodname)" />
+ </xsl:attribute>
+ <xsl:if test="$_fSoap">
+ <soap:operation>
+ <!-- VMware has an empty attribute like this as well -->
+ <xsl:attribute name="soapAction"><xsl:value-of select="''" /></xsl:attribute>
+ <xsl:attribute name="style"><xsl:value-of select="$G_basefmt" /></xsl:attribute>
+ </soap:operation>
+ </xsl:if>
+ <wsdl:input>
+ <xsl:choose>
+ <xsl:when test="$_fSoap">
+ <soap:body>
+ <xsl:attribute name="use"><xsl:value-of select="$G_parmfmt" /></xsl:attribute>
+ <!-- avoid jax-ws warning: <xsl:attribute name="namespace"><xsl:value-of select="concat($G_targetNamespace, $G_targetNamespaceSeparator)" /></xsl:attribute>-->
+ </soap:body>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="message">vbox:<xsl:copy-of select="$_ifname" /><xsl:value-of select="$G_classSeparator" /><xsl:value-of select="$_methodname" /><xsl:copy-of select="$G_methodRequest" /></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </wsdl:input>
+ <xsl:choose>
+ <xsl:when test="$_resulttype">
+ <wsdl:output>
+ <xsl:choose>
+ <xsl:when test="$_fSoap">
+ <soap:body>
+ <xsl:attribute name="use"><xsl:value-of select="$G_parmfmt" /></xsl:attribute>
+ <!-- avoid jax-ws warning: <xsl:attribute name="namespace"><xsl:value-of select="concat($G_targetNamespace, $G_targetNamespaceSeparator)" /></xsl:attribute> -->
+ </soap:body>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="message">vbox:<xsl:copy-of select="$_ifname" /><xsl:value-of select="$G_classSeparator" /><xsl:value-of select="$_methodname" /><xsl:copy-of select="$G_methodResponse" /></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </wsdl:output>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- <xsl:if test="count($_params[@dir='out'] | $_params[@dir='return']) > 0"> -->
+ <wsdl:output>
+ <xsl:choose>
+ <xsl:when test="$_fSoap">
+ <soap:body>
+ <xsl:attribute name="use"><xsl:value-of select="$G_parmfmt" /></xsl:attribute>
+ <!-- avoid jax-ws warning: <xsl:attribute name="namespace"><xsl:value-of select="concat($G_targetNamespace, $G_targetNamespaceSeparator)" /></xsl:attribute> -->
+ </soap:body>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="message">vbox:<xsl:copy-of select="$_ifname" /><xsl:value-of select="$G_classSeparator" /><xsl:value-of select="$_methodname" /><xsl:copy-of select="$G_methodResponse" /></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </wsdl:output>
+ <!-- </xsl:if> -->
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="not($_fSoap)">
+ <wsdl:fault name="InvalidObjectFault" message="vbox:InvalidObjectFaultMsg" />
+ <wsdl:fault name="RuntimeFault" message="vbox:RuntimeFaultMsg" />
+ </xsl:when>
+ <xsl:otherwise>
+ <wsdl:fault name="InvalidObjectFault">
+ <soap:fault name="InvalidObjectFault">
+ <xsl:attribute name="use"><xsl:value-of select="$G_parmfmt" /></xsl:attribute>
+ </soap:fault>
+ </wsdl:fault>
+ <wsdl:fault name="RuntimeFault">
+ <soap:fault name="RuntimeFault">
+ <xsl:attribute name="use"><xsl:value-of select="$G_parmfmt" /></xsl:attribute>
+ </soap:fault>
+ </wsdl:fault>
+ </xsl:otherwise>
+ </xsl:choose>
+ </wsdl:operation>
+</xsl:template>
+
+<!--
+ function verifyInterface
+-->
+<xsl:template name="verifyInterface">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+
+ <xsl:choose>
+ <xsl:when test="$wsmap='global'" />
+ <xsl:when test="$wsmap='managed'" />
+ <xsl:when test="$wsmap='explicit'" />
+ <xsl:when test="$wsmap='struct'" />
+ <xsl:when test="$wsmap='suppress'" />
+ <xsl:otherwise>
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat(local-name(), ' template: Interface &quot;', $ifname, '&quot; has invalid wsmap attribute &quot;', $wsmap, '&quot; in XIDL.')" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- now make sure we have each interface only once -->
+ <xsl:if test="(count(//library/interface[@name=$ifname]) > 1)">
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat(local-name(), ' template: There is more than one interface with a name=&quot;', $ifname, '&quot; attribute.')" />
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<!--
+ function emitMessagesForInterface
+-->
+<xsl:template name="emitMessagesForInterface">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+
+ <!-- 1) outside the portType, here come the in/out methods for all the "operations" we declare below;
+ a) for attributes (get/set methods)
+ b) for "real" methods
+ -->
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('************* messages for interface &quot;', $ifname, '&quot;')" /></xsl:call-template>
+ <!-- a) attributes first -->
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="attrtype"><xsl:value-of select="@type" /></xsl:variable>
+ <xsl:variable name="attrreadonly"><xsl:value-of select="@readonly" /></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('messages for ', $ifname, '::', $attrname, ': attribute of type &quot;', $attrtype, '&quot;, readonly: ', $attrreadonly)" /></xsl:call-template>
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:comment> readonly attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:comment> read/write attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!-- aa) get method: emit request and result -->
+ <xsl:call-template name="emitGetAttributeMessages">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ </xsl:call-template>
+ <!-- bb) emit a set method if the attribute is read/write -->
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:call-template name="emitSetAttributeMessages">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each> <!-- select="attribute" -->
+ <!-- b) "real" methods after the attributes -->
+ <xsl:for-each select="method">
+ <xsl:variable name="methodname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('messages for ', $ifname, '::', $methodname, ': method')" /></xsl:call-template>
+ <xsl:comment> method <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$methodname" /> </xsl:comment>
+ <!-- skip this method if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test=" (param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr'])" >
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it has parameters with suppressed types')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- always emit a request message -->
+ <xsl:call-template name="emitRequestMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$methodname" />
+ <xsl:with-param name="_params" select="param" />
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ </xsl:call-template>
+ <!-- emit a second "result" message only if the method has "out" arguments or a return value -->
+ <!-- <xsl:if test="(count(param[@dir='out'] | param[@dir='return']) > 0)"> -->
+ <xsl:call-template name="emitResultMessage">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="@name" />
+ <xsl:with-param name="_params" select="param" />
+ <xsl:with-param name="elname" select="'wsdl:part'" /> <!-- "part" or "element" -->
+ </xsl:call-template>
+ <!-- </xsl:if> -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+</xsl:template>
+
+<!--
+ function emitOperationsForInterface
+ -->
+<xsl:template name="emitOperationsInPortTypeForInterface">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+
+ <!-- a) again, first for the attributes whose messages we produced above -->
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('************* portType for interface &quot;', $ifname, '&quot;')" /></xsl:call-template>
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname" select="@name" />
+ <xsl:variable name="attrtype" select="@type" />
+ <xsl:variable name="attrreadonly" select="@readonly" />
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('operations for ', $ifname, '::', $attrname, ': attribute of type &quot;', $attrtype, '&quot;, readonly: ', $attrreadonly)" /></xsl:call-template>
+ <xsl:choose>
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="attrGetter"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $G_attributeGetPrefix, $attrname)" /></xsl:call-template>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." />
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ </xsl:call-template>
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:variable name="attrSetter"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $attrSetter)" /></xsl:call-template>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." />
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <!-- b) then for the "real" methods whose messages we produced above -->
+ <xsl:for-each select="method">
+ <xsl:variable name="methodname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('operations for ', $ifname, '::', $methodname, ': method')" /></xsl:call-template>
+ <!-- skip this method if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test=" (param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr'])" >
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it has parameters with suppressed types')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$methodname" />
+ <xsl:with-param name="_params" select="param" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+</xsl:template>
+
+<!--
+ function emitOperationsInBindingForInterface
+ -->
+<xsl:template name="emitOperationsInBindingForInterface">
+ <xsl:param name="ifname" />
+ <xsl:param name="wsmap" />
+
+ <!-- a) again, first for the attributes whose messages we produced above -->
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname" select="@name" />
+ <xsl:variable name="attrtype" select="@type" />
+ <xsl:variable name="attrreadonly" select="@readonly" />
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="attrGetter"><xsl:call-template name="makeGetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrGetter" />
+ <xsl:with-param name="_params" select="/.." />
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ <xsl:with-param name="_fSoap" select="1" />
+ </xsl:call-template>
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:variable name="attrSetter"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." />
+ <xsl:with-param name="_resulttype" select='$attrtype' />
+ <xsl:with-param name="_fSoap" select="1" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <!-- b) then for the "real" methods whose messages we produced above -->
+ <xsl:for-each select="method">
+ <xsl:variable name="methodname"><xsl:value-of select="@name" /></xsl:variable>
+ <!-- skip this method if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test=" (param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr'])" >
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it has parameters with suppressed types')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="emitInOutOperation">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$methodname" />
+ <xsl:with-param name="_params" select="param" />
+ <xsl:with-param name="_fSoap" select="1" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+</xsl:template>
+
+<!--**********************************************************************
+ *
+ * matches
+ *
+ **********************************************************************-->
+
+<!--
+ template for "idl" match; this emits the header of the target file
+ and recurses into the libraries with interfaces (which are matched below)
+ -->
+<xsl:template match="/idl">
+ <xsl:comment>
+ DO NOT EDIT! This is a generated file.
+ Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML)
+ Generator: src/VBox/Main/webservice/websrv-wsdl.xsl
+</xsl:comment>
+
+ <xsl:apply-templates />
+
+</xsl:template>
+
+<!--
+ template for "if" match: ignore all ifs except those for wsdl
+ -->
+<xsl:template match="if">
+ <xsl:if test="@target='wsdl'">
+ <xsl:apply-templates/>
+ </xsl:if>
+</xsl:template>
+
+<!--
+ template for "cpp": ignore
+ -->
+<xsl:template match="cpp">
+<!-- ignore this -->
+</xsl:template>
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ class
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="module/class">
+<!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ enum
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="enum">
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ desc
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="desc">
+<!-- swallow -->
+</xsl:template>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ note
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="note">
+ <xsl:apply-templates />
+</xsl:template>
+
+<!--
+ "library" match: we use this to emit most of the WSDL <types> section.
+ With WSDL "document" style, this requires us to go through all interfaces
+ and emit complexTypes for all method arguments and return values.
+-->
+<xsl:template match="library">
+ <wsdl:definitions
+ name="VirtualBox"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+ <xsl:attribute name="targetNamespace"><xsl:value-of select="$G_targetNamespace" /></xsl:attribute>
+ <!-- at top of WSDL file, dump a <types> section with user-defined types -->
+ <xsl:comment>
+ ******************************************************
+ *
+ * WSDL type definitions in XML Schema
+ *
+ ******************************************************
+</xsl:comment>
+ <wsdl:types>
+ <xsd:schema>
+ <xsl:attribute name="targetNamespace"><xsl:value-of select='$G_targetNamespace' /></xsl:attribute>
+
+ <!-- type-define all enums -->
+ <xsl:comment>
+ ******************************************************
+ * enumerations
+ ******************************************************
+</xsl:comment>
+ <xsl:for-each select="//enum">
+ <xsl:comment> enum: <xsl:value-of select="@name" /> -
+ <xsl:for-each select="const">
+ <xsl:value-of select="@name" />: <xsl:value-of select="@value" /> -
+ </xsl:for-each>
+</xsl:comment>
+ <xsd:simpleType>
+ <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
+ <xsd:restriction base="xsd:string">
+ <!-- XML Schema does not seem to have a C-like mapping between identifiers and numbers;
+ instead, it treats enumerations like strings that can have only specific values. -->
+ <xsl:for-each select="const">
+ <xsd:enumeration>
+ <xsl:attribute name="value"><xsl:value-of select="@name" /></xsl:attribute>
+ </xsd:enumeration>
+ </xsl:for-each>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsl:for-each>
+
+ <!-- type-define all interfaces that have wsmap=struct as structs (complexTypes) -->
+ <xsl:comment>
+ ******************************************************
+ * structs
+ ******************************************************
+</xsl:comment>
+ <xsl:for-each select="//interface[@wsmap='struct']">
+ <xsl:comment> interface <xsl:value-of select="@name" /> as struct: </xsl:comment>
+ <xsd:complexType>
+ <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
+ <xsd:sequence>
+ <xsl:for-each select="attribute">
+ <xsd:element>
+ <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
+ <xsl:attribute name="type">
+ <xsl:call-template name="emitConvertedType">
+ <xsl:with-param name="type" select="@type" />
+ </xsl:call-template>
+ </xsl:attribute>
+ </xsd:element>
+ </xsl:for-each>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsl:for-each>
+
+ <!-- for WSDL 'document' style, we need to emit elements since we can't
+ refer to types in message parts as with RPC style -->
+ <xsl:if test="$G_basefmt='document'">
+ <xsl:comment>
+ ******************************************************
+ * elements for message arguments (parts); generated for WSDL 'document' style
+ ******************************************************
+</xsl:comment>
+
+ <xsl:for-each select="//interface">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+
+ <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") )'>
+ <xsl:comment>Interface <xsl:copy-of select="$ifname" /></xsl:comment>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('************* types: elements for interface &quot;', $ifname, '&quot;')" /></xsl:call-template>
+ <!-- a) attributes first -->
+ <xsl:for-each select="attribute">
+ <xsl:variable name="attrname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="attrtype"><xsl:value-of select="@type" /></xsl:variable>
+ <xsl:variable name="attrsafearray"><xsl:value-of select="@safearray" /></xsl:variable>
+ <xsl:variable name="attrreadonly"><xsl:value-of select="@readonly" /></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('elements for ', $ifname, '::', $attrname, ': attribute of type &quot;', $attrtype, '&quot;, readonly: ', $attrreadonly)" /></xsl:call-template>
+ <!-- skip this attribute if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test="( $attrtype=($G_setSuppressedInterfaces/@name) )">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrtype, ' for it is of a suppressed type')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping attribute ', $attrname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="@readonly='yes'">
+ <xsl:comment> readonly attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:comment> read/write attribute <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$attrname" /> </xsl:comment>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!-- aa) get method: emit request and result -->
+ <xsl:call-template name="emitGetAttributeElements">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ <xsl:with-param name="attrname" select="$attrname" />
+ <xsl:with-param name="attrtype" select="$attrtype" />
+ <xsl:with-param name="attrsafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <!-- bb) emit a set method if the attribute is read/write -->
+ <xsl:if test="not($attrreadonly='yes')">
+ <xsl:variable name="attrSetter"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('..', $ifname, '::', $attrSetter)" /></xsl:call-template>
+ <xsl:call-template name="emitRequestElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." />
+ <xsl:with-param name="_valuetype" select="$attrtype" />
+ <xsl:with-param name="_valuesafearray" select="$attrsafearray" />
+ </xsl:call-template>
+ <xsl:call-template name="emitResultElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_methodname" select="$attrSetter" />
+ <xsl:with-param name="_params" select="/.." />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each> <!-- select="attribute" -->
+ <!-- b) "real" methods after the attributes -->
+ <xsl:for-each select="method">
+ <xsl:variable name="methodname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:call-template name="debugMsg"><xsl:with-param name="msg" select="concat('messages for ', $ifname, '::', $methodname, ': method')" /></xsl:call-template>
+ <xsl:comment> method <xsl:copy-of select="$ifname" />::<xsl:copy-of select="$methodname" /> </xsl:comment>
+ <!-- skip this method if it has parameters of a type that has wsmap="suppress" -->
+ <xsl:choose>
+ <xsl:when test=" (param[@type=($G_setSuppressedInterfaces/@name)])
+ or (param[@mod='ptr'])" >
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it has parameters with suppressed types')" /></xsl:comment>
+ </xsl:when>
+ <xsl:when test="@wsmap = 'suppress'">
+ <xsl:comment><xsl:value-of select="concat('skipping method ', $methodname, ' for it is suppressed')" /></xsl:comment>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- always emit a request message -->
+ <xsl:call-template name="emitRequestElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$methodname" />
+ <xsl:with-param name="_params" select="param" />
+ </xsl:call-template>
+ <!-- emit a second "result" message only if the method has "out" arguments or a return value -->
+ <!-- <xsl:if test="(count(param[@dir='out'] | param[@dir='return']) > 0)"> -->
+ <xsl:call-template name="emitResultElements">
+ <xsl:with-param name="_ifname" select="$ifname" />
+ <xsl:with-param name="_wsmap" select="$wsmap" />
+ <xsl:with-param name="_methodname" select="$methodname" />
+ <xsl:with-param name="_params" select="param" />
+ </xsl:call-template>
+ <!-- </xsl:if> -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:if> <!-- <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") )'> -->
+ </xsl:for-each>
+
+ </xsl:if> <!-- <xsl:if test="$G_basefmt='document'"> -->
+
+ <xsl:comment>
+ ******************************************************
+ * faults
+ ******************************************************
+</xsl:comment>
+
+ <xsd:element name="InvalidObjectFault">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="badObjectID">
+ <xsl:attribute name="type">
+ <xsl:value-of select="$G_typeObjectRef" />
+ </xsl:attribute>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="RuntimeFault">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="resultCode" type="xsd:int" />
+ <xsd:element name="returnval">
+ <xsl:attribute name="type">
+ <xsl:value-of select="$G_typeObjectRef" />
+ </xsl:attribute>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- done! -->
+ </xsd:schema>
+
+
+ </wsdl:types>
+
+ <wsdl:message name="InvalidObjectFaultMsg">
+ <wsdl:part name="fault" element="vbox:InvalidObjectFault" />
+ </wsdl:message>
+ <wsdl:message name="RuntimeFaultMsg">
+ <wsdl:part name="fault" element="vbox:RuntimeFault" />
+ </wsdl:message>
+
+ <xsl:comment>
+ ******************************************************
+ *
+ * messages for all interfaces
+ *
+ ******************************************************
+</xsl:comment>
+
+ <xsl:for-each select="//interface">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+
+ <xsl:call-template name="verifyInterface">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ </xsl:call-template>
+
+ <xsl:comment>
+ *************************************
+ messages for interface <xsl:copy-of select="$ifname" />
+ *************************************
+ </xsl:comment>
+
+ <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") )'>
+ <xsl:call-template name="emitMessagesForInterface">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:comment>
+ ******************************************************
+ *
+ * one portType for all interfaces
+ *
+ ******************************************************
+ </xsl:comment>
+
+ <wsdl:portType>
+ <xsl:attribute name="name"><xsl:copy-of select="'vbox'" /><xsl:value-of select="$G_portTypeSuffix" /></xsl:attribute>
+
+ <xsl:for-each select="//interface">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+
+ <xsl:comment>
+ *************************************
+ operations in portType for interface <xsl:copy-of select="$ifname" />
+ *************************************
+ </xsl:comment>
+
+ <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") )'>
+ <xsl:call-template name="emitOperationsInPortTypeForInterface">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </wsdl:portType>
+
+ <xsl:comment>
+ ******************************************************
+ *
+ * one binding for all interfaces
+ *
+ ******************************************************
+ </xsl:comment>
+
+ <wsdl:binding>
+ <xsl:attribute name="name"><xsl:value-of select="concat('vbox', $G_bindingSuffix)" /></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="concat('vbox:vbox', $G_portTypeSuffix)" /></xsl:attribute>
+
+ <soap:binding>
+ <xsl:attribute name="style"><xsl:value-of select="$G_basefmt" /></xsl:attribute>
+ <xsl:attribute name="transport">http://schemas.xmlsoap.org/soap/http</xsl:attribute>
+ </soap:binding>
+
+ <xsl:for-each select="//interface">
+ <xsl:variable name="ifname"><xsl:value-of select="@name" /></xsl:variable>
+ <xsl:variable name="wsmap"><xsl:value-of select="@wsmap" /></xsl:variable>
+
+ <xsl:comment>
+ *************************************
+ operations in portType for interface <xsl:copy-of select="$ifname" />
+ *************************************
+ </xsl:comment>
+
+ <xsl:if test='not( ($wsmap="suppress") or ($wsmap="struct") )'>
+ <xsl:call-template name="emitOperationsInBindingForInterface">
+ <xsl:with-param name="ifname" select="$ifname" />
+ <xsl:with-param name="wsmap" select="$wsmap" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
+ </wsdl:binding>
+
+ </wsdl:definitions>
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl b/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl
new file mode 100644
index 00000000..4303e537
--- /dev/null
+++ b/src/VBox/Main/webservice/websrv-wsdl2gsoapH.xsl
@@ -0,0 +1,308 @@
+<?xml version="1.0"?>
+
+<!--
+ websrv-gsoapH.xsl:
+ XSLT stylesheet that generates a gSOAP pseudo-header
+ file from VirtualBox.xidl. Such a pseudo-header files
+ can be fed into gSOAP's soapcpp2 to create web service
+ client headers and server stubs.
+ See webservice/Makefile.kmk for an overview of all the things
+ generated for the webservice.
+-->
+<!--
+ Copyright (C) 2006-2022 Oracle and/or its affiliates.
+
+ This file is part of VirtualBox base platform packages, as
+ available from https://www.virtualbox.org.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation, in version 3 of the
+ License.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses>.
+
+ SPDX-License-Identifier: GPL-3.0-only
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ 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"
+ extension-element-prefixes="exsl"
+ >
+
+ <xsl:param name="G_argDebug" />
+
+ <xsl:output method="text"/>
+
+ <xsl:strip-space elements="*"/>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ global XSLT variables
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:variable name="G_xsltFilename" select="'websrv-wsdl2gsoapH.xsl'" />
+
+<xsl:include href="../idl/typemap-shared.inc.xsl" />
+
+<!-- collect all interfaces with "wsmap='suppress'" in a global variable for
+ quick lookup -->
+<xsl:variable name="G_setSuppressedInterfaces"
+ select="//interface[@wsmap='suppress']" />
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ Keys for more efficiently looking up of stuff
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:key name="G_keyMessagesByName" match="//wsdl:message[@name]" use="@name"/>
+<xsl:key name="G_keySimpleTypesByName" match="//xsd:simpleType[@name]" use="@name"/>
+<xsl:key name="G_keyComplexTypesByName" match="//xsd:complexType[@name]" use="@name"/>
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - -
+ root match
+ - - - - - - - - - - - - - - - - - - - - - - -->
+
+<xsl:template match="/wsdl:definitions">
+ <xsl:text><![CDATA[
+/* DO NOT EDIT! This is a generated file.
+ * Generated from: vboxweb.wsdl (generated WSDL file)
+ * Generator: src/VBox/Main/webservice/websrv-gsoapH.xsl
+ *
+ * Note: This is not a real C/C++ header file. Instead, gSOAP uses files like this
+ * one -- with a pseudo-C-header syntax -- to describe a web service API.
+ */
+
+// STL vector containers
+#import "stlvector.h"
+
+]]></xsl:text>
+
+ <xsl:value-of select="concat('//gsoap vbox schema namespace: ', $G_targetNamespace)" />
+ <xsl:value-of select="concat('//gsoap vbox schema form: unqualified', '')" />
+
+ <xsl:text>
+/****************************************************************************
+ *
+ * declarations
+ *
+ ****************************************************************************/
+
+// forward declarations
+class _vbox__InvalidObjectFault;
+class _vbox__RuntimeFault;
+
+struct SOAP_ENV__Detail
+{
+ _vbox__InvalidObjectFault *vbox__InvalidObjectFault;
+ _vbox__RuntimeFault *vbox__RuntimeFault;
+ int __type;
+ void *fault;
+ _XML __any;
+};
+</xsl:text>
+
+ <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template name="convertSequence">
+ <xsl:param name="xmltype" />
+ <xsl:param name="ctype" />
+
+ <xsl:value-of select="concat('class ', $ctype, $G_sNewLine)" />
+ <xsl:text>{
+ public:
+</xsl:text>
+ <xsl:for-each select="xsd:element">
+ <xsl:variable name="typefield" select="@type" />
+ <xsl:variable name="xmltypefield" select="substring($typefield, 5)" /><!-- remove "xsd:" prefix-->
+ <xsl:variable name="withoutvboxtypefield" select="substring($typefield, 6)" /><!-- remove "vbox:" prefix-->
+ <xsl:variable name="ctypefield" select="exsl:node-set($G_aSharedTypes)/type[@xmlname=$xmltypefield]/@cname" />
+ <xsl:text> </xsl:text>
+ <xsl:choose>
+ <xsl:when test="$ctypefield">
+ <!-- array or simple type: depends on whether maxOccurs="unbounded" is in WSDL -->
+ <xsl:choose>
+ <xsl:when test="@maxOccurs='unbounded'">
+ <xsl:value-of select="concat('std::vector&lt;', $ctypefield, '&gt;')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$ctypefield" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <!-- is there an enum of this type? (look up in simple types) -->
+ <xsl:when test="count(key('G_keySimpleTypesByName', $withoutvboxtypefield)) > 0">
+ <xsl:variable name="enumname">
+ <xsl:value-of select="concat('enum vbox__', $withoutvboxtypefield)" />
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="@maxOccurs='unbounded'">
+ <xsl:value-of select="concat('std::vector&lt;', $enumname, '&gt;')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$enumname" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <!-- is this one of the vbox types? (look up in complex types) -->
+ <xsl:when test="count(key('G_keyComplexTypesByName', $withoutvboxtypefield)) > 0">
+ <!-- array or simple type: depends on whether maxOccurs="unbounded" is in WSDL -->
+ <xsl:choose>
+ <xsl:when test="@maxOccurs='unbounded'">
+ <xsl:value-of select="concat('std::vector&lt;vbox__', $withoutvboxtypefield, '*&gt;')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('vbox__', $withoutvboxtypefield, '*')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('std::string', '')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:variable name="underscoredname">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="concat(' ', $underscoredname, ' 1;', $G_sNewLine)" />
+ </xsl:for-each>
+ <xsl:text> struct soap *soap;
+};
+</xsl:text>
+<xsl:call-template name="xsltprocNewlineOutputHack"/>
+
+</xsl:template>
+
+<xsl:template match="wsdl:types/xsd:schema">
+
+ <!-- enums are represented as simple types -->
+ <xsl:for-each select="xsd:simpleType">
+ <xsl:variable name="ctype" select="concat('vbox__', @name)" />
+ <xsl:for-each select="xsd:restriction">
+ <xsl:value-of select="concat('enum ', $ctype)" />
+ <xsl:text>
+{
+</xsl:text>
+ <xsl:for-each select="xsd:enumeration">
+ <xsl:variable name="underscoredname">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="@value" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="concat(' ', $ctype, '__', $underscoredname)" />
+ <xsl:if test = "not(position()=last())" >
+ <xsl:text >,</xsl:text>
+ </xsl:if>
+ <xsl:text>
+</xsl:text>
+ </xsl:for-each>
+ <xsl:text>};
+
+</xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+
+ <!-- structs and arrays are represented as complex types -->
+ <xsl:for-each select="xsd:complexType">
+ <xsl:variable name="xmltype" select="@name" />
+ <xsl:variable name="ctype" select="concat('vbox__', $xmltype)" />
+ <xsl:for-each select="xsd:sequence">
+ <xsl:call-template name="convertSequence">
+ <xsl:with-param name="xmltype" select="$xmltype" />
+ <xsl:with-param name="ctype" select="$ctype" />
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:for-each>
+
+ <!-- individual message elements are represented with xsd:element -> xsd:complexType -> xsdSequence -->
+ <xsl:for-each select="xsd:element">
+ <xsl:variable name="xmltype" select="@name" />
+ <xsl:variable name="underscoredname">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="$xmltype" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="ctype" select="concat('_vbox__', $underscoredname)" />
+ <xsl:for-each select="xsd:complexType">
+ <xsl:for-each select="xsd:sequence">
+ <xsl:call-template name="convertSequence">
+ <xsl:with-param name="xmltype" select="$xmltype" />
+ <xsl:with-param name="ctype" select="$ctype" />
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:for-each>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="wsdl:portType">
+
+ <xsl:value-of select="concat('//gsoap vbox service name: vbox', $G_bindingSuffix, $G_sNewLine)" />
+ <xsl:value-of select="concat('//gsoap vbox service type: vbox', $G_portTypeSuffix, $G_sNewLine)" />
+ <xsl:value-of select="concat('//gsoap vbox service namespace: ', $G_targetNamespace, $G_targetNamespaceSeparator, $G_sNewLine)" />
+ <xsl:value-of select="concat('//gsoap vbox service transport: ', 'http://schemas.xmlsoap.org/soap/http', $G_sNewLine)" />
+
+ <xsl:for-each select="wsdl:operation">
+ <xsl:variable name="methodname" select="@name" />
+ <xsl:variable name="cmethodname">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="$methodname" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="requestmsg" select="concat($methodname, $G_methodRequest)" />
+ <xsl:variable name="responsemsg" select="concat($methodname, $G_methodResponse)" />
+
+ <xsl:value-of select="concat($G_sNewLine, '//gsoap vbox service method-style: ', $cmethodname, ' ', $G_basefmt)" />
+ <xsl:value-of select="concat($G_sNewLine, '//gsoap vbox service method-encoding: ', $cmethodname, ' ', $G_parmfmt)" />
+ <xsl:value-of select="concat($G_sNewLine, '//gsoap vbox service method-action: ', $cmethodname, ' &quot;&quot;')" />
+ <xsl:value-of select="concat($G_sNewLine, '//gsoap vbox service method-fault: ', $cmethodname, ' vbox__InvalidObjectFault')" />
+ <xsl:value-of select="concat($G_sNewLine, '//gsoap vbox service method-fault: ', $cmethodname, ' vbox__RuntimeFault')" />
+ <xsl:value-of select="concat($G_sNewLine, 'int __vbox__', $cmethodname, '(', $G_sNewLine)" />
+
+ <!-- request element -->
+ <xsl:variable name="reqtype" select="key('G_keyMessagesByName', $requestmsg)/wsdl:part/@element" />
+ <xsl:if test="not($reqtype)">
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('wsdl:portType match: Cannot find message with &quot;name&quot;=&quot;', $requestmsg, '&quot;.')" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:variable name="creqtype">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="substring($reqtype, 6)" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="concat(' _vbox__', $creqtype, '* vbox__', $creqtype, ',', $G_sNewLine)"/>
+ <!-- response element -->
+ <xsl:variable name="resptype" select="key('G_keyMessagesByName', $responsemsg)/wsdl:part/@element" />
+ <xsl:if test="not($resptype)">
+ <xsl:call-template name="fatalError">
+ <xsl:with-param name="msg" select="concat('wsdl:portType match: Cannot find message with &quot;name&quot;=&quot;', $responsemsg, '&quot;.')" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:variable name="cresptype">
+ <xsl:call-template name="escapeUnderscores">
+ <xsl:with-param name="string" select="substring($resptype, 6)" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="concat(' _vbox__', $cresptype, '* vbox__', $cresptype, $G_sNewLine)"/>
+
+ <xsl:text>);</xsl:text>
+ <xsl:call-template name="xsltprocNewlineOutputHack"/>
+
+ </xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/VBox/Main/webservice/webtest.cpp b/src/VBox/Main/webservice/webtest.cpp
new file mode 100644
index 00000000..166ebcce
--- /dev/null
+++ b/src/VBox/Main/webservice/webtest.cpp
@@ -0,0 +1,572 @@
+/* $Id: webtest.cpp $ */
+/** @file
+ * webtest.cpp:
+ * demo webservice client in C++. This mimics some of the
+ * functionality of VBoxManage for testing purposes.
+ */
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+// gSOAP headers (must come after vbox includes because it checks for conflicting defs)
+#include "soapStub.h"
+
+// include generated namespaces table
+#include "vboxwebsrv.nsmap"
+
+#include <iostream>
+#include <iprt/sanitized/sstream>
+#include <iprt/sanitized/string>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/errcore.h>
+
+
+static void usage(int exitcode)
+{
+ std::cout <<
+ "webtest: VirtualBox webservice testcase.\n"
+ "\nUsage: webtest [options] [command]...\n"
+ "\nSupported options:\n"
+ " -h: print this help message and exit.\n"
+ " -c URL: specify the webservice server URL (default http://localhost:18083/).\n"
+ "\nSupported commands:\n"
+ " - IWebsessionManager:\n"
+ " - webtest logon <user> <pass>: IWebsessionManager::logon().\n"
+ " - webtest getsession <vboxref>: IWebsessionManager::getSessionObject().\n"
+ " - webtest logoff <vboxref>: IWebsessionManager::logoff().\n"
+ " - IVirtualBox:\n"
+ " - webtest version <vboxref>: IVirtualBox::getVersion().\n"
+ " - webtest gethost <vboxref>: IVirtualBox::getHost().\n"
+ " - webtest getpc <vboxref>: IVirtualBox::getPerformanceCollector().\n"
+ " - webtest getmachines <vboxref>: IVirtualBox::getMachines().\n"
+ " - webtest createmachine <vboxref> <settingsPath> <name>: IVirtualBox::createMachine().\n"
+ " - webtest registermachine <vboxref> <machineref>: IVirtualBox::registerMachine().\n"
+ " - IHost:\n"
+ " - webtest getdvddrives <hostref>: IHost::getDVDDrives.\n"
+ " - IHostDVDDrive:\n"
+ " - webtest getdvdname <dvdref>: IHostDVDDrive::getname.\n"
+ " - IMachine:\n"
+ " - webtest getname <machineref>: IMachine::getName().\n"
+ " - webtest getid <machineref>: IMachine::getId().\n"
+ " - webtest getostype <machineref>: IMachine::getGuestOSType().\n"
+ " - webtest savesettings <machineref>: IMachine::saveSettings().\n"
+ " - IPerformanceCollector:\n"
+ " - webtest setupmetrics <pcref>: IPerformanceCollector::setupMetrics()\n"
+ " - webtest querymetricsdata <pcref>: IPerformanceCollector::QueryMetricsData()\n"
+ " - IVirtualBoxErrorInfo:\n"
+ " - webtest errorinfo <eiref>: various IVirtualBoxErrorInfo getters\n"
+ " - All managed object references:\n"
+ " - webtest getif <ref>: report interface of object.\n"
+ " - webtest release <ref>: IUnknown::Release().\n";
+ exit(exitcode);
+}
+
+/**
+ *
+ * @param argc
+ * @param argv[]
+ * @return
+ */
+int main(int argc, char* argv[])
+{
+ bool fSSL = false;
+ const char *pcszArgEndpoint = "http://localhost:18083/";
+
+ /* SSL callbacks drag in IPRT sem/thread use, so make sure it is ready. */
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+
+ int ap;
+ for (ap = 1; ap < argc; ap++)
+ {
+ if (argv[ap][0] == '-')
+ {
+ if (!strcmp(argv[ap], "-h"))
+ usage(0);
+ else if (!strcmp(argv[ap], "-c"))
+ {
+ ap++;
+ if (ap >= argc)
+ usage(1);
+ pcszArgEndpoint = argv[ap];
+ fSSL = !strncmp(pcszArgEndpoint, "https://", 8);
+ }
+ else
+ usage(1);
+ }
+ else
+ break;
+ }
+
+ if (argc < 1 + ap)
+ usage(1);
+
+#ifdef WITH_OPENSSL
+ if (fSSL)
+ soap_ssl_init();
+#endif /* WITH_OPENSSL */
+
+ struct soap soap; // gSOAP runtime environment
+ soap_init(&soap); // initialize runtime environment (only once)
+#ifdef WITH_OPENSSL
+ // Use SOAP_SSL_NO_AUTHENTICATION here to accept broken server configs.
+ // In a real world setup please use at least SOAP_SSL_DEFAULT and provide
+ // the necessary CA certificate for validating the server's certificate.
+ if (fSSL && soap_ssl_client_context(&soap, SOAP_SSL_NO_AUTHENTICATION | SOAP_TLSv1,
+ NULL /*clientkey*/, NULL /*password*/,
+ NULL /*cacert*/, NULL /*capath*/,
+ NULL /*randfile*/))
+ {
+ soap_print_fault(&soap, stderr);
+ exit(1);
+ }
+#endif /* WITH_OPENSSL */
+
+ const char *pcszMode = argv[ap];
+ int soaprc = SOAP_SVR_FAULT;
+
+ if (!strcmp(pcszMode, "logon"))
+ {
+ if (argc < 3 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IWebsessionManager_USCORElogon req;
+ req.username = argv[ap + 1];
+ req.password = argv[ap + 2];
+ _vbox__IWebsessionManager_USCORElogonResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IWebsessionManager_USCORElogon(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "VirtualBox objref: \"" << resp.returnval << "\"\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "getsession"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IWebsessionManager_USCOREgetSessionObject req;
+ req.refIVirtualBox = argv[ap + 1];
+ _vbox__IWebsessionManager_USCOREgetSessionObjectResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IWebsessionManager_USCOREgetSessionObject(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "session: \"" << resp.returnval << "\"\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "logoff"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IWebsessionManager_USCORElogoff req;
+ req.refIVirtualBox = argv[ap + 1];
+ _vbox__IWebsessionManager_USCORElogoffResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IWebsessionManager_USCORElogoff(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ ;
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "version"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREgetVersion req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IVirtualBox_USCOREgetVersionResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREgetVersion(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "version: \"" << resp.returnval << "\"\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "gethost"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREgetHost req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IVirtualBox_USCOREgetHostResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREgetHost(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ std::cout << "Host objref " << resp.returnval << "\n";
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "getpc"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREgetPerformanceCollector req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IVirtualBox_USCOREgetPerformanceCollectorResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREgetPerformanceCollector(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ std::cout << "Performance collector objref " << resp.returnval << "\n";
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "getmachines"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREgetMachines req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IVirtualBox_USCOREgetMachinesResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREgetMachines(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ size_t c = resp.returnval.size();
+ for (size_t i = 0;
+ i < c;
+ ++i)
+ {
+ std::cout << "Machine " << i << ": objref " << resp.returnval[i] << "\n";
+ }
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "createmachine"))
+ {
+ if (argc < 4 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREcreateMachine req;
+ req._USCOREthis = argv[ap + 1];
+ req.settingsFile = argv[ap + 2];
+ req.name = argv[ap + 3];
+ std::cout << "createmachine: settingsFile = \"" << req.settingsFile << "\", name = \"" << req.name << "\"\n";
+ _vbox__IVirtualBox_USCOREcreateMachineResponse resp;
+
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREcreateMachine(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "Machine created: managed object reference ID is " << resp.returnval << "\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "registermachine"))
+ {
+ if (argc < 3 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IVirtualBox_USCOREregisterMachine req;
+ req._USCOREthis = argv[ap + 1];
+ req.machine = argv[ap + 2];
+ _vbox__IVirtualBox_USCOREregisterMachineResponse resp;
+ if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREregisterMachine(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "Machine registered.\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "getdvddrives"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IHost_USCOREgetDVDDrives req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IHost_USCOREgetDVDDrivesResponse resp;
+ if (!(soaprc = soap_call___vbox__IHost_USCOREgetDVDDrives(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ size_t c = resp.returnval.size();
+ for (size_t i = 0;
+ i < c;
+ ++i)
+ {
+ std::cout << "DVD drive " << i << ": objref " << resp.returnval[i] << "\n";
+ }
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "getname"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IMachine_USCOREgetName req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IMachine_USCOREgetNameResponse resp;
+ if (!(soaprc = soap_call___vbox__IMachine_USCOREgetName(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ printf("Name is: %s\n", resp.returnval.c_str());
+ }
+ }
+ else if (!strcmp(pcszMode, "getid"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IMachine_USCOREgetId req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IMachine_USCOREgetIdResponse resp;
+ if (!(soaprc = soap_call___vbox__IMachine_USCOREgetId(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "UUID is: " << resp.returnval << "\n";;
+ }
+ }
+ else if (!strcmp(pcszMode, "getostypeid"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IMachine_USCOREgetOSTypeId req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IMachine_USCOREgetOSTypeIdResponse resp;
+ if (!(soaprc = soap_call___vbox__IMachine_USCOREgetOSTypeId(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "Guest OS type is: " << resp.returnval << "\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "savesettings"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IMachine_USCOREsaveSettings req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IMachine_USCOREsaveSettingsResponse resp;
+ if (!(soaprc = soap_call___vbox__IMachine_USCOREsaveSettings(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "Settings saved\n";
+ }
+ }
+ else if (!strcmp(pcszMode, "setupmetrics"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IPerformanceCollector_USCOREsetupMetrics req;
+ req._USCOREthis = argv[ap + 1];
+// req.metricNames[0] = "*";
+// req.objects
+ req.period = 1; // seconds
+ req.count = 100;
+ _vbox__IPerformanceCollector_USCOREsetupMetricsResponse resp;
+ if (!(soaprc = soap_call___vbox__IPerformanceCollector_USCOREsetupMetrics(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ size_t c = resp.returnval.size();
+ for (size_t i = 0;
+ i < c;
+ ++i)
+ {
+ std::cout << "Metric " << i << ": objref " << resp.returnval[i] << "\n";
+ }
+ }
+ }
+ }
+ else if (!strcmp(pcszMode, "querymetricsdata"))
+ {
+ if (argc < 2 + ap)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IPerformanceCollector_USCOREqueryMetricsData req;
+ req._USCOREthis = argv[ap + 1];
+// req.metricNames[0] = "*";
+// req.objects
+ _vbox__IPerformanceCollector_USCOREqueryMetricsDataResponse resp;
+ if (!(soaprc = soap_call___vbox__IPerformanceCollector_USCOREqueryMetricsData(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ {
+ size_t c = resp.returnval.size();
+ for (size_t i = 0;
+ i < c;
+ ++i)
+ {
+ std::cout << "long " << i << ": " << resp.returnval[i] << "\n";
+ }
+ }
+ }
+ }
+ 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)
+ std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n";
+ else
+ {
+ _vbox__IManagedObjectRef_USCORErelease req;
+ req._USCOREthis = argv[ap + 1];
+ _vbox__IManagedObjectRef_USCOREreleaseResponse resp;
+ if (!(soaprc = soap_call___vbox__IManagedObjectRef_USCORErelease(&soap,
+ pcszArgEndpoint,
+ NULL,
+ &req,
+ &resp)))
+ std::cout << "Managed object reference " << req._USCOREthis << " released.\n";
+ }
+ }
+ else
+ std::cout << "Unknown mode parameter \"" << pcszMode << "\".\n";
+
+ if (soaprc)
+ {
+ if ( (soap.fault)
+ && (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::cerr << "Bad object ID: " << soap.fault->detail->vbox__InvalidObjectFault->badObjectID << "\n";
+ }
+ else if (soap.fault->detail->vbox__RuntimeFault)
+ {
+ 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
+ {
+ std::cerr << "Invalid fault data, fault message:\n";
+ soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream
+ }
+ }
+
+ soap_destroy(&soap); // delete deserialized class instances (for C++ only)
+ soap_end(&soap); // remove deserialized data and clean up
+ soap_done(&soap); // detach the gSOAP environment
+
+ return soaprc;
+}
+