gSOAP 2.7.11 User Guide

gSOAP 2.7.11 User Guide

Robert van Engelen
Florida State University
and Genivia, Inc.
engelen@genivia.com & engelen@acm.org

Aug 24, 2008
[This document is also available in PDF format (black and white only)]



Contents

Introduction
    1.1  Getting Started
    1.2  Developing a Web Service Client Application
    1.3  Developing a Web Service in CGI
    1.4  XML C/C++ Data Bindings: Mapping WSDL and XSD to C/C++
    1.5  Features
Notational Conventions
Differences Between gSOAP Versions 2.4 (and Earlier) and 2.5
Differences Between gSOAP Versions 2.1 (and Earlier) and 2.2
Differences Between gSOAP Versions 1.X and 2.X
Interoperability
Quick User Guide
    7.1  How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Clients
        7.1.1  Example
        7.1.2  Namespace Considerations
        7.1.3  Example
        7.1.4  How to Generate C++ Client Proxy Classes
        7.1.5  XSD Type Encoding Considerations
        7.1.6  Example
        7.1.7  How to Change the Response Element Name
        7.1.8  Example
        7.1.9  How to Specify Multiple Output Parameters
        7.1.10  Example
        7.1.11  How to Specify Output Parameters With struct/class Compound Data Types
        7.1.12  Example
        7.1.13  How to Specify Anonymous Parameter Names
        7.1.14  How to Specify a Method with No Input Parameters
        7.1.15  How to Specify a Method with No Output Parameters
    7.2  How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Web Services
        7.2.1  Example
        7.2.2  MSVC++ Builds
        7.2.3  How to Create a Stand-Alone gSOAP Service
        7.2.4  How to Create a Multi-Threaded Stand-Alone Service
        7.2.5  How to Pass Application Data to Service Methods
        7.2.6  Some Web Service Implementation Issues
        7.2.7  How to Generate C++ Server Object Classes
        7.2.8  How to Generate WSDL Service Descriptions
        7.2.9  Example
        7.2.10  How to Parse and Import WSDL Service Descriptions to Develop Clients and Servers
        7.2.11  The typemap.dat File
        7.2.12  How to Use Client Functionalities Within a Service
    7.3  How to Use gSOAP for Asynchronous One-Way Message Passing
    7.4  One-Way Message Passing over HTTP
    7.5  How to Use the SOAP Serializers and Deserializers to Save and Load Application Data using XML Data Bindings
        7.5.1  Serializing a Data Type
        7.5.2  Deserializing a Data Type
        7.5.3  Example
        7.5.4  Serializing and Deserializing Class Instances to Streams
        7.5.5  How to Specify Default Values for Omitted Data
Using the gSOAP Stub and Skeleton Compiler
    8.1  Compiler Options
    8.2  SOAP 1.1 Versus SOAP 1.2
    8.3  The soapdefs.h Header File
    8.4  How to Build Modules and Libraries with the gSOAP #module Directive
    8.5  How to use the gSOAP #import Directive
    8.6  How to Use #include and #define Directives
    8.7  Compiling a gSOAP Client
    8.8  Compiling a gSOAP Web Service
    8.9  Using gSOAP for Creating Web Services and Clients in Pure C
    8.10  Limitations of gSOAP
    8.11  Compile Time Flags
    8.12  Run Time Flags
    8.13  Memory Management
        8.13.1  Memory Management Policies
        8.13.2  Intra-Class Memory Management
    8.14  Debugging
    8.15  Required Libraries
The gSOAP Remote Method Specification Format
    9.1  Remote Method Parameter Passing
    9.2  Error Codes
    9.3  C/C++ Identifier Name to XML Name Translations
    9.4  Namespace Mapping Table
10  gSOAP Serialization and Deserialization Rules
    10.1  SOAP RPC Encoding Versus Document/Literal and xsi:type Info
    10.2  Primitive Type Encoding
    10.3  How to Represent Primitive C/C++ Types as XSD Types
        10.3.1  How to Use Multiple C/C++ Types for a Single Primitive XSD Type
        10.3.2  How to use Wrapper Classes to Specify Polymorphic Primitive Types
        10.3.3  XSD Schema Type Decoding Rules
        10.3.4  Multi-Reference Strings
        10.3.5  "Smart String" Mixed-Content Decoding
        10.3.6  STL Strings
        10.3.7  Changing the Encoding Precision of float and double Types
        10.3.8  INF, -INF, and NaN Values of float and double Types
    10.4  Enumeration Serialization
        10.4.1  Serialization of Symbolic Enumeration Constants
        10.4.2  Encoding of Enumeration Constants
        10.4.3  Initialized Enumeration Constants
        10.4.4  How to "Reuse" Symbolic Enumeration Constants
        10.4.5  Boolean Enumeration Serialization for C
        10.4.6  Bitmask Enumeration Serialization
    10.5  Struct Serialization
    10.6  Class Instance Serialization
        10.6.1  Example
        10.6.2  Initialized static const Fields
        10.6.3  Class Methods
        10.6.4  Getter and Setter Methods
        10.6.5  Streaming XML with Getter and Setter Methods
        10.6.6  Polymorphism, Derived Classes, and Dynamic Binding
        10.6.7  XML Attributes
        10.6.8  QName Attributes and Elements
    10.7  Union Serialization
    10.8  Serializing Pointer Types
        10.8.1  Multi-Referenced Data
        10.8.2  NULL Pointers and Nil Elements
    10.9  Void Pointers
    10.10  Fixed-Size Arrays
    10.11  Dynamic Arrays
        10.11.1  SOAP Array Bounds Limits
        10.11.2  One-Dimensional Dynamic Arrays
        10.11.3  Example
        10.11.4  One-Dimensional Dynamic Arrays With Non-Zero Offset
        10.11.5  Nested One-Dimensional Dynamic Arrays
        10.11.6  Multi-Dimensional Dynamic Arrays
        10.11.7  Encoding XML Generics Containing Dynamic Arrays
        10.11.8  STL Containers
        10.11.9  Polymorphic Dynamic Arrays and Lists
        10.11.10  How to Change the Tag Names of the Elements of a SOAP Array or List
    10.12  Base64Binary XML Schema Type Encoding
    10.13  hexBinary XML Schema Type Encoding
    10.14  Literal XML Encoding Style
        10.14.1  Serializing and Deserializing Mixed Content XML With Strings
11  SOAP Fault Processing
12  SOAP Header Processing
13  MIME Attachments
    13.1  Sending a Collection of MIME Attachments (SwA)
    13.2  Retrieving a Collection of MIME Attachments (SwA)
14  DIME Attachments
    14.1  Sending a Collection of DIME Attachments
    14.2  Retrieving a Collection of DIME Attachments
    14.3  Serializing Binary Data in DIME
    14.4  Streaming DIME
    14.5  Streaming Chunked DIME
    14.6  WSDL Bindings for DIME Attachments
15  MTOM Attachments
    15.1  Generating MultipartRelated MIME Attachment Bindings in WSDL
    15.2  Sending and Receiving MTOM Attachments
    15.3  Streaming MTOM/MIME
    15.4  Redirecting Inbound MTOM/MIME Streams Based on SOAP Body Content
    15.5  Streaming Chunked MTOM/MIME
16  XML Validation
    16.1  Occurrence Constraints
        16.1.1  Elements with minOccurs and maxOccurs Restrictions
        16.1.2  Required and Prohibited Attributes
        16.1.3  Data Length Restrictions
    16.2  Other Constraints
17  SOAP-over-UDP
    17.1  Using WS-Addressing with SOAP-over-UDP
    17.2  Client-side One-way Unicast
    17.3  Client-side One-way Multicast
    17.4  Client-side Request-Response Unicast
    17.5  Client-side Request-Response Multicast
    17.6  SOAP-over-UDP Server
18  Advanced Features
    18.1  Internationalization
    18.2  Customizing the WSDL and Namespace Mapping Table File Contents With gSOAP Directives
        18.2.1  Example
    18.3  Transient Data Types
    18.4  Volatile Data Types
    18.5  How to Declare User-Defined Serializers and Deserializers
    18.6  How to Serialize Data Without Generating XSD Type Attributes
    18.7  Function Callbacks for Customized I/O and HTTP Handling
    18.8  HTTP 1.0 and 1.1
    18.9  HTTP 307 Temporary Redirect Support
    18.10  HTTP GET Support
    18.11  TCP and HTTP Keep-Alive
    18.12  HTTP Chunked Transfer Encoding
    18.13  HTTP Buffered Sends
    18.14  HTTP Authentication
    18.15  HTTP Proxy Authentication
    18.16  Speed Improvement Tips
    18.17  Timeout Management for Non-Blocking Operations
    18.18  Socket Options and Flags
    18.19  Secure SOAP Web Services with HTTPS/SSL
    18.20  Secure SOAP Clients with HTTPS/SSL
    18.21  SSL Authentication Callback
    18.22  SSL Certificates
    18.23  SSL Hardware Acceleration
    18.24  SSL on Windows
    18.25  Zlib Compression
    18.26  Client-Side Cookie Support
    18.27  Server-Side Cookie Support
    18.28  Connecting Clients Through Proxy Servers
    18.29  FastCGI Support
    18.30  How to Create gSOAP Applications With a Small Memory Footprint
    18.31  How to Eliminate BSD Socket Library Linkage
    18.32  How to Combine Multiple Client and Server Implementations into one Executable
    18.33  How to Build a Client or Server in a C++ Code Namespace
    18.34  How to Create Client/Server Libraries
        18.34.1  C++ Example
        18.34.2  C Example
    18.35  How to Create DLLs
        18.35.1  Create the Base stdsoap2.dll
        18.35.2  Creating Client and Server DLLs
    18.36  gSOAP Plug-ins
        18.36.1  The Message Logging and Statistics Plug-in
        18.36.2  The HTTP GET Plug-in
        18.36.3  The HTTP MD5 Plug-in
        18.36.4  The HTTP Digest Authentication Plug-in
        18.36.5  The WS-Addressing Plug-in
        18.36.6  The WS-Security Plug-in

Copyright (C) 2000-2006 Robert A. van Engelen, Genivia, Inc., All Rights Reserved.

1  Introduction

The gSOAP tools provide a SOAP/XML-to-C/C++ language binding to ease the development of SOAP/XML Web services and client application in C and C++. Most toolkits for C++ Web services adopt a SOAP-centric view and offer APIs that require the use of class libraries for SOAP-specific data structures. This often forces a user to adapt the application logic to these libraries. In contrast, gSOAP provides a C/C++ transparent SOAP API through the use of compiler technology that hides irrelevant SOAP-specific details from the user. The gSOAP stub and skeleton compiler automatically maps native and user-defined C and C++ data types to semantically equivalent XML data types and vice-versa. As a result, full SOAP interoperability is achieved with a simple API relieving the user from the burden of SOAP details, thus enabling him or her to concentrate on the application-essential logic.
The gSOAP compiler enables the integration of (legacy) C/C++ and Fortran codes (through a Fortran to C interface), embedded systems, and real-time software in SOAP applications that share computational resources and information with other SOAP applications, possibly across different platforms, language environments, and disparate organizations located behind firewalls.

1.1  Getting Started

To start building Web services applications with gSOAP, you need: gSOAP is self-contained, so there is no need to download any third-party software (unless you want to use OpenSSL and the library is not already installed).
Although gSOAP is available in binary format for several platforms, the code generated by the gSOAP stub and skeleton compiler and the gSOAP runtime codes are equivalent. This means that the generated source codes can be transferred to other platforms and locally compiled.
The gSOAP packages available from SourceForge include pre-build tools in the gsoap/bin directory: Win32 binaries of these two tools are included in the gSOAP package, see the README files in the package for more details. If you don't have the binaries or if you want to rebuild them, you need Bison and Flex are preferred.
The gSOAP engine is build as a library libgsoap.a and libgsoap++.a with separate versions that support SSL. See the README.txt instructions on how to build these libraries with the platform-independent gSOAP package's autoconf and automake. Alternatively, you can compile and link the engine's source code stdsoap2.c (or stdsoap2.cpp for C++) directly with your code.
The gSOAP packages contain numerous examples in the samples directory. Run make to build the example applications. The examples are also meant to demonstrate different features of gSOAP. A streaming MTOM attachment server and client application demonstrate efficient file exchanges in samples/mtom-streaming. An SSL-secure Web server application demonstrates the generation of dynamic content for Web browsing and Web services functionality at the same time, see samples/webservice. And much more.

1.2  Developing a Web Service Client Application

The gSOAP tools minimize application adaptation efforts for building Web Services by using an XML C/C++ data binding implemented by source-to-source code generation tools. The gSOAP wsdl2h tool imports one or more WSDLs and XML schemas and generates a gSOAP header file in familiar C/C++ syntax with the Web service operations and the C/C++ data types used by the services. The gSOAP soapcpp2 compiler then takes this header file and generates XML serializers for the data types (soapH.h and soapC.cpp), the client-side stubs (soapClient.cpp), and server-side skeletons (soapServer.cpp).
The gSOAP soapcpp2 compiler can also generate WSDL definitions for implementing a service from scratch, i.e. without defining a WSDL first. This "closes the circle" in that it enables Web services development from WSDL or directly from a set op C/C++ operations in a header file without the need for users to analyze Web service details.
You only need to follow a few steps to execute the tools from the command line or Makefile (see also MSVC++ project examples in the samples directory with tool integration in the MSVC++ IDE). For example, to generate code for the calculator Web service, we run the wsdl2h tool from the command line on the URL of the WSDL and use option -o to specify the output file:

$ wsdl2h -o calc.h http://www.cs.fsu.edu/~engelen/calc.wsdl

This generates the calc.h header file with Web service operation declarations and the data types of the operation parameter. This header file is then to be processed with soapcpp2 to generate the stub and/or skeleton code. The calc.h file includes all documentation, so you can use Doxygen (http://www.doxygen.org) to automatically generate the documentation pages for your development.
In this example we are developing a C++ API for the calculator service. By default, gSOAP assumes you will use C++ with STL. To build without STL, use option -s:

$ wsdl2h -s -o calc.h http://www.cs.fsu.edu/~engelen/calc.wsdl

To build a pure C application, use option -c:

$ wsdl2h -c -o calc.h http://www.cs.fsu.edu/~engelen/calc.wsdl

We have not yet generated the stubs for the C/C++ API. To do so, run the soapcpp2 compiler:

$ soapcpp2 -i -C -Iimport calc.h

Option -i indicates that we want C++ proxy and server objects that include the client (and server) code, -C indicates client-side only files (soapcpp2 generates both client and server stubs and skeletons by default). Option -I is needed to import the stlvector.h file to support STL vectors.
Suppose we develop a C++ client for the calculator service using wsdl2h -o calc,h http://www.cs.fsu.edu/~engelen/calc.wsdl and soapcpp2 -i -C calc.h.
We use the generated soapcalcProxy class and calc.nsmap XML namespace mapping table to access the Web service. The soapcalcProxy class is a proxy to invoke the service:

#include "soapcalcProxy.h"
#include "calc.nsmap"
main()
{
   calcProxy service;
   double result;
   if (service.add(1.0, 2.0, result) == SOAP_OK)
      std::cout << "The sum of 1.0 and 2.0 is " << result << std::endl;
   else
      service.soap_stream_fault(std::cerr);
}

To complete the build, compile and link the generated soapC.cpp, soapcalcProxy.cpp, and the run-time gSOAP engine -lgsoap++ (or use source stdsoap2.cpp in case libgsoap++.a is not installed) with your code.
Suppose we develop a client in C using wsdl2h -c -o calc.h http://www.cs.fsu.edu/~engelen/calc.wsdl and soapcpp2 -C calc.h. The code should have to use C calling conventions:


#include "soapH.h"
#include "calc.nsmap"
main()
{
   struct soap *soap = soap_new();
   double result;
   if (soap_call_ns__add(soap, 1.0, 2.0, &result) == SOAP_OK)
      printf("The sum of 1.0 and 2.0 is %g
n", result);
   else
      soap_print_fault(soap, stderr);
   soap_end(soap);
   soap_free(soap);
}

Similar examples can be found in the samples directory in the gSOAP package, including a server for the calculator example.

1.3  Developing a Web Service in CGI

Developing a service application is easy too.
Suppose we implement a CGI-based service that returns the time in GMT. The Common Gateway Interface (CGI) is a simple mechanism to publish services on your Web site, but it is certainly not the most efficient way. You can also develop high-performance stand-alone gSOAP services with built-in HTTP/S stacks or you can use Apache mod_gsoap and IIS (see the extras directory).
For this example we start with a gSOAP header file, currentTime.h which contains the service definitions. Such as file can be obtained from a WSDL using wsdl2h when a WSDL is available. When a WSDL is not available, you can define the service in C/C++ definitions in a newly created header file and let the gSOAP tools generate the source code and WSDL for you.
Our currentTime service only has an output parameter, which is the current time as defined in our currentTime.h gSOAP service specification:

// File: currentTime.h
//gsoap ns service name: currentTime
//gsoap ns service namespace: urn:currentTime
//gsoap ns service location: http://www.yourdomain.com/currentTime.cgi
int ns__currentTime(time_t& response);

Note that we must associate an XML namespace with a service. The gSOAP tools use a special convention for identifier names that are part of a namespace: a namespace prefix (ns in this case) followed by a double underscore __. This convention is used to resolve namespaces and to avoid name clashes. The ns namespace prefix is bound to the urn:currentTime namespace name with the //gsoap directive. The //gsoap directives are used to set the properties of the service, in this case the name, namespace, and location endpoint.
The service implementation for CGI requires a soap_serve call on a soap context created with soap_new. The service operations are implemented as functions, which are called by the RPC dispatcher soap_serve:

// File: currentTime.cpp
main()
{
   // create soap context and serve one CGI-based request:
   soap_serve(soap_new());
}
int ns__currentTime(struct soap *soap, time_t& response)
{
   response = time(0);
   return SOAP_OK;
}

Note that we pass the soap struct with the gSOAP context information to the service routine. This can come in handy to determine properties of the connection and to dynamically allocate data with soap_malloc(soap, num_bytes) that will be automatically deleted when the service is finished. We run the soapcpp2 compiler on the header file to generate the server-side code:

$ soapcpp2 -S currentTime.h

and then compile the CGI binary:

$ c++ -o currentTime.cgi currentTime.cpp soapC.cpp soapServer.cpp stdsoap2.cpp

To activate the service, copy the currentTime.cgi binary to your bin-cgi directory with the proper file permissions.
The soapcpp2 compiler generated the WSDL definitions currentTime.wsdl. You can use the WSDL to advertize your service. You don't need to use this WSDL to develop a gSOAP client. You can use the currentTime.h file with the soapcpp2 -C command to generate client-side code.

1.4  XML C/C++ Data Bindings: Mapping WSDL and XSD to C/C++

The XML C/C++ data binding in gSOAP allows any C and C++ data type to be transformed into XML and vice versa (with very few exceptions). Likewise, an XML schema (XSD file) can be transformed into a set of C or C++ definitions that can be readily incorporated into your application to manipulate XML with much more ease than DOM or SAX. Essentially, each XML component definition in an XML schema has a C/C++ data type representation. An automatic mapping between XML elements of the XML schema and members of a class is created to store the data in memory. No DOM traversals and SAX events need to be defined. In addition, the XML C/C++ data binding makes XML manipulation type safe. That is, the type safety of C/C++ ensures that only valid XML documents can be parsed and generated.
We will illustrate this with a simple example. Suppose we have an XML document with a book record:

<book isbn="1234567890">
   <title>Farewell John Doe</title>
   <publisher>ABC's is our Name</publisher>
</book>

A natural choice for a mapping to a class could be

class book
{
   @ULONG64 isbn;
   std::string title;
   std::string publisher;
}

Note that annotations such as @ can be used to distinguish attributes from elements.
The XML document could be described by the following XML schema

<schema ...>
   <element name="book">
      <complexType>
         <sequence>
            <element name="title" type="string" minOccurs="1"/>
            <element name="publisher" type="string" minOccurs="1"/>
         </sequence>
         <attribute name="isbn" type="unsignedLong" use="required"/>
      </complexType>
   </element>
</schema>

To create C or C++ data bindings for this schema, the wsdl2h tool transforms the XSD file to the C/C++ definitions, similar to the example C++ declarations code shown above. The soapcpp2 compiler then generates all to code to parse and generate XML for this book object. Validation constraints such as minOccurs="1" and use="required" are included in the generated code as checks.
To generate the XML representation of a book nicely indented, first create a soap engine context and use it with the soap_put method (generated by soapcpp2) to send the object to standard output as an XML "book" tag:

soap *ctx = soap_new1(SOAP_XML_INDENT); // new context with option
book bk;
bk.isbn = 1234567890;
bk.title = "Farewell John Doe";
bk.publisher = "ABC's is our Name";
soap_begin_send(ctx);
bk.soap_put(ctx, "book", NULL);
soap_end_send(ctx);
soap_end(ctx); // clean up allocated temporaries
soap_free(ctx); // delete context

The ctx gSOAP engine context (type struct soap) controls settings and holds state, such as XML formatting, (e.g. SOAP_XML_INDENT), serialization options, current state, and I/O settings. Simply set the output stream (std::ostream) ctx->os of the context to redirect the content, e.g. to a file or string. Also, when serializing a graph the code should invoke the serializer bk.soap_serialize(ctx) on the object or type before the soap_put method to ensure the output conforms to SOAP encoding for object graphs or you can use an encoding that is based on id-ref, see Section 7.5 for details.
To parse the XML representation into a book object, use:

soap *ctx = soap_new1(SOAP_XML_STRICT); // new context with option
book bk;
soap_begin_recv(ctx);
bk.soap_get(ctx, "book", NULL);
if (ctx->error == SOAP_OK)    cout << bk.isbn << ", " << bk.title << ", " << bk.publisher << endl;
... further use of bk ...
soap_end_recv(ctx);
soap_destroy(ctx); // delete deserialized objects
soap_end(ctx); // delete temporaries
soap_free(ctx); // delete context

Automatic built-in XML validation (enabled with SOAP_XML_STRICT) ensures that data members are present so we can safely print them in this example, thus ensuring consistency of data with the XML schema. Set the ctx->is input stream to read from a file/string stream instead of stdin.
The soap_destroy and soap_end calls deallocate the deserialized content, so use with care. In general, memory management is automatic in gSOAP to avoid leaks.
The above is a very simple example. The gSOAP toolkit handles pointer-based data structures (including cyclic graphs!), structs/classes, unions, enums, STL containers, and even special data types such as struct tm, that are handled via user-definable custom serializers.
Normally the namespace prefixes of XML namespaces are added to the C/C++ type definitions to ensure type uniqueness. For example, if we would combine two schemas in the same application where both schemas define a book object, we need to resolve this conflict. In gSOAP this is done using namespace prefixes, rather than C++ namespaces (research has pointed out that XML namespaces are not equivalent to C++ namespaces). Thus, the book class might actually be bound to an XML namespace and the class would be named ns__book, where ns is bound to the corresponding namespace.
More information on serialization of C/C++ data types can be found in Section 7.5.

1.5  Features

The highlights of gSOAP are:

2  Notational Conventions

The typographical conventions used by this document are:
Sans serif or italics font
denotes C and C++ source code, file names, and shell/batch commands.
Bold font
denotes C and C++ keywords.
Courier font
denotes HTTP header content, HTML, XML, XML Schema content and WSDL content.
[Optional]
denotes an optional construct.
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC-2119.

3  Differences Between gSOAP Versions 2.4 (and Earlier) and 2.5

To comply with WS-I Basic Profile 1.0a, gSOAP 2.5 and higher adopts SOAP document/literal by default. There is no need for concern, because the WSDL parser wsdl2h automatically takes care of the differences when you provide a WSDL document, because SOAP RPC encoding, literal, and document style are supported. A new soapcpp2 compiler option was added -e for backward compatibility with gSOAP 2.4 and earlier to adopt SOAP RPC encoding by default in case you want to develop a service that uses SOAP encoding. You can also use the gSOAP compiler directives to specify SOAP encoding for individual operarations, when desired.

4  Differences Between gSOAP Versions 2.1 (and Earlier) and 2.2

You should read this section only if you are upgrading from gSOAP 2.1 to 2.2 and later.
Run-time options and flags have been changed to enable separate recv/send settings for transport, content encodings, and mappings. The flags are divided into four classes: transport (IO), content encoding (ENC), XML marshalling (XML), and C/C++ data mapping (C). The old-style flags soap_disable_X and soap_enable_X, where X is a particular feature, are deprecated. See Section 8.12 for more details.

5  Differences Between gSOAP Versions 1.X and 2.X

You should read this section only if you are upgrading from gSOAP 1.X to 2.X.
gSOAP versions 2.0 and later have been rewritten based on versions 1.X. gSOAP 2.0 and later is thread-safe, while 1.X is not. All files in the gSOAP 2.X distribution are renamed to avoid confusion with gSOAP version 1.X files:

gSOAP 1.X gSOAP 2.X
soapcpp soapcpp2
soapcpp.exe soapcpp2.exe
stdsoap.h stdsoap2.h
stdsoap.c stdsoap2.c
stdsoap.cpp stdsoap2.cpp

Changing the version 1.X application codes to accommodate gSOAP 2.X does not require a significant amount of recoding. The change to gSOAP 2.X affects all functions defined in stdsoap2.c[pp] (the gSOAP runtime environment API) and the functions in the sources generated by the gSOAP compiler (the gSOAP RPC+marshalling API). Therefore, clients and services developed with gSOAP 1.X need to be modified to accommodate a change in the calling convention used in 2.X: In 2.X, all gSOAP functions (including the remote method proxy routines) take an additional parameter which is an instance of the gSOAP runtime environment that includes file descriptors, tables, buffers, and flags. This additional parameter is always the first parameter of any gSOAP function.
The gSOAP runtime environment is stored in a struct soap type. A struct was chosen to support application development in C without the need for a separate gSOAP implementation. An object-oriented approach with a class for the gSOAP runtime environment would have prohibited the implementation of pure C applications. Before a client can invoke remote methods or before a service can accept requests, a runtime environment need to be allocated and initialized. Three new functions are added to gSOAP 2.X:

Function Description
soap_init(struct soap *soap) Initializes a static or stack-allocated environment (required only once)
struct soap *soap_new() Allocates, initializes, and returns a pointer to a runtime environment
struct soap *soap_copy(struct soap *soap) Allocates a new runtime environment and copies contents of the environment such that the new environment does not share any data with the original environment

An environment can be reused as many times as necessary and does not need to be reinitialized in doing so. A dynamically allocated environment is deallocated with soap_free.
A new environment is only required for each new thread to guarantee exclusive access to a new runtime environment by each thread. For example, the following code stack-allocates the runtime environment which is used for multiple remote method calls:

int main()
{
   struct soap soap;
   ...
   soap_init(&soap); // initialize runtime environment
   ...
   soap_call_ns__method1(&soap, ...); // make a remote call
   ...
   soap_call_ns__method2(&soap, ...); // make another remote call
   ...
   soap_destroy(&soap); // remove deserialized class instances (C++ only)
   soap_end(&soap); // clean up and remove deserialized data
   soap_done(&soap); // detach environment (last use and no longer in scope)
   ...
}

The runtime environment can also be heap allocated:

int main()
{
   struct soap *soap;
   ...
   soap = soap_new(); // allocate and initialize runtime environment
   if (!soap) // couldn't allocate: stop
   ...
   soap_call_ns__method1(soap, ...); // make a remote call
   ...
   soap_call_ns__method2(soap, ...); // make another remote call
   ...
   soap_destroy(soap); // remove deserialized class instances (C++ only)
   soap_end(soap); // clean up and remove deserialized data
   soap_free(soap); // detach and free runtime environment
}

A service need to allocate and initialize an environment before calling soap_serve:

int main()
{
   struct soap soap;
   soap_init(&soap);
   soap_serve(&soap);
}

Or alternatively:

int main()
{
   soap_serve(soap_new());
}

The soap_serve dispatcher handles one request or multiple requests when HTTP keep-alive is enabled (with the SOAP_IO_KEEPALIVE flag see Section 18.11).
A service can use multi-threading to handle requests while running some other code that invokes remote methods:

int main()
{
   struct soap soap1, soap2;
   pthread_t tid;
   ...
   soap_init(&soap1);
   if (soap_bind(&soap1, host, port, backlog) < 0) exit(1);
   if (soap_accept(&soap1) < 0) exit(1);
   pthread_create(&tid, NULL, (void*(*)(void*))soap_serve, (void*)&soap1);
   ...
   soap_init(&soap2);
   soap_call_ns__method(&soap2, ...); // make a remote call
   ...
   soap_end(&soap2);
   ...
   pthread_join(tid, NULL); // wait for thread to terminate
   soap_end(&soap1); // release its data
}

In the example above, two runtime environments are required. In comparison, gSOAP 1.X statically allocates the runtime environment, which prohibits multi-threading (only one thread can invoke remote methods and/or accept requests due to the single runtime environment).
Section 7.2.4 presents a multi-threaded stand-alone Web Service that handles multiple SOAP requests by spawning a thread for each request.

6  Interoperability

gSOAP interoperability has been verified with the following SOAP implementations and toolkits:
Apache 2.2
Apache Axis
ASP.NET
Cape Connect
Delphi
easySOAP++
eSOAP
Frontier
GLUE
Iona XMLBus
kSOAP
MS SOAP
Phalanx
SIM
SOAP::Lite
SOAP4R
Spray
SQLData
Wasp Adv.
Wasp C++
White Mesa
xSOAP
ZSI
4S4C

7  Quick User Guide

This user guide offers a quick way to get started with gSOAP. This section requires a basic understanding of the SOAP 1.1 protocol and some familiarity with C and/or C++. In principle, SOAP clients and SOAP Web services can be developed in C and C++ with the gSOAP compiler without a detailed understanding of the SOAP protocol when gSOAP client-server applications are built as an ensamble and only communicate within this group (i.e. meaning that you don't have to worry about interoperability with other SOAP implementations). This section is intended to illustrate the implementation of gSOAP Web services and clients that connect to and interoperate with other SOAP implementations such as Apache Axis, SOAP::Lite, and .NET. This requires some details of the SOAP and WSDL protocols to be understood.

7.1  How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Clients

In general, the implementation of a SOAP client application requires a stub routine for each remote method that the client application needs to invoke. The primary stub's responsibility is to marshall the parameter data, send the request with the parameters to the designated SOAP service over the wire, to wait for the response, and to demarshall the parameter data of the response when it arrives. The client application invokes the stub routine for a remote method as if it would invoke a local method. To write a stub routine in C or C++ by hand is a tedious task, especially if the input and/or output parameters of a remote method contain elaborate data structures such as records, arrays, and graphs. Fortunately, the gSOAP 'wsdl2h' WSDL parser and 'soapcpp2' stub and skeleton compiler automate the development of Web service client and server applications.
The gSOAP stub and skeleton compiler is a preprocessor that generates the necessary C++ sources to build SOAP C++ clients. The input to the gSOAP stub and skeleton compiler consists of a standard C/C++ header file. The header file can be generated from a WSDL (Web Service Description Language) documentation of a service with the gSOAP WSDL parser.
Consider the following command (entered at the command prompt):

$ wsdl2h -o quote.h http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl

This generates the file quote.h in C++ format from the WSDL at the specified URL.
To generate a header file to develop a pure C client application, issue the command: Consider the following command (entered at the command prompt):

$ wsdl2h -c -o quote.h http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl

For more details on the WSDL parser and its options, see 7.2.10.
The quote.h header file is then processed by the gSOAP compiler to generate the stubs to develop client applications (and skeletons to develop a service).
The SOAP service methods are specified in the header file as function prototypes. Stub routines in C/C++ source form are automatically generated by the gSOAP compiler for these function prototypes of remote methods. The resulting stub routines allow C and C++ client applications to seamlessly interact with existing SOAP Web services.
The gSOAP stub and skeleton compiler also generates skeleton routines for each of the remote methods specified in the header file. The skeleton routines can be readily used to implement one or more of the remote methods in a new SOAP Web service. These skeleton routines are not used for building SOAP clients in C++, although they can be used to build mixed SOAP client/server applications (peer applications).
The input and output parameters of a SOAP service method may be simple data types or compound data types, either generated by the WSDL parser or specified by hand. The gSOAP stub and skeleton compiler automatically generates serializers and deserializers for the data types to enable the generated stub routines to encode and decode the contents of the parameters of the remote methods in XML.

7.1.1  Example

The getQuote remote method of XMethods Delayed Stock Quote service (defined in the quote.h file obtained with the 'wsdl2h' WSDL parser) provides a delayed stock quote for a given ticker name. The WSDL description of the XMethods Delayed Stock Quote service provides the following details:

Endpoint URL: http://services.xmethods.net:80/soap
SOAP action: "" (2 quotes)
Remote method namespace: urn:xmethods-delayed-quotes
Remote method name: getQuote
   Input parameter: symbol of type xsd:string
   Output parameter: Result of type xsd:float

The following getQuote.h header file for C is created from the WSDL description with the WSDL parser (the actual contents may vary depending on the 'wsdl2h' release version and the options used to determine the output):

//gsoap ns1 service name: net_DOTxmethods_DOTservices_DOTstockquote_DOTStockQuoteBinding
//gsoap ns1 service type: net_DOTxmethods_DOTservices_DOTstockquote_DOTStockQuotePortType
//gsoap ns1 service port: http://66.28.98.121:9090/soap
//gsoap ns1 service namespace: urn:xmethods-delayed-quotes
//gsoap ns1 service documentation: Definitions generated by the gSOAP WSDL parser 1.0
// Service net.xmethods.services.stockquote.StockQuoteService : net.xmethods.services.stockquote.StockQuote web service

//gsoap ns1 service method-style: getQuote rpc
//gsoap ns1 service method-encoding: getQuote http://schemas.xmlsoap.org/soap/encoding/
//gsoap ns1 service method-action: getQuote urn:xmethods-delayed-quotes#getQuote
int ns1__getQuote(char *symbol, float &Result);

The header file essentially specifies the service details in C/C++ with directives for the gSOAP compiler. The remote method is declared as a ns1__getQuote function prototype which specifies all of the necessary details for the gSOAP compiler to generate the stub routine for a client application to interact with the Delayed Stock Quote service.
The Delayed Stock Quote service description requires that the input parameter of the getQuote remote method is a symbol parameter of type string. The description also indicates that the Result output parameter is a floating point number that represents the current unit price of the stock in dollars. The gSOAP compiler uses the convention the last parameter of the function prototype must be the output parameter of the remote method, which is required to be passed by reference using the reference operator (&) or by using a pointer type. All other parameters except the last are input parameters of the remote method, which are required to be passed by value or passed using a pointer to a value (by reference is not allowed). The function prototype associated with a remote method is required to return an int, whose value indicates to the caller whether the connection to a SOAP Web service was successful or resulted in an exception, see Section 9.2 for the error codes.
The use of the namespace prefix ns1__ in the remote method name in the function prototype declaration is discussed in detail in 7.1.2. Basically, a namespace prefix is distinguished by a pair of underscores in the function name, as in ns1__getQuote where ns1 is the namespace prefix and getQuote is the remote method name. (A single underscore in an identifier name will be translated into a dash in XML, because dashes are more frequently used in XML compared to underscores, see Section 9.3.)
The gSOAP compiler is invoked from the command line with:

soapcpp2 getQuote.h

The compiler generates the stub routine for the getQuote remote method specified in the getQuote.h header file. This stub routine can be called by a client program at any time to request a stock quote from the Delayed Stock Quote service. The interface to the generated stub routine is the following function prototype generated by the gSOAP compiler:

int soap_call_ns1__getQuote(struct soap *soap, char *URL, char *action, char *symbol, float &Result);

The stub routine is saved in soapClient.cpp. The file soapC.cpp contains the serializer and deserializer routines for the data types used by the stub. You can use option -c for the soapcpp2 compiler to generate pure C code.
Note that the parameters of the soap_call_ns1__getQuote function are identical to the ns1__getQuote function prototype with three additional input parameters: soap must be a valid pointer to a gSOAP runtime environment, URL is the SOAP Web service endpoint URL passed as a string, and action is a string that denotes the SOAP action required by the Web service. Note that the XMethods Delayed Stock Quote service endpoint URL is http://66.28.98.121:9090/soap and the SOAP action required is "" (two quotes). You can change the endpoint and action dynamically. The endpoint and action are the second and third parameters of the soap_call_ns1__getQuote. When NULL, the values specified in the header file will be used.
The following example mixed C/C++ client program invokes the stub to retrieve the latest IBM stock quote from the XMethods Delayed Stock Quote service:

#include "soapH.h" // obtain the generated stub
#include "net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding.nsmap" // obtain the namespace mapping table
int main()
{
   struct soap soap; // gSOAP runtime environment
   float quote;
   soap_init(&soap); // initialize runtime environment (only once)
   if (soap_call_ns1__getQuote(&soap, NULL, NULL, "IBM", &quote) == SOAP_OK)
      std::cout << "Current IBM Stock Quote = " << quote << std::endl;
   else // an error occurred
      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 0;
}

When successful, the stub returns SOAP_OK and quote contains the latest stock quote. Otherwise, an error occurred and the SOAP fault is displayed with the soap_print_fault function. Use soap_sprint_fault(struct soap*, char *buf, size_t len) to print the error to a string.
The gSOAP compiler also generates a proxy class for C++ client applications. This generated proxy class can be included into a client application together with the generated namespace table as shown in this example:

#include "soapnet_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBindingProxy.h" // get proxy
#include "net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding.nsmap" // obtain the namespace mapping table
int main()
{
   net q; // "net" is the proxy class with a name that is the short name of the service
   float r;
   if (q.ns1__getQuote("IBM", r) == SOAP_OK)
      std::cout << r << std::endl;
   else
      soap_print_fault(q.soap, stderr);
   return 0;
}

The proxy class constructor allocates and initializes a gSOAP environment for the instance. All the HTTP and SOAP/XML processing is hidden and performed on the background. Note that you can change the name of the service in the header file generated by the WSDL parser. The name is extracted from the WSDL content and may not always be in a short format. Feel free to change the entry

//gsoap ns1 service name: net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding

to use a more suitable name. The name will control the file name of the proxy class file and the XML namespace mapping table.
The following functions can be used to explicitly setup a gSOAP runtime environment (struct soap):

Function Description
soap_init(struct soap *soap) Initializes a static/stack-allocated runtime environment
soap_init1(struct soap *soap, soap_mode iomode) Initializes a runtime environment and set in/out mode flags
soap_init2(struct soap *soap, soap_mode imode, soap_mode omode) Initializes a runtime environment and set separate in/out mode flags
struct soap *soap_new() Allocates, initializes, and returns a pointer to a runtime environment
struct soap *soap_new1(soap_mode iomode) Allocates, initializes, and returns a pointer to a runtime environment and set in/out mode flags
struct soap *soap_new2(soap_mode imode, soap_mode omode) Allocates, initializes, and returns a pointer to a runtime environment and set separate in/out mode flags
struct soap *soap_copy(struct soap *soap) Allocates a new runtime environment and copies contents of the source environment such that the new environment does not share data with the source environment
soap_done(struct soap *soap) Reset, close communications, and remove callbacks
soap_free(struct soap *soap) Reset and deallocate the environment created with soap_new or soap_copy

An environment can be reused as many times as necessary for client-side remote calls and does not need to be reinitialized in doing so. A new environment is required for each new thread to guarantee exclusive access to runtime environments by threads. Also the use of any client calls within an active service method requires a new environment.
When the example client application is invoked, the SOAP request is performed by the stub routine soap_call_ns1__getQuote, which generates the following SOAP RPC request message:

POST /soap HTTP/1.1
Host: services.xmethods.net
Content-Type: text/xml
Content-Length: 529
SOAPAction: ""

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:ns1="urn:xmethods-delayed-quotes"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getQuote>
<symbol>IBM</symbol>
</ns1:getQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The XMethods Delayed Stock Quote service responds with the SOAP response message:

HTTP/1.1 200 OK
Date: Sat, 25 Aug 2001 19:28:59 GMT
Content-Type: text/xml
Server: Electric/1.0
Connection: Keep-Alive
Content-Length: 491

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
   soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/»
<soap:Body>
<n:getQuoteResponse xmlns:n="urn:xmethods-delayed-quotes»
<Result xsi:type="xsd:float»41.81</Result>
</n:getQuoteResponse>
</soap:Body>
</soap:Envelope>

The server's SOAP RPC response is parsed by the stub. The stub routine further demarshalls the data of Result element of the SOAP response and stores it in the quote parameter of soap_call_ns1__getQuote.
A client program can invoke a remote method at any time and multiple times if necessary. Consider for example:

...
struct soap soap;
float quotes[3]; char *myportfolio[] = {"IBM", "MSDN"};
soap_init(&soap); // need to initialize only once
for (int i = 0; i < 3; i++)
   if (soap_call_ns1__getQuote(&soap, "http://services.xmethods.net:80/soap", "", myportfolio[i], &quotes[i]) != SOAP_OK)
      break;
if (soap.error) // an error occurred
   soap_print_fault(&soap, stderr);
soap_end(&soap); // clean up all deserialized data
...

This client composes an array of stock quotes by calling the ns1__getQuote stub routine for each symbol in a portfolio array.
This example demonstrated how easy it is to build a SOAP client with gSOAP once the details of a Web service are available in the form of a WSDL document.

7.1.2  Namespace Considerations

The declaration of the ns1__getQuote function prototype (discussed in the previous section) uses the namespace prefix ns1__ of the remote method namespace, which is distinguished by a pair of underscores in the function name to separate the namespace prefix from the remote method name. The purpose of a namespace prefix is to associate a remote method name with a service in order to prevent naming conflicts, e.g. to distinguish identical remote method names used by different services.
Note that the XML response of the XMethods Delayed Stock Quote service example uses the namespace prefix n which is bound to the namespace name urn:xmethods-delayed-quotes through the xmlns:n="urn:xmethods-delayed-quotes binding. The use of namespace prefixes and namespace names is also required to enable SOAP applications to validate the content of SOAP messages. The namespace name in the service response is verified by the stub routine by using the information supplied in a namespace mapping table that is required to be part of gSOAP client and service application codes. The table is accessed at run time to resolve namespace bindings, both by the generated stub's data structure serializer for encoding the client request and by the generated stub's data structure deserializer to decode and validate the service response. The namespace mapping table should not be part of the header file input to the gSOAP stub and skeleton compiler. Service details including namespace bindings may be provided with gSOAP directives in a header file, see Section 18.2.
The namespace mapping table for the Delayed Stock Quote client is:

struct Namespace namespaces[] =
{   // {"ns-prefix", "ns-name"}
   {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, // MUST be first
   {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, // MUST be second
   {"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, // MUST be third
   {"xsd", "http://www.w3.org/2001/XMLSchema"}, // 2001 XML Schema
   {"ns1", "urn:xmethods-delayed-quotes"}, // given by the service description
   {NULL, NULL} // end of table
};

The first four namespace entries in the table consist of the standard namespaces used by the SOAP 1.1 protocol. In fact, the namespace mapping table is explicitly declared to enable a programmer to specify the SOAP encoding style and to allow the inclusion of namespace-prefix with namespace-name bindings to comply to the namespace requirements of a specific SOAP service. For example, the namespace prefix ns1, which is bound to urn:xmethods-delayed-quotes by the namespace mapping table shown above, is used by the generated stub routine to encode the getQuote request. This is performed automatically by the gSOAP compiler by using the ns1 prefix of the ns1__getQuote method name specified in the getQuote.h header file. In general, if a function name of a remote method, struct name, class name, enum name, or field name of a struct or class has a pair of underscores, the name has a namespace prefix that must be defined in the namespace mapping table.
The namespace mapping table will be output as part of the SOAP Envelope by the stub routine. For example:

...
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:ns1="urn:xmethods-delayed-quotes"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
...

The namespace bindings will be used by a SOAP service to validate the SOAP request.

7.1.3  Example

The incorporation of namespace prefixes into C++ identifier names is necessary to distinguish remote methods that share the same name but are provided by separate Web services and/or organizations. Consider for example:

// Contents of file "getQuote.h":
int ns1__getQuote(char *symbol, float &Result);
int ns2__getQuote(char *ticker, char *&quote);

Recall that the namespace prefix is always separated from the name of a remote method by a pair of underscores (__).
This example enables a client program to connect to a (hypothetical) Stock Quote service with remote methods that can only be distinguished by their namespaces. Consequently, two different namespace prefixes had to be used as part of the remote method names.
The namespace prefix convention can also be applied to class declarations that contain SOAP compound values that share the same name but have different namespaces that refer to different XML Schemas. For example:

class e__Address // an electronic address
{
   char *email;
   char *url;
};
class s__Address // a street address
{
   char *street;
   int number;
   char *city;
};

The namespace prefix is separated from the name of a data type by a pair of underscores (__).
An instance of e__Address is encoded by the generated serializer for this type as an Address element with namespace prefix e:

<e:Address xsi:type="e:Address">
<email xsi:type="string">me@home</email>
<url xsi:type="string">www.me.com</url>
</e:Address>

While an instance of s__Address is encoded by the generated serializer for this type as an Address element with namespace prefix s:

<s:Address xsi:type="s:Address">
<street xsi:type="string">Technology Drive</street>
<number xsi:type="int">5</number>
<city xsi:type="string">Softcity</city>
</s:Address>

The namespace mapping table of the client program must have entries for e and s that refer to the XML Schemas of the data types:

struct Namespace namespaces[] =
{ ...
   {"e", "http://www.me.com/schemas/electronic-address"},
   {"s", "http://www.me.com/schemas/street-address"},
...

This table is required to be part of the client application to allow access by the serializers and deserializers of the data types at run time.

7.1.4  How to Generate C++ Client Proxy Classes

Proxy classes for C++ client applications are automatically generated by the gSOAP compiler.
There is a new and improved code generation capability for proxy classes, which is activated with the soapcpp2 -i option. These new proxy classes are derived from the soap structure, have a cleaner interface and offer more capabilites.
With C++, you can also use wsdl2h option -qname to generate the proxy in a C++ namespace name. This is very useful if you want to create multiple proxies for services by repeated use of wsdl2h and combine them in one code. Alternatively, you can run wsdl2h just once on all service WSDLs and have soapcpp2 generate multiple proxies for you. The latter approach does not use C++ namespaces and may reduce the overall amount of code.
To illustrate the generation of a "standard" (old-style) proxy class, the getQuote.h header file example of the previous section is augmented with the appropriate directives to enable the gSOAP compiler to generate the proxy class. Similar directives are included in the header file by the WSDL importer.

// Content of file "getQuote.h":
//gsoap ns1 service name: Quote
//gsoap ns1 service location: http://services.xmethods.net/soap
//gsoap ns1 service namespace: urn:xmethods-delayed-quotes
//gsoap ns1 service style: rpc
//gsoap ns1 service encoding: encoded
//gsoap ns1 service method-action: getQuote ""
int ns1__getQuote(char *symbol, float &Result);

The first three directives provide the service name which is used to name the proxy class, the service location (endpoint), and the schema. The forth and fifth directives specify that SOAP RPC encoding is used, which is required by this service. The last directive defines the optional SOAPAction, which is a string associated with SOAP 1.1 operations. This directive must be provided for each remote method when the SOAPAction is required. Compilation of this header file with the gSOAP compiler soapcpp2 creates a new file soapQuoteProxy.h with the following contents:

#include "soapH.h"
class Quote
{ public:
   struct soap *soap;
   const char *endpoint;
   Quote() { soap = soap_new(); endpoint = "http://services.xmethods.net/soap"; };
   ~Quote() { if (soap) { soap_destroy(soap); soap_end(soap); soap_free(soap); }};
   int getQuote(char *symbol, float &Result) { return soap ? soap_call_ns1__getQuote(soap, endpoint, "", symbol, Result) : SOAP_EOM; };
};

The gSOAP environment and endpoint are declared public to enable access for run-time customization.
This generated proxy class can be included into a client application together with the generated namespace table as shown in this example:

#include "soapQuoteProxy.h" // get proxy
#include "Quote.nsmap" // get namespace bindings
int main()
{
   Quote q;
   float r;
   if (q.ns1__getQuote("IBM", r) == SOAP_OK)
      std::cout << r << std::endl;
   else
      soap_print_fault(q.soap, stderr);
   return 0;
}

The Quote constructor allocates and initializes a gSOAP environment for the instance. All the HTTP and SOAP/XML processing is hidden and performed on the background.
You can use soapcpp2 compiler option -n together with -p to create a local namespaces table to avoid link conflicts when you need multiple namespace tables or need to combine multiple clients, see also Sections 8.1 and 18.34, and you can use a C++ code namespace to create a namespace qualified proxy class, see Section 18.33.
Don't forget to try the soapcpp2 -i option to generate proxy classes derived from the base soap structure. In addition, these classes offer more functionality.

7.1.5  XSD Type Encoding Considerations

Many SOAP services require the explicit use of XML Schema types in the SOAP payload. The default encoding, which is also adopted by the gSOAP compiler, assumes SOAP RPC encoding which only requires the use of types to handle polymorphic cases. Nevertheless, the use of XSD typed messages is advised to improve interoperability. XSD types are introduced with typedef definitions in the header file input to the gSOAP compiler. The type name defined by a typedef definition corresponds to an XML Schema type (XSD type). For example, the following typedef declarations define various built-in XSD types implemented as primitive C/C++ types:

// Contents of header file:
...
typedef char *xsd__string; // encode xsd__string value as the xsd:string schema type
typedef char *xsd__anyURI; // encode xsd__anyURI value as the xsd:anyURI schema type
typedef float xsd__float; // encode xsd__float value as the xsd:float schema type
typedef long xsd__int; // encode xsd__int value as the xsd:int schema type
typedef bool xsd__boolean; // encode xsd__boolean value as the xsd:boolean schema type
typedef unsigned long long xsd__positiveInteger; // encode xsd__positiveInteger value as the xsd:positiveInteger schema type
...

This simple mechanism informs the gSOAP compiler to generate serializers and deserializers that explicitly encode and decode the primitive C++ types as built-in primitive XSD types when the typedefed type is used in the parameter signature of a remote method (or when used nested within structs, classes, and arrays). At the same time, the use of typedef does not force any recoding of a C++ client or Web service application as the internal C++ types used by the application are not required to be changed (but still have to be primitive C++ types, see Section 10.3.2 for alternative class implementations of primitive XSD types which allows for the marshalling of polymorphic primitive types).

7.1.6  Example

Reconsider the getQuote example, now rewritten with explicit XSD types to illustrate the effect:

// Contents of file "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
int ns1__getQuote(xsd__string symbol, xsd__float &Result);

This header file is compiled by the gSOAP stub and skeleton compiler and the compiler generates source code for the function soap_call_ns1__getQuote, which is identical to the "old" proxy:

int soap_call_ns1__getQuote(struct soap *soap, char *URL, char *action, char *symbol, float &Result);

The client application does not need to be rewritten and can still call the proxy using the "old" parameter signature. In contrast to the previous implementation of the stub however, the encoding and decoding of the data types by the stub has been changed to explicitly use the XSD types in the message payload.
For example, when the client application calls the proxy, the proxy produces a SOAP request with an xsd:string:

...
<SOAP-ENV:Body>
<ns1:getQuote><symbol xsi:type="xsd:string">IBM</symbol>
</ns1:getQuote>
</SOAP-ENV:Body>
...

The service response is:

...
<soap:Body>
<n:getQuoteResponse xmlns:n="urn:xmethods-delayed-quotes»
<Result xsi:type="xsd:float»41.81</Result>
</n:getQuoteResponse>
</soap:Body>
...

The validation of this service response by the stub routine takes place by matching the namespace names (URIs) that are bound to the xsd namespace prefix. The stub also expects the getQuoteResponse element to be associated with URI urn:xmethods-delayed-quotes through the binding of the namespace prefix ns1 in the namespace mapping table. The service response uses namespace prefix n for the getQuoteResponse element. This namespace prefix is bound to the same URI urn:xmethods-delayed-quotes and therefore the service response is assumed to be valid. The response is rejected and a SOAP fault is generated when the URIs do not match.

7.1.7  How to Change the Response Element Name

There is no standardized convention for the response element name in a SOAP response message, although it is recommended that the response element name is the method name ending with "Response". For example, the response element of getQuote is getQuoteResponse.
The response element name can be specified explicitly using a struct or class declaration in the header file. The struct or class name represents the SOAP response element name used by the service. Consequently, the output parameter of the remote method must be declared as a field of the struct or class. The use of a struct or a class for the service response is fully SOAP 1.1 compliant. In fact, the absence of a struct or class indicates to the gSOAP compiler to automatically generate a struct for the response which is internally used by a stub.

7.1.8  Example

Reconsider the getQuote remote method specification which can be rewritten with an explicit declaration of a SOAP response element as follows:

// Contents of "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
struct ns1__getQuoteResponse {xsd__float Result;};
int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse &r);

The SOAP request is the same as before:

...
<SOAP-ENV:Body>
<ns1:getQuote><symbol xsi:type="xsd:string">IBM</symbol>
</ns1:getQuote>
</SOAP-ENV:Body>
...

The difference is that the service response is required to match the specified getQuoteResponse name and its namespace URI:

...
<soap:Body>
<n:getQuoteResponse xmlns:n='urn:xmethods-delayed-quotes'>
<Result xsi:type='xsd:float'>41.81</Result>
</n:getQuoteResponse>
</soap:Body>
...

This use of a struct or class enables the adaptation of the default SOAP response element name and/or namespace URI when required.
Note that the struct (or class) declaration may appear within the function prototype declaration. For example:

// Contents of "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse {xsd__float Result;} &r);

This example combines the declaration of the response element of the remote method with the function prototype of the remote method.

7.1.9  How to Specify Multiple Output Parameters

The gSOAP stub and skeleton compiler uses the convention that the last parameter of the function prototype declaration of a remove method in a header file is also the only single output parameter of the method. All other parameters are considered input parameters of the remote method. To specify a remote method with multiple output parameters, a struct or class must be declared for the remote method response, see also 7.1.7. The fields of the struct or class are the output parameters of the remote method. Both the order of the input parameters in the function prototype and the order of the output parameters (the fields in the struct or class) is not significant. However, the SOAP 1.1 specification states that input and output parameters may be treated as having anonymous parameter names which requires a particular ordering, see Section 7.1.13.

7.1.10  Example

As an example, consider a hypothetical remote method getNames with a single input parameter SSN and two output parameters first and last. This can be specified as:

// Contents of file "getNames.h":
int ns3__getNames(char *SSN, struct ns3__getNamesResponse {char *first; char *last;} &r);

The gSOAP stub and skeleton compiler takes this header file as input and generates source code for the function soap_call_ns3__getNames. When invoked by a client application, the proxy produces the SOAP request:

...
<SOAP-ENV:Envelope ... xmlns:ns3="urn:names" ...>
...
<ns3:getNames>
<SSN>999 99 9999</SSN>
</ns3:getNames>
...

The response by a SOAP service could be:

...
<m:getNamesResponse xmlns:m="urn:names">
<first>John</first>
<last>Doe</last>
</m:getNamesResponse>
...

where first and last are the output parameters of the getNames remote method of the service.
As another example, consider a remote method copy with an input parameter and an output parameter with identical parameter names (this is not prohibited by the SOAP 1.1 protocol). This can be specified as well using a response struct:

// Content of file "copy.h":
int X_rox__copy_name(char *name, struct X_rox__copy_nameResponse {char *name;} &r);

The use of a struct or class for the remote method response enables the declaration of remote methods that have parameters that are passed both as input and output parameters.
The gSOAP compiler takes the copy.h header file as input and generates the soap_call_X_rox__copy_name proxy. When invoked by a client application, the proxy produces the SOAP request:

...
<SOAP-ENV:Envelope ... xmlns:X-rox="urn:copy" ...>
...
<X-rox:copy-name>
<name>SOAP</name>
</X-rox:copy-name>
...

The response by a SOAP copy service could be something like:

...
<m:copy-nameResponse xmlns:m="urn:copy">
<name>SOAP</name>
</m:copy-nameResponse>
...

The name will be parsed and decoded by the proxy and returned in the name field of the struct X_rox__copy_nameResponse &r parameter.

7.1.11  How to Specify Output Parameters With struct/class Compound Data Types

If the single output parameter of a remote method is a complex data type such as a struct or class it is necessary to specify the response element of the remote method as a struct or class at all times. Otherwise, the output parameter will be considered the response element (!), because of the response element specification convention used by gSOAP, as discussed in 7.1.7.

7.1.12  Example

This is is best illustrated with an example. The Flighttracker service by ObjectSpace provides real time flight information for flights in the air. It requires an airline code and flight number as parameters. The remote method name is getFlightInfo and the method has two string parameters: the airline code and flight number, both of which must be encoded as xsd:string types. The method returns a getFlightResponse response element with a return output parameter that is of complex type FlightInfo. The type FlightInfo is represented by a class in the header file, whose field names correspond to the FlightInfo accessors:

// Contents of file "flight.h":
typedef char *xsd__string;
class ns2__FlightInfo
{
   public:
   xsd__string airline;
   xsd__string flightNumber;
   xsd__string altitude;
   xsd__string currentLocation;
   xsd__string equipment;
   xsd__string speed;
};
struct ns1__getFlightInfoResponse {ns2__FlightInfo _return;};
int ns1__getFlightInfo(xsd__string param1, xsd__string param2, struct ns1__getFlightInfoResponse &r);

The response element ns1__getFlightInfoResponse is explicitly declared and it has one field: return_ of type ns2__FlightInfo. Note that return_ has a trailing underscore to avoid a name clash with the return keyword, see Section 9.3 for details on the translation of C++ identifiers to XML element names.
The gSOAP compiler generates the soap_call_ns1__getFlightInfo proxy. Here is an example fragment of a client application that uses this proxy to request flight information:

struct soap soap;
...
soap_init(&soap);
...
soap_call_ns1__getFlightInfo(&soap, "testvger.objectspace.com/soap/servlet/rpcrouter",
   "urn:galdemo:flighttracker", "UAL", "184", r);
...
struct Namespace namespaces[] =
{
   {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"},
   {"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"},
   {"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
   {"xsd", "http://www.w3.org/2001/XMLSchema"},
   {"ns1", "urn:galdemo:flighttracker"},
   {"ns2", "http://galdemo.flighttracker.com"},
   {NULL, NULL}
};

When invoked by a client application, the proxy produces the SOAP request:

POST /soap/servlet/rpcrouter HTTP/1.1
Host: testvger.objectspace.com
Content-Type: text/xml
Content-Length: 634
SOAPAction: "urn:galdemo:flighttracker"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:ns1="urn:galdemo:flighttracker"
   xmlns:ns2="http://galdemo.flighttracker.com"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getFlightInfo xsi:type="ns1:getFlightInfo">
<param1 xsi:type="xsd:string">UAL</param1>
<param2 xsi:type="xsd:string">184</param2>
</ns1:getFlightInfo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The Flighttracker service responds with:

HTTP/1.1 200 ok
Date: Thu, 30 Aug 2001 00:34:17 GMT
Server: IBM_HTTP_Server/1.3.12.3 Apache/1.3.12 (Win32)
Set-Cookie: sesessionid=2GFVTOGC30D0LGRGU2L4HFA;Path=/
Cache-Control: no-cache="set-cookie,set-cookie2"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Content-Length: 861
Content-Type: text/xml; charset=utf-8
Content-Language: en

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:getFlightInfoResponse xmlns:ns1="urn:galdemo:flighttracker"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xmlns:ns2="http://galdemo.flighttracker.com" xsi:type="ns2:FlightInfo">
<equipment xsi:type="xsd:string">A320</equipment>
<airline xsi:type="xsd:string">UAL</airline>
<currentLocation xsi:type="xsd:string">188 mi W of Lincoln, NE</currentLocation>
<altitude xsi:type="xsd:string">37000</altitude>
<speed xsi:type="xsd:string">497</speed>
<flightNumber xsi:type="xsd:string">184</flightNumber>
</return>
</ns1:getFlightInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The proxy returns the service response in variable r of type struct ns1__getFlightInfoResponse and this information can be displayed by the client application with the following code fragment:

cout << r.return_.equipment << " flight " << r.return_.airline << r.return_.flightNumber
    << " traveling " << r.return_.speed << " mph " << " at " << r.return_.altitude
    << " ft, is located " << r.return_.currentLocation << endl;

This code displays the service response as:

A320 flight UAL184 traveling 497 mph at 37000 ft, is located 188 mi W of Lincoln, NE

Note: the flight tracker service is no longer available since 9/11/2001. It is kept in the documentation as an example to illustrate the use of structs/classes and response types.

7.1.13  How to Specify Anonymous Parameter Names

The SOAP 1.1 protocol allows parameter names to be anonymous. That is, the name(s) of the output parameters of a remote method are not strictly required to match a client's view of the parameters names. Also, the input parameter names of a remote method are not strictly required to match a service's view of the parameter names. Although this convention is likely to be deprecated in SOAP 1.2, the gSOAP compiler can generate stub and skeleton routines that support anonymous parameters. Parameter names are implicitly anonymous by omitting the parameter names in the function prototype of the remote method. For example:

// Contents of "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
int ns1__getQuote(xsd__string, xsd__float&);

To make parameter names explicitly anonymous on the receiving side (client or service), the parameter names should start with an underscore (_) in the function prototype in the header file.
For example:

// Contents of "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
int ns1__getQuote(xsd__string symbol, xsd__float &_return);

Or, alternatively with a response struct:

// Contents of "getQuote.h":
typedef char *xsd__string;
typedef float xsd__float;
struct ns1__getQuoteResponse {xsd__float _return;};
int ns1__getQuote(xsd__string symbol, struct ns1__getQuoteResponse &r);

In this example, _return is an anonymous output parameter. As a consequence, the service response to a request made by a client created with gSOAP using this header file specification may include any name for the output parameter in the SOAP payload. The input parameters may also be anonymous. This affects the implementation of Web services in gSOAP and the matching of parameter names by the service.
Caution: when anonymous parameter names are used, the order of the parameters in the function prototype of a remote method is significant.

7.1.14  How to Specify a Method with No Input Parameters

To specify a remote method that has no input parameters, just provide a function prototype with one parameter which is the output parameter (some C/C++ c