diff options
Diffstat (limited to 'src/VBox/Main/webservice')
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 ©From); + + 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, ' = "', $ifname, '";')" /> + <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="struct", 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 &idThis,'" /> + <xsl:call-template name="emitNewline" /> + <xsl:value-of select="' HRESULT &rc,'" /> + <xsl:call-template name="emitNewline" /> + <xsl:value-of select="concat(' ComPtr<', $structname, '> &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) </xsl:text> + <xsl:text> { </xsl:text> + <xsl:text> // @todo ambiguous. Problem is the MOR for the object converted to struct </xsl:text> + <xsl:text> RaiseSoapInvalidObjectFault(soap, ""); </xsl:text> + <xsl:text> break; </xsl:text> + <xsl:text> } </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<IN_BSTR>'" /> <!-- input string arrays must use IN_BSTR (see com/array.h) --> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="'com::SafeArray<BSTR>'" /> <!-- 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<IUnknown>'" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="'ComPtr<IUnknown>'" /> + </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<', $thatifname, '>')" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat('ComPtr<', $thatifname, '>')" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="fatalError"> + <xsl:with-param name="msg" select="concat('emitCppTypeForIDLType: Type "', $type, '" in method "', $method, '" 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 &', $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<IVirtualBox> 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 "', $ifname, '" 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 </xsl:text> + <xsl:value-of select="concat(' ComPtr<', $ifname, '> pObj; ')" /> + <xsl:value-of select="concat(' if (!', $G_requestElementVarName, ') ')" /> + <xsl:text> { </xsl:text> + <xsl:text> RaiseSoapInvalidObjectFault(soap, ""); </xsl:text> + <xsl:text> break; </xsl:text> + <xsl:text> } </xsl:text> + <xsl:value-of select="concat(' const WSDLT_ID &idThis = ', $structprefix, $G_nameObjectRefEncoded, '; ')" /> + <xsl:value-of select="' if ((rc = findComPtrFromId(soap, idThis, pObj, false)) != S_OK) '" /> + <xsl:text> break; </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<BYTE> comcall_',$name, ';')" /> + <xsl:call-template name="emitNewlineIndent8" /> + <xsl:value-of select="concat('Base64DecodeByteArray(soap, ',$structprefix,$name,', ComSafeArrayAsOutParam(comcall_',$name, '), idThis, "', $ifname, '::', $methodname, '", ', $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 < 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<IUnknown> 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<', $type, '> 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(&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 "', $type, '" in arg "', $name, '" of method "', $method, '" 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 "', $type, '" in arg "', $name, '" of method "', $method, '" 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 "', $type, '" in arg "', $name, '" of method "', $method, '" has unsupported wsmap attribute value "', $wsmap, '" 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<', $type, '>')" /> + </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>&</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, "', $methodname, '"));')" /> + <xsl:call-template name="emitNewlineIndent8" /> + <xsl:value-of select="concat('rc = ', $object, '->', $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, "', $ifname, '::', $methodname,'", 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 "', $type, '" in arg "', $name, '" of method "', $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 "', $type, '" in arg "', $name, '" of method "', $thatifname, '::', $method, '" has invalid wsmap attribute value "', $wsmap, '" 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 "', $type, '" in arg "', $name, '" of method "', $method, '" 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, "', $name, '"));')" /> + <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, '->', $name)" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat($G_responseElementVarName, '->', $G_result)" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat($callerprefix, $G_result, '->', $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 < ', $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<', $type, '> 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<IUnknown> 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 "', $type, '" in arg "', $name, '" of method "', $method, '" 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, "', $name, '"));')" /> + <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, '->')" /> + <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 "', $attrname, '" 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, '->')" /> + </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 "', $attrname, '" 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, '->')" /> + </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 "', $methodname, '" because it has arguments with "array" 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, '->')" /> + </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, '->')" /> + <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(' {"vbox", "', $G_targetNamespace, $G_targetNamespaceSeparator, '", 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 { ')" /> + </xsl:when> + <xsl:when test="count(key('G_keyInterfacesByName', $extends)) > 0"> + <xsl:value-of select="concat('class ', $ifname, ' extends ', $extends, ' { ')" /> + </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>; </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>) { </xsl:text> + <xsl:call-template name="genreq"><xsl:with-param name="wsmap" select="$wsmap" /></xsl:call-template> + <xsl:text> } </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><?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>, </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> </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>): </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>
</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 < other + + def __le__(self, other): + if self.isarray: + return NotImplemented + else: + return self.handle <= 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 > other + + def __ge__(self, other): + if self.isarray: + return NotImplemented + else: + return self.handle >= 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 = "', $G_targetNamespace, '"')" /> + <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="'<<<<Request'" /> +<xsl:variable name="G_typeIsGlobalResponseElementMarker" + select="'<<<<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="', $type, '"')" /></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 "', $type, '" in method "', $ifname, '::', $methodname, '" has wsmap="suppress" 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 "', $type, '" used in method "', $ifname, '::', $methodname, '" has unsupported wsmap attribute value "', $wsmap, '"')" /> + </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 "', $type, '" used in method "', $ifname, '::', $methodname, '".')" /> + </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 "', $ifname, '" has invalid wsmap attribute "', $wsmap, '" 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="', $ifname, '" 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 "', $ifname, '"')" /></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 "', $attrtype, '", 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 "', $ifname, '"')" /></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 "', $attrtype, '", 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 "', $ifname, '"')" /></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 "', $attrtype, '", 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<', $ctypefield, '>')" /> + </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<', $enumname, '>')" /> + </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<vbox__', $withoutvboxtypefield, '*>')" /> + </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, ' ""')" /> + <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 "name"="', $requestmsg, '".')" /> + </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 "name"="', $responsemsg, '".')" /> + </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; +} + |