blob: 791338c9239718ff3a2a0ee166eb6e36f78c8109 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<meta name="GENERATOR" content="TtH 3.72">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style type="text/css"> div.p { margin-top: 7pt;}</style>
<style type="text/css"><!--
td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
td div.norm {line-height:normal;}
span.roman {font-family: serif; font-style: normal; font-weight: normal;}
span.overacc2 {position: relative; left: .8em; top: -1.2ex;}
span.overacc1 {position: relative; left: .6em; top: -1.2ex;} --></style>
<body bgcolor="#FFFFFF">
<title> gSOAP 2.7.6 User Guide</title>
<h1 align="center">gSOAP 2.7.6 User Guide </h1>
<h3 align="center">Robert van Engelen <br />Florida State University <br />and Genivia, Inc. <br />engelen@genivia.com &amp; engelen@acm.org </h3>
<h3 align="center">Feb 19, 2006
<br /><a href="soapdoc2.pdf"><font color="#FF0000"><b>[This document is also available in PDF format (black and white only)]</b></font></a></h3>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<h1>Contents </h1><a href="#tth_sEc1"
>1&nbsp; <font color="#0000FF">Introduction</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc1.1"
>1.1&nbsp; <font color="#0000FF">Getting Started</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc1.2"
>1.2&nbsp; <font color="#0000FF">Your First Web Service Client Application</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc1.3"
>1.3&nbsp; <font color="#0000FF">Your First Web Service in CGI</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc1.4"
>1.4&nbsp; <font color="#0000FF">Features</font></a><br />
<a href="#tth_sEc2"
>2&nbsp; <font color="#0000FF">Notational Conventions</font></a><br />
<a href="#tth_sEc3"
>3&nbsp; <font color="#0000FF">Differences Between gSOAP Versions 2.4 (and Earlier) and 2.5</font></a><br />
<a href="#tth_sEc4"
>4&nbsp; <font color="#0000FF">Differences Between gSOAP Versions 2.1 (and Earlier) and 2.2</font></a><br />
<a href="#tth_sEc5"
>5&nbsp; <font color="#0000FF">Differences Between gSOAP Versions 1.X and 2.X</font></a><br />
<a href="#tth_sEc6"
>6&nbsp; <font color="#0000FF">Interoperability</font></a><br />
<a href="#tth_sEc7"
>7&nbsp; <font color="#0000FF">Quick User Guide</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1"
>7.1&nbsp; <font color="#0000FF">How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Clients</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.1"
>7.1.1&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.2"
>7.1.2&nbsp; <font color="#0000FF">Namespace Considerations</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.3"
>7.1.3&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.4"
>7.1.4&nbsp; <font color="#0000FF">How to Generate C++ Client Proxy Classes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.5"
>7.1.5&nbsp; <font color="#0000FF">XSD Type Encoding Considerations</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.6"
>7.1.6&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.7"
>7.1.7&nbsp; <font color="#0000FF">How to Change the Response Element Name</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.8"
>7.1.8&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.9"
>7.1.9&nbsp; <font color="#0000FF">How to Specify Multiple Output Parameters</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.10"
>7.1.10&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.11"
>7.1.11&nbsp; <font color="#0000FF">How to Specify Output Parameters With struct/class Compound Data Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.12"
>7.1.12&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.13"
>7.1.13&nbsp; <font color="#0000FF">How to Specify Anonymous Parameter Names</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.14"
>7.1.14&nbsp; <font color="#0000FF">How to Specify a Method with No Input Parameters</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.1.15"
>7.1.15&nbsp; <font color="#0000FF">How to Specify a Method with No Output Parameters</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2"
>7.2&nbsp; <font color="#0000FF">How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Web Services</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.1"
>7.2.1&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.2"
>7.2.2&nbsp; <font color="#0000FF">MSVC++ Builds</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.3"
>7.2.3&nbsp; <font color="#0000FF">How to Create a Stand-Alone gSOAP Service</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.4"
>7.2.4&nbsp; <font color="#0000FF">How to Create a Multi-Threaded Stand-Alone Service</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.5"
>7.2.5&nbsp; <font color="#0000FF">How to Pass Application Data to Service Methods</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.6"
>7.2.6&nbsp; <font color="#0000FF">Some Web Service Implementation Issues</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.7"
>7.2.7&nbsp; <font color="#0000FF">How to Generate C++ Server Object Classes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.8"
>7.2.8&nbsp; <font color="#0000FF">How to Generate WSDL Service Descriptions</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.9"
>7.2.9&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.10"
>7.2.10&nbsp; <font color="#0000FF">How to Parse and Import WSDL Service Descriptions to Develop Clients and Servers</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.11"
>7.2.11&nbsp; <font color="#0000FF">The typemap.dat File</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.2.12"
>7.2.12&nbsp; <font color="#0000FF">How to Use Client Functionalities Within a Service</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.3"
>7.3&nbsp; <font color="#0000FF">How to Use gSOAP for Asynchronous One-Way Message Passing</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.4"
>7.4&nbsp; <font color="#0000FF">One-Way Message Passing over HTTP</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5"
>7.5&nbsp; <font color="#0000FF">How to Use the SOAP Serializers and Deserializers to Save and Load Application Data</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5.1"
>7.5.1&nbsp; <font color="#0000FF">Serializing a Data Type</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5.2"
>7.5.2&nbsp; <font color="#0000FF">Deserializing a Data Type</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5.3"
>7.5.3&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5.4"
>7.5.4&nbsp; <font color="#0000FF">Serializing and Deserializing Class Instances to Streams</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc7.5.5"
>7.5.5&nbsp; <font color="#0000FF">How to Specify Default Values for Omitted Data</font></a><br />
<a href="#tth_sEc8"
>8&nbsp; <font color="#0000FF">Using the gSOAP Stub and Skeleton Compiler</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.1"
>8.1&nbsp; <font color="#0000FF">Compiler Options</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.2"
>8.2&nbsp; <font color="#0000FF">SOAP 1.1 Versus SOAP 1.2</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.3"
>8.3&nbsp; <font color="#0000FF">The soapdefs.h Header File</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.4"
>8.4&nbsp; <font color="#0000FF">How to Build Modules and Libraries with the gSOAP #module Directive</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.5"
>8.5&nbsp; <font color="#0000FF">How to use the gSOAP #import Directive</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.6"
>8.6&nbsp; <font color="#0000FF">How to Use #include and #define Directives</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.7"
>8.7&nbsp; <font color="#0000FF">Compiling a gSOAP Client</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.8"
>8.8&nbsp; <font color="#0000FF">Compiling a gSOAP Web Service</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.9"
>8.9&nbsp; <font color="#0000FF">Using gSOAP for Creating Web Services and Clients in Pure C</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.10"
>8.10&nbsp; <font color="#0000FF">Limitations of gSOAP</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.11"
>8.11&nbsp; <font color="#0000FF">Compile Time Flags</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.12"
>8.12&nbsp; <font color="#0000FF">Run Time Flags</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.13"
>8.13&nbsp; <font color="#0000FF">Memory Management</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.13.1"
>8.13.1&nbsp; <font color="#0000FF">Memory Management Policies</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.13.2"
>8.13.2&nbsp; <font color="#0000FF">Intra-Class Memory Management</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.14"
>8.14&nbsp; <font color="#0000FF">Debugging</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc8.15"
>8.15&nbsp; <font color="#0000FF">Required Libraries</font></a><br />
<a href="#tth_sEc9"
>9&nbsp; <font color="#0000FF">The gSOAP Remote Method Specification Format</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc9.1"
>9.1&nbsp; <font color="#0000FF">Remote Method Parameter Passing</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc9.2"
>9.2&nbsp; <font color="#0000FF">Error Codes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc9.3"
>9.3&nbsp; <font color="#0000FF">C/C++ Identifier Name to XML Name Translations</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc9.4"
>9.4&nbsp; <font color="#0000FF">Namespace Mapping Table</font></a><br />
<a href="#tth_sEc10"
>10&nbsp; <font color="#0000FF">gSOAP Serialization and Deserialization Rules</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.1"
>10.1&nbsp; <font color="#0000FF">Primitive Type Encoding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2"
>10.2&nbsp; <font color="#0000FF">How to Encode and Decode Primitive Types as XSD Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.1"
>10.2.1&nbsp; <font color="#0000FF">How to Use Multiple C/C++ Types for a Single Primitive XSD Type</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.2"
>10.2.2&nbsp; <font color="#0000FF">How to use Wrapper Classes to Specify Polymorphic Primitive Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.3"
>10.2.3&nbsp; <font color="#0000FF">XSD Schema Type Decoding Rules</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.4"
>10.2.4&nbsp; <font color="#0000FF">Multi-Reference Strings</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.5"
>10.2.5&nbsp; <font color="#0000FF">"Smart String" Mixed-Content Decoding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.6"
>10.2.6&nbsp; <font color="#0000FF">STL Strings</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.7"
>10.2.7&nbsp; <font color="#0000FF">Changing the Encoding Precision of <b>float</b>&nbsp;and <b>double</b>&nbsp;Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.2.8"
>10.2.8&nbsp; <font color="#0000FF">INF, -INF, and NaN Values of <b>float</b>&nbsp;and <b>double</b>&nbsp;Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3"
>10.3&nbsp; <font color="#0000FF">Enumeration Serialization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.1"
>10.3.1&nbsp; <font color="#0000FF">Serialization of Symbolic Enumeration Constants</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.2"
>10.3.2&nbsp; <font color="#0000FF">Encoding of Enumeration Constants</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.3"
>10.3.3&nbsp; <font color="#0000FF">Initialized Enumeration Constants</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.4"
>10.3.4&nbsp; <font color="#0000FF">How to "Reuse" Symbolic Enumeration Constants</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.5"
>10.3.5&nbsp; <font color="#0000FF">Boolean Enumeration Serialization for C</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.3.6"
>10.3.6&nbsp; <font color="#0000FF">Bitmask Enumeration Serialization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.4"
>10.4&nbsp; <font color="#0000FF">Struct Serialization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5"
>10.5&nbsp; <font color="#0000FF">Class Instance Serialization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.1"
>10.5.1&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.2"
>10.5.2&nbsp; <font color="#0000FF">Initialized <b>static</b>&nbsp;<b>const</b>&nbsp;Fields</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.3"
>10.5.3&nbsp; <font color="#0000FF">Class Methods</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.4"
>10.5.4&nbsp; <font color="#0000FF">Getter and Setter Methods</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.5"
>10.5.5&nbsp; <font color="#0000FF">Streaming XML with Getter and Setter Methods</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.6"
>10.5.6&nbsp; <font color="#0000FF">Polymorphism, Derived Classes, and Dynamic Binding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.7"
>10.5.7&nbsp; <font color="#0000FF">XML Attributes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.5.8"
>10.5.8&nbsp; <font color="#0000FF">QName Attributes and Elements</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.6"
>10.6&nbsp; <font color="#0000FF">Union Serialization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.7"
>10.7&nbsp; <font color="#0000FF">Serializing Pointer Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.7.1"
>10.7.1&nbsp; <font color="#0000FF">Multi-Referenced Data</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.7.2"
>10.7.2&nbsp; <font color="#0000FF">NULL Pointers and Nil Elements</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.8"
>10.8&nbsp; <font color="#0000FF">Void Pointers</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.9"
>10.9&nbsp; <font color="#0000FF">Fixed-Size Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10"
>10.10&nbsp; <font color="#0000FF">Dynamic Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.1"
>10.10.1&nbsp; <font color="#0000FF">SOAP Array Bounds Limits</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.2"
>10.10.2&nbsp; <font color="#0000FF">One-Dimensional Dynamic Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.3"
>10.10.3&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.4"
>10.10.4&nbsp; <font color="#0000FF">One-Dimensional Dynamic Arrays With Non-Zero Offset</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.5"
>10.10.5&nbsp; <font color="#0000FF">Nested One-Dimensional Dynamic Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.6"
>10.10.6&nbsp; <font color="#0000FF">Multi-Dimensional Dynamic Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.7"
>10.10.7&nbsp; <font color="#0000FF">Encoding XML Generics Containing Dynamic Arrays</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.8"
>10.10.8&nbsp; <font color="#0000FF">STL Containers</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.9"
>10.10.9&nbsp; <font color="#0000FF">Polymorphic Dynamic Arrays and Lists</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.10.10"
>10.10.10&nbsp; <font color="#0000FF">How to Change the Tag Names of the Elements of a SOAP Array or List</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.11"
>10.11&nbsp; <font color="#0000FF">Base64Binary XML Schema Type Encoding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.12"
>10.12&nbsp; <font color="#0000FF">hexBinary XML Schema Type Encoding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.13"
>10.13&nbsp; <font color="#0000FF">Literal XML Encoding Style</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc10.13.1"
>10.13.1&nbsp; <font color="#0000FF">Serializing and Deserializing Mixed Content XML With Strings</font></a><br />
<a href="#tth_sEc11"
>11&nbsp; <font color="#0000FF">SOAP Fault Processing</font></a><br />
<a href="#tth_sEc12"
>12&nbsp; <font color="#0000FF">SOAP Header Processing</font></a><br />
<a href="#tth_sEc13"
>13&nbsp; <font color="#0000FF">MIME Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc13.1"
>13.1&nbsp; <font color="#0000FF">Sending a Collection of MIME Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc13.2"
>13.2&nbsp; <font color="#0000FF">Retrieving a Collection of MIME Attachments</font></a><br />
<a href="#tth_sEc14"
>14&nbsp; <font color="#0000FF">DIME Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.1"
>14.1&nbsp; <font color="#0000FF">Sending a Collection of DIME Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.2"
>14.2&nbsp; <font color="#0000FF">Retrieving a Collection of DIME Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.3"
>14.3&nbsp; <font color="#0000FF">Serializing Binary Data in DIME</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.4"
>14.4&nbsp; <font color="#0000FF">Streaming DIME</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.5"
>14.5&nbsp; <font color="#0000FF">Streaming Chunked DIME</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc14.6"
>14.6&nbsp; <font color="#0000FF">WSDL Bindings for DIME Attachments</font></a><br />
<a href="#tth_sEc15"
>15&nbsp; <font color="#0000FF">MTOM Attachments</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc15.1"
>15.1&nbsp; <font color="#0000FF">Generating MultipartRelated MIME Attachment Bindings in WSDL</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc15.2"
>15.2&nbsp; <font color="#0000FF">Sending and Receiving MTOM Attachments</font></a><br />
<a href="#tth_sEc16"
>16&nbsp; <font color="#0000FF">XML Validation</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc16.1"
>16.1&nbsp; <font color="#0000FF">Occurrence Constraints</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc16.1.1"
>16.1.1&nbsp; <font color="#0000FF">Elements with minOccurs and maxOccurs Restrictions</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc16.1.2"
>16.1.2&nbsp; <font color="#0000FF">Required and Prohibited Attributes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc16.1.3"
>16.1.3&nbsp; <font color="#0000FF">Data Length Restrictions</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc16.2"
>16.2&nbsp; <font color="#0000FF">Other Constraints</font></a><br />
<a href="#tth_sEc17"
>17&nbsp; <font color="#0000FF">SOAP-over-UDP</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.1"
>17.1&nbsp; <font color="#0000FF">Using WS-Addressing with SOAP-over-UDP</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.2"
>17.2&nbsp; <font color="#0000FF">Client-side One-way Unicast</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.3"
>17.3&nbsp; <font color="#0000FF">Client-side One-way Multicast</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.4"
>17.4&nbsp; <font color="#0000FF">Client-side Request-Response Unicast</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.5"
>17.5&nbsp; <font color="#0000FF">Client-side Request-Response Multicast</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc17.6"
>17.6&nbsp; <font color="#0000FF">SOAP-over-UDP Server</font></a><br />
<a href="#tth_sEc18"
>18&nbsp; <font color="#0000FF">Advanced Features</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.1"
>18.1&nbsp; <font color="#0000FF">Internationalization</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.2"
>18.2&nbsp; <font color="#0000FF">Customizing the WSDL and Namespace Mapping Table File Contents With gSOAP Directives</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.2.1"
>18.2.1&nbsp; <font color="#0000FF">Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.3"
>18.3&nbsp; <font color="#0000FF">Transient Data Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.4"
>18.4&nbsp; <font color="#0000FF">Volatile Data Types</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.5"
>18.5&nbsp; <font color="#0000FF">How to Declare User-Defined Serializers and Deserializers</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.6"
>18.6&nbsp; <font color="#0000FF">How to Serialize Data Without Generating XSD Type Attributes</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.7"
>18.7&nbsp; <font color="#0000FF">Function Callbacks for Customized I/O and HTTP Handling</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.8"
>18.8&nbsp; <font color="#0000FF">HTTP 1.0 and 1.1</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.9"
>18.9&nbsp; <font color="#0000FF">HTTP 307 Temporary Redirect Support</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.10"
>18.10&nbsp; <font color="#0000FF">HTTP GET Support</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.11"
>18.11&nbsp; <font color="#0000FF">HTTP Keep-Alive</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.12"
>18.12&nbsp; <font color="#0000FF">HTTP Chunked Transfer Encoding</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.13"
>18.13&nbsp; <font color="#0000FF">HTTP Buffered Sends</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.14"
>18.14&nbsp; <font color="#0000FF">HTTP Authentication</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.15"
>18.15&nbsp; <font color="#0000FF">HTTP Proxy Authentication</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.16"
>18.16&nbsp; <font color="#0000FF">Speed Improvement Tips</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.17"
>18.17&nbsp; <font color="#0000FF">Timeout Management for Non-Blocking Operations</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.18"
>18.18&nbsp; <font color="#0000FF">Socket Options and Flags</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.19"
>18.19&nbsp; <font color="#0000FF">Secure SOAP Web Services with HTTPS/SSL</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.20"
>18.20&nbsp; <font color="#0000FF">Secure SOAP Clients with HTTPS/SSL</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.21"
>18.21&nbsp; <font color="#0000FF">SSL Authentication Callback</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.22"
>18.22&nbsp; <font color="#0000FF">SSL Certificates</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.23"
>18.23&nbsp; <font color="#0000FF">SSL Hardware Acceleration</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.24"
>18.24&nbsp; <font color="#0000FF">SSL on Windows</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.25"
>18.25&nbsp; <font color="#0000FF">Zlib Compression</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.26"
>18.26&nbsp; <font color="#0000FF">Client-Side Cookie Support</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.27"
>18.27&nbsp; <font color="#0000FF">Server-Side Cookie Support</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.28"
>18.28&nbsp; <font color="#0000FF">Connecting Clients Through Proxy Servers</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.29"
>18.29&nbsp; <font color="#0000FF">FastCGI Support</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.30"
>18.30&nbsp; <font color="#0000FF">How to Create gSOAP Applications With a Small Memory Footprint</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.31"
>18.31&nbsp; <font color="#0000FF">How to Eliminate BSD Socket Library Linkage</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.32"
>18.32&nbsp; <font color="#0000FF">How to Combine Multiple Client and Server Implementations into one Executable</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.33"
>18.33&nbsp; <font color="#0000FF">How to Build a Client or Server in a C++ Code Namespace</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.34"
>18.34&nbsp; <font color="#0000FF">How to Create Client/Server Libraries</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.34.1"
>18.34.1&nbsp; <font color="#0000FF">C++ Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.34.2"
>18.34.2&nbsp; <font color="#0000FF">C Example</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.35"
>18.35&nbsp; <font color="#0000FF">How to Create DLLs</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.35.1"
>18.35.1&nbsp; <font color="#0000FF">Create the Base stdsoap2.dll</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.35.2"
>18.35.2&nbsp; <font color="#0000FF">Creating Client and Server DLLs</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.36"
>18.36&nbsp; <font color="#0000FF">gSOAP Plug-ins</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.36.1"
>18.36.1&nbsp; <font color="#0000FF">The Message Logging and Statistics Plug-in</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.36.2"
>18.36.2&nbsp; <font color="#0000FF">The HTTP GET Plug-in</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.36.3"
>18.36.3&nbsp; <font color="#0000FF">The HTTP MD5 Plug-in</font></a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#tth_sEc18.36.4"
>18.36.4&nbsp; <font color="#0000FF">The HTTP Digest Authentication Plug-in</font></a><br />
</td></tr></table><br></span>
<i>Copyright (C) 2000-2006 Robert A. van Engelen, Genivia, Inc., All Rights Reserved.</i>
<div class="p"><!----></div>
<h2><a name="tth_sEc1">
1</a>&nbsp;&nbsp;<font color="#0000FF">Introduction</font></h2>
<div class="p"><!----></div>
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.
<div class="p"><!----></div>
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.
<div class="p"><!----></div>
<h3><a name="tth_sEc1.1">
1.1</a>&nbsp;&nbsp;<font color="#0000FF">Getting Started</font></h3>
<div class="p"><!----></div>
To start building Web services applications with gSOAP, you need:
<ul>
<li> The gSOAP package from <a href="http://sourceforge.net/projects/gsoap2"><tt>http://sourceforge.net/projects/gsoap2</tt></a>
<div class="p"><!----></div>
</li>
<li> A C or C++ compiler.
<div class="p"><!----></div>
</li>
<li> You may want to install OpenSSL and the Zlib libraries to enable SSL (HTTPS) and compression. These libraries are available for most platforms and are often already installed.
<div class="p"><!----></div>
</li>
</ul>
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).
<div class="p"><!----></div>
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 codes can be transferred to other
platforms and compiled.
<div class="p"><!----></div>
The gSOAP packages available from SourceForge include pre-build tools:
<ul>
<li> The <i>wsdl2h</i> WSDL/schema parser tool.
<div class="p"><!----></div>
</li>
<li> The <i>soapcpp2</i> stub/skeleton compiler.
<div class="p"><!----></div>
</li>
</ul>
Win32 versions of these two are included in the Win32 gSOAP package only.
If you don't have the binaries or if you want to rebuild them, you need
<ul>
<li> A C++ compiler to build <i>wsdl2h</i>.
<div class="p"><!----></div>
</li>
<li> A C compiler and Bison or Yacc to build <i>soapcpp2</i>.
<div class="p"><!----></div>
</li>
<li> A C compiler and Flex or Lex to build <i>soapcpp2</i>.
<div class="p"><!----></div>
</li>
</ul>
Bison and Flex are preferred.
<div class="p"><!----></div>
The tools are used to generate code that is linked with the gSOAP engine
<i>soapcpp2.c</i> (C version) or <i>soapcpp2.cpp</i> (C++ version) and your
application code. The engine is also available as a library <i>libgsoap.a</i> and
<i>libgsoap++.a</i> with separate versions that support SSL. See the
<i>README.txt</i> instructions on how to build these libraries with the
platform-independent gSOAP package's autoconf and automake.
<div class="p"><!----></div>
The gSOAP packages contain numerous examples in the <i>samples</i> directory.
Run <i>make</i> to build the example applications. The examples are also meant
to demonstrate different features of gSOAP. The simplest examples are the
one-liners in <i>samples/oneliners</i>. Indeed, you can write a one-line Web
service with CGI!. A streaming DIME attachment server and client application
demonstrate efficient file exchanges in <i>samples/dime</i>. An SSL-secure Web
server application demonstrates the generation of dynamic content for Web
browsing and Web services functionality at the same time, see
<i>samples/webservice</i>. And much more.
<div class="p"><!----></div>
<h3><a name="tth_sEc1.2">
1.2</a>&nbsp;&nbsp;<font color="#0000FF">Your First Web Service Client Application</font></h3>
<div class="p"><!----></div>
The gSOAP tools minimize application adaptation efforts for building Web
Services. The gSOAP <i>wsdl2h</i> tool imports one or more WSDLs and XML
schemas to generate a header file with the Web service operations and the C/C++
data types used by the services. The gSOAP <i>soapcpp2</i> compiler takes the
header file and generates XML serializers for the data types (<i>soapH.h</i> and
<i>soapC.cpp</i>), the client-side stubs (<i>soapClient.cpp</i>), and server-side
skeletons (<i>soapServer.cpp</i>).
<div class="p"><!----></div>
The gSOAP <i>soapcpp2</i> compiler can also generate WSDL definitions for
implementing a service from scratch, i.e.&nbsp;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.
<div class="p"><!----></div>
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 <i>samples</i> directory
with tool integration in the MSVC++ IDE). For example, to generate code for the
XMethods service listing Web service, we run the <i>wsdl2h</i> tool from the
command line on the URL of the WSDL and use option <i>-o</i> to specify the
output file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ wsdl2h -o XMethodsQuery.h http://www.xmethods.net/wsdl/query.wsdl</i>
</td></tr></table><br></span>
This generates the <i>XMethodsQuery.h</i> header file with Web service
operations and the data types that the service uses. This header file is to be
processed with <i>soapcpp2</i> to generate the stub and/or skeleton code. The
<i>XMethodsQuery.h</i> file includes all documentation, so you can use Doxygen
(<a href="http://www.doxygen.org"><tt>http://www.doxygen.org</tt></a>) to automatically generate the documentation pages for
your development.
<div class="p"><!----></div>
In this example we are developing a C++ API for the XMethods service. By
default, gSOAP assumes you will use C++ with STL. To build without STL, use option
<i>-s</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ wsdl2h -s -o XMethodsQuery.h http://www.xmethods.net/wsdl/query.wsdl</i>
</td></tr></table><br></span>
To build a pure C application, use option <i>-c</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ wsdl2h -c -o XMethodsQuery.h http://www.xmethods.net/wsdl/query.wsdl</i>
</td></tr></table><br></span>
We have not yet generated the stubs for the C/C++ API. To do so, run the <i>soapcpp2</i> compiler:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ soapcpp2 -C -Iimport XMethodsQuery.h</i>
</td></tr></table><br></span>
Where option <i>-C</i> indicates client-side only files (<i>soapcpp2</i>
generates both client and server stubs and skeletons by default). Option
<i>-I</i> is needed to import the <i>stlvector.h</i> file to support STL vectors.
<div class="p"><!----></div>
Suppose we develop a C++ client for the XMethods service. In this case we use
the generated <i>soapXMethodsQuerySoapProxy</i> class and
<i>XMethodsQuerySoap.nsmap</i> XML namespace mapping table to access the Web
service. The <i>soapXMethodsQuerySoapProxy</i> class is a proxy to invoke the
service:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapXMethodsQuerySoapProxy.h" <br />
#include "XMethodsQuerySoap.nsmap" <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;XMethodsQuerySoap service; <br />
&nbsp;&nbsp;&nbsp;ns3__getAllServiceNamesResponse response; <br />
&nbsp;&nbsp;&nbsp;// get all service names from the XMethods database: <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(service.ns3__getAllServiceNames(response) == SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout <tt>&lt;&lt;</tt> "The first XMethods service is: " <tt>&lt;&lt;</tt> (*response._Result<tt>-&gt;</tt>__ptr[0]<tt>-&gt;</tt>name) <tt>&lt;&lt;</tt> std::endl; <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(service.soap, stderr); <br />
}
</td></tr></table><br></i>
The <i>response</i> data structure is defined in <i>XMethodsQuery.h</i>, and
contains a SOAP encoded array (<i>__ptr[n]</i>) of pointers to ID-Name pairs
(<i>__ptr[n]</i><tt>-&gt;</tt><i>id</i> and <i>__ptr[n]</i><tt>-&gt;</tt><i>name</i>). (Note: you may
want to add NULL checks before dereferencing the pointers.)
To complete the build, compile and link the generated <i>soapC.cpp</i>,
<i>soapClient.cpp</i>, and the run-time gSOAP engine <i>stdsoap2.cpp</i> with
your code.
<div class="p"><!----></div>
<h3><a name="tth_sEc1.3">
1.3</a>&nbsp;&nbsp;<font color="#0000FF">Your First Web Service in CGI</font></h3>
<div class="p"><!----></div>
Developing a service application is easy too.
<div class="p"><!----></div>
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 <i>extras</i> directory).
<div class="p"><!----></div>
Our <i>currentTime</i> service only has an output parameter, which is the
current time:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// File: currentTime.h <br />
//gsoap ns service name: currentTime <br />
//gsoap ns service namespace: urn:currentTime <br />
//gsoap ns service location: http://www.yourdomain.com/currentTime.cgi <br />
<b>int</b>&nbsp;ns__currentTime(time_t&amp; response);
</td></tr></table><br></i>
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 (<i>ns</i> in this case) followed by a double underscore
<i>__</i>. This convention is used to resolve namespaces and to avoid name
clashes. The <i>ns</i> namespace prefix is bound to the <i>urn:currentTime</i>
namespace name with the <i>//gsoap</i> directive. The <i>//gsoap</i> directives
are used to set the properties of the service, in this case the name,
namespace, and location endpoint.
<div class="p"><!----></div>
The service implementation for CGI is
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// File: currentTime.cpp <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;// create soap context and serve one CGI-based request: <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); <br />
}
<br />
<b>int</b>&nbsp;ns__currentTime(<b>struct</b>&nbsp;soap *soap, time_t&amp; response) <br />
{ <br />
&nbsp;&nbsp;&nbsp;response = time(0); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
Note that we pass the soap struct with the gSOAP context information to the
service routine, which can be handy to determine properties of the connection
and to dynamically allocate data with <i>soap_malloc(soap, num_bytes)</i> that
will be automatically deleted when the service is finished.
We run the <i>soapcpp2</i> compiler on the header file to generate the
server-side code:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ soapcpp2 -S currentTime.h</i>
</td></tr></table><br></span>
and then compile the CGI binary:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>$ c++ -o currentTime.cgi currentTime.cpp soapC.cpp soapServer.cpp stdsoap2.cpp</i>
</td></tr></table><br></span>
To activate the service, copy the <i>currentTime.cgi</i> binary to your
<i>bin-cgi</i> directory with the proper file permissions.
<div class="p"><!----></div>
The <i>soapcpp2</i> compiler generated the WSDL definitions
<i>currentTime.wsdl</i>. 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
<i>currentTime.h</i> file with the <i>soapcpp2 -C</i> command to generate
client-side code.
<div class="p"><!----></div>
When you contribute a Web service with interesting capabilities, you can
contact www.XMethods.com to publish your service and see it with the client
application for the XMethods service listing you developed in the previous
section.
<div class="p"><!----></div>
<h3><a name="tth_sEc1.4">
1.4</a>&nbsp;&nbsp;<font color="#0000FF">Features</font></h3>
<div class="p"><!----></div>
The highlights of gSOAP are:
<ul>
<li>Unique interoperability features: the gSOAP compiler generates SOAP marshalling routines that (de)serialize native and
user-defined C and C++ data structures.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports WSDL 1.1, SOAP 1.1, SOAP 1.2, SOAP RPC encoding style, and document/literal style.
<div class="p"><!----></div>
</li>
<li>
gSOAP is one of the few SOAP toolkits that support the full range of SOAP 1.1 RPC encoding features
including sparse multi-dimensional arrays and polymorphic types. For example, a remote method with a base class parameter may accept
derived class instances from a client. Derived class instances keep their identity through dynamic binding.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports MIME (SwA), DIME, and MTOM attachments.
<div class="p"><!----></div>
</li>
<li>
gSOAP is the only toolkit that supports <em>streaming</em> DIME attachment transfers, which allows you to exchange binary data of practically unlimited size in the fastest possible way (streaming) while ensuring the usefulness of XML interoperability.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports SOAP-over-UDP.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports IPv4 and IPv6.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports Zlib deflate and gzip compression (for HTTP, TCP/IP, and XML file storage).
<div class="p"><!----></div>
</li>
<li>
gSOAP supports SSL (HTTPS).
<div class="p"><!----></div>
</li>
<li>
gSOAP supports HTTP/1.0, HTTP/1.1 keep-alive, chunking, basic authentication, and digest authentication using a plugin.
<div class="p"><!----></div>
</li>
<li>
gSOAP supports SOAP one-way messaging.
<div class="p"><!----></div>
</li>
<li>
The schema-specific XML pull parser is fast and efficient and does not require intermediate data storage for
demarshalling to save space and time.
<div class="p"><!----></div>
</li>
<li>
The gSOAP <i>soapcpp2</i> compiler includes a WSDL generator for convenient Web Service publishing.
<div class="p"><!----></div>
</li>
<li>
gSOAP includes a WSDL parser <i>wsld2h</i> (WSDL converter to gSOAP header files) for automated client and server development.
<div class="p"><!----></div>
</li>
<li>
Generates source code for stand-alone Web Services and client applications.
<div class="p"><!----></div>
</li>
<li>
Ideal for small devices such as Palm OS, Symbian, Pocket PC, because the memory footprint is small.
<div class="p"><!----></div>
</li>
<li>
Ideal for building web services that are compute-intensive and are therefore best written in C and C++.
<div class="p"><!----></div>
</li>
<li>
Platform independent: Windows, Unix, Linux, Mac OS X, Pocket PC, Palm OS, Symbian, etc.
<div class="p"><!----></div>
</li>
<li>
Supports serializing of application's native C and C++ data structures, which allows you to save and load of XML serialized data structures to and from files.
<div class="p"><!----></div>
</li>
<li>
Selective input and output buffering is used to increase efficiency, but full message buffering to determine HTTP message length
is not used. Instead, a three-phase serialization method is used to determine message length. As a result, large data sets
such as base64-encoded images can be transmitted with or without DIME attachments by small-memory devices such as PDAs.
<div class="p"><!----></div>
</li>
<li>
Supports C++ single class inheritance, dynamic binding, overloading, arbitrary pointer structures such as lists, trees, graphs,
cyclic graphs, fixed-size arrays, (multi-dimensional) dynamic arrays, enumerations, built-in XSD Schema types including
base64Binary encoding, and hexBinary encoding.
<div class="p"><!----></div>
</li>
<li>
No need to rewrite existing C/C++ applications for Web service deployment. However, parts of an application that use unions,
pointers to sequences of elements in memory, and <i><b>void</b>*</i> need to be modified, but <b>only</b> if the data structures that
adopt them are required to be serialized or deserialized as part of a remote method invocation.
<div class="p"><!----></div>
</li>
<li>
Three-phase marshalling: 1) analysis of pointers, single-reference, multi-reference, and cyclic data structures, 2) HTTP
message-length determination, and 3) serialization as per SOAP 1.1 encoding style or user-defined encoding styles.
<div class="p"><!----></div>
</li>
<li>
Two-phase demarshalling: 1) SOAP parsing and decoding, which involves the reconstruction of multi-reference and cyclic data
structures from the payload, and 2) resolution of "forward" pointers (i.e. resolution of the forward <tt>href</tt> attributes in SOAP).
<div class="p"><!----></div>
</li>
<li>
Full and customizable SOAP Fault processing (client receive and service send).
<div class="p"><!----></div>
</li>
<li>
Customizable SOAP Header processing (send and receive), which for example enables easy transaction processing for the service to
keep state information.
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h2><a name="tth_sEc2">
2</a>&nbsp;&nbsp;<font color="#0000FF">Notational Conventions</font></h2>
<div class="p"><!----></div>
The typographical conventions used by this document are:
<dl compact="compact">
<dt><b><span class="roman"><i>Sans serif or italics font</i></b></dt>
<dd> denotes C and C++ source code, file names, and shell/batch commands.</span></dd>
<dt><b><i><b>Bold font</b></i></b></dt>
<dd> denotes C and C++ keywords.</dd>
<dt><b><tt>Courier font</tt></b></dt>
<dd> denotes HTTP header content, HTML, XML, XML Schema content and WSDL content.</dd>
<dt><b><span class="roman"><font size="+1"><span class="roman">[</span></font>Optional<font size="+1"><span class="roman">]</span></font></b></dt>
<dd> denotes an optional construct.</span></dd>
</dl>
<div class="p"><!----></div>
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.
<div class="p"><!----></div>
<h2><a name="tth_sEc3">
3</a>&nbsp;&nbsp;<font color="#0000FF">Differences Between gSOAP Versions 2.4 (and Earlier) and 2.5</font></h2>
<div class="p"><!----></div>
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 <i>wsdl2h</i> 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 <i>-e</i> 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.
<div class="p"><!----></div>
<h2><a name="tth_sEc4">
4</a>&nbsp;&nbsp;<font color="#0000FF">Differences Between gSOAP Versions 2.1 (and Earlier) and 2.2</font></h2>
<div class="p"><!----></div>
You should read this section only if you are upgrading from gSOAP 2.1 to 2.2 and later.
<div class="p"><!----></div>
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 <i>soap_disable_X</i>
and <i>soap_enable_X</i>, where <i>X</i> is a particular feature, are
deprecated. See Section&nbsp;<a href="#sec:flags">8.12</a> for more details.
<div class="p"><!----></div>
<h2><a name="tth_sEc5">
5</a>&nbsp;&nbsp;<font color="#0000FF">Differences Between gSOAP Versions 1.X and 2.X</font></h2>
<div class="p"><!----></div>
You should read this section only if you are upgrading from gSOAP 1.X to 2.X.
<div class="p"><!----></div>
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>gSOAP 1.X</b></font> </td><td><font color="#FF0000"><b>gSOAP 2.X</b></font> </td></tr>
<tr><td>soapcpp </td><td>soapcpp2 </td></tr>
<tr><td>soapcpp.exe </td><td>soapcpp2.exe </td></tr>
<tr><td>stdsoap.h </td><td>stdsoap2.h </td></tr>
<tr><td>stdsoap.c </td><td>stdsoap2.c </td></tr>
<tr><td>stdsoap.cpp </td><td>stdsoap2.cpp </td></tr></table>
</td></tr></table><br></span>
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 <i>stdsoap2.c[pp]</i> (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, <b>all</b> 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 <b>always</b> the first parameter of any gSOAP function.
<div class="p"><!----></div>
The gSOAP runtime environment is stored in a <i><b>struct</b>&nbsp;soap</i> type. A <i><b>struct</b></i> 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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function</b></font> </td><td width="351"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soap_init(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Initializes a runtime environment (required only once) </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_new()</i> </td><td width="351">Allocates, initializes, and returns a pointer to a runtime environment </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_copy(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Allocates a new runtime environment and copies contents of
the argument environment such that the new environment does not share any data
with the original environment </td></tr></table>
</td></tr></table><br></span>
An environment can be reused as many times as necessary and does not need to be reinitialized in doing so.
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); // initialize runtime environment <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method1(&amp;soap, ...); // make a remote call <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method2(&amp;soap, ...); // make another remote call <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // remove deserialized class instances (C++ only) <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // clean up and remove deserialized data <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // detach environment (last use and no longer in scope)<br />
&nbsp;&nbsp;&nbsp;... <br />
}
</td></tr></table><br></i>
The runtime environment can also be heap allocated:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap = soap_new(); // allocate and initialize runtime environment <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap) // couldn't allocate: stop <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method1(soap, ...); // make a remote call <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method2(soap, ...); // make another remote call <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_destroy(soap); // remove deserialized class instances (C++ only) <br />
&nbsp;&nbsp;&nbsp;soap_end(soap); // clean up and remove deserialized data <br />
&nbsp;&nbsp;&nbsp;soap_done(soap); // detach runtime environment <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;free(soap); // deallocate runtime environment <br />
}
</td></tr></table><br></i>
A service need to allocate and initialize an environment before calling <i>soap_serve</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); <br />
}
</td></tr></table><br></i>
Or alternatively:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); <br />
}
</td></tr></table><br></i>
The <i>soap_serve</i> dispatcher handles one request or multiple requests when HTTP keep-alive is enabled (with the <i>SOAP_IO_KEEPALIVE</i> flag see Section&nbsp;<a href="#sec:keepalive">18.11</a>).
<div class="p"><!----></div>
A service can use multi-threading to handle requests while running some other code that invokes remote methods:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap1, soap2; <br />
&nbsp;&nbsp;&nbsp;pthread_t tid; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap1); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_bind(&amp;soap1, host, port, backlog) &lt; 0) exit(1); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_accept(&amp;soap1) &lt; 0) exit(1); <br />
&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid, NULL, (<b>void</b>*(*)(<b>void</b>*))soap_serve, (<b>void</b>*)&amp;soap1); <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap2); <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method(&amp;soap2, ...); // make a remote call <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap2); <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;pthread_join(tid, NULL); // wait for thread to terminate <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap1); // release its data <br />
}
</td></tr></table><br></i>
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).
<div class="p"><!----></div>
Section&nbsp;<a href="#sec:mt">7.2.4</a> presents a multi-threaded stand-alone Web Service that handles multiple SOAP requests by spawning a thread for each request.
<div class="p"><!----></div>
<h2><a name="tth_sEc6">
6</a>&nbsp;&nbsp;<font color="#0000FF">Interoperability</font></h2>
<div class="p"><!----></div>
gSOAP interoperability has been verified with the following SOAP implementations and toolkits:
<dl compact="compact">
<dt><b>Apache 2.2</b></dt>
<dd></dd>
<dt><b>Apache Axis</b></dt>
<dd></dd>
<dt><b>ASP.NET</b></dt>
<dd></dd>
<dt><b>Cape Connect</b></dt>
<dd></dd>
<dt><b>Delphi</b></dt>
<dd></dd>
<dt><b>easySOAP++</b></dt>
<dd></dd>
<dt><b>eSOAP</b></dt>
<dd></dd>
<dt><b>Frontier</b></dt>
<dd></dd>
<dt><b>GLUE</b></dt>
<dd></dd>
<dt><b>Iona XMLBus</b></dt>
<dd></dd>
<dt><b>kSOAP</b></dt>
<dd></dd>
<dt><b>MS SOAP</b></dt>
<dd></dd>
<dt><b>Phalanx</b></dt>
<dd></dd>
<dt><b>SIM</b></dt>
<dd></dd>
<dt><b>SOAP::Lite</b></dt>
<dd></dd>
<dt><b>SOAP4R</b></dt>
<dd></dd>
<dt><b>Spray</b></dt>
<dd></dd>
<dt><b>SQLData</b></dt>
<dd></dd>
<dt><b>Wasp Adv.</b></dt>
<dd></dd>
<dt><b>Wasp C++</b></dt>
<dd></dd>
<dt><b>White Mesa</b></dt>
<dd></dd>
<dt><b>xSOAP</b></dt>
<dd></dd>
<dt><b>ZSI</b></dt>
<dd></dd>
<dt><b>4S4C</b></dt>
<dd></dd>
</dl>
<div class="p"><!----></div>
<h2><a name="tth_sEc7">
7</a>&nbsp;&nbsp;<font color="#0000FF">Quick User Guide</font></h2>
<div class="p"><!----></div>
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.&nbsp;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.
<div class="p"><!----></div>
<h3><a name="tth_sEc7.1">
7.1</a>&nbsp;&nbsp;<font color="#0000FF">How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Clients</font></h3><a name="sec:client">
</a>
<div class="p"><!----></div>
In general, the implementation of a SOAP client application requires a <b>
stub</b> 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.
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler is a <b>preprocessor</b> 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++ <b>header file</b>. The
header file can be generated from a WSDL (Web Service Description Language)
documentation of a service with the gSOAP WSDL parser.
<div class="p"><!----></div>
Consider the following command (entered at the command prompt):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
$ wsdl2h -o quote.h http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl
</td></tr></table><br></span>
This generates the file <i>quote.h</i> in C++ format from the WSDL at the specified URL.
<div class="p"><!----></div>
To generate a header file to develop a pure C client application, issue the command:
Consider the following command (entered at the command prompt):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
$ wsdl2h -c -o quote.h http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl
</td></tr></table><br></span>
For more details on the WSDL parser and its options, see&nbsp;<a href="#sec:wsdlin">7.2.10</a>.
<div class="p"><!----></div>
The <i>quote.h</i> header file is then processed by the gSOAP compiler to generate the stubs to develop client applications
(and skeletons to develop a service).
<div class="p"><!----></div>
The SOAP service methods are specified in the header file as <b>function
prototypes</b>. 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.
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler also generates <b>skeleton</b> 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).
<div class="p"><!----></div>
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 <b>
serializers</b> and <b>deserializers</b> 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.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.1">
7.1.1</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example1">
</a>
<div class="p"><!----></div>
The <i>getQuote</i> remote method of XMethods Delayed Stock Quote service (defined in the <i>quote.h</i> 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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td>Endpoint URL: </td><td><tt>http://services.xmethods.net:80/soap</tt> </td></tr>
<tr><td>SOAP action: </td><td>"" (2 quotes) </td></tr>
<tr><td>Remote method namespace: </td><td><tt>urn:xmethods-delayed-quotes</tt> </td></tr>
<tr><td>Remote method name: </td><td><tt>getQuote</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Input parameter: </td><td><tt>symbol</tt> of type <tt>xsd:string</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Output parameter: </td><td><tt>Result</tt> of type <tt>xsd:float</tt>
</td></tr></table>
</td></tr></table><br></span>
The following <i>getQuote.h</i> 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):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns1 service name: net_DOTxmethods_DOTservices_DOTstockquote_DOTStockQuoteBinding <br />
//gsoap ns1 service type: net_DOTxmethods_DOTservices_DOTstockquote_DOTStockQuotePortType <br />
//gsoap ns1 service port: http://66.28.98.121:9090/soap <br />
//gsoap ns1 service namespace: urn:xmethods-delayed-quotes <br />
//gsoap ns1 service documentation: Definitions generated by the gSOAP WSDL parser 1.0 <br />
// Service net.xmethods.services.stockquote.StockQuoteService : net.xmethods.services.stockquote.StockQuote web service <br />
<br />
//gsoap ns1 service method-style: getQuote rpc <br />
//gsoap ns1 service method-encoding: getQuote http://schemas.xmlsoap.org/soap/encoding/ <br />
//gsoap ns1 service method-action: getQuote urn:xmethods-delayed-quotes#getQuote <br />
<b>int</b>&nbsp;ns1__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result);
</td></tr></table><br></i>
The header file essentially specifies the service details in C/C++ with
directives for the gSOAP compiler. The remote method is declared as a
<i>ns1__getQuote</i> <b>function prototype</b> 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.
<div class="p"><!----></div>
The Delayed Stock Quote service description requires that the <b>input
parameter</b> of the <i>getQuote</i> remote method is a <i>symbol</i> parameter of
type string. The description also indicates that the <i>Result</i> <b>output
parameter</b> is a floating point number that represents the current unit price of
the stock in dollars. The gSOAP compiler uses the convention the <b>last
parameter</b> 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 (<i>&amp;</i>) 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
<i><b>int</b></i>, whose value indicates to the caller whether the connection to a
SOAP Web service was successful or resulted in an exception, see
Section&nbsp;<a href="#sec:errcodes">9.2</a> for the error codes.
<div class="p"><!----></div>
The use of the namespace prefix <i>ns1__</i> in the remote method name in the
function prototype declaration is discussed in detail in&nbsp;<a href="#sec:namespace">7.1.2</a>.
Basically, a namespace prefix is distinguished by a <b>pair of underscores</b>
in the function name, as in <i>ns1__getQuote</i> where <i>ns1</i> is the
namespace prefix and <i>getQuote</i> 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&nbsp;<a href="#sec:idtrans">9.3</a>.)
<div class="p"><!----></div>
The gSOAP compiler is invoked from the command line with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 getQuote.h</i>
</td></tr></table><br></span>
The compiler generates the stub routine for the <i>getQuote</i> remote method
specified in the <i>getQuote.h</i> 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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_call_ns1__getQuote(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*URL, <b>char</b>&nbsp;*action, <b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result);
</td></tr></table><br></i>
The stub routine is saved in <i>soapClient.cpp</i>. The file <i>soapC.cpp</i>
contains the <b>serializer</b> and <b>deserializer</b> routines for the data
types used by the stub. You can use option <i>-c</i> for the <i>soapcpp2</i> compiler to
generate pure C code.
<div class="p"><!----></div>
Note that the parameters of the <i>soap_call_ns1__getQuote</i> function are
identical to the <i>ns1__getQuote</i> function prototype with three additional
input parameters: <i>soap</i> must be a valid pointer to a gSOAP runtime
environment, <i>URL</i> is the SOAP Web service <b>endpoint URL</b> passed as a
string, and <i>action</i> is a string that denotes the <b>SOAP action</b>
required by the Web service.
Note that the XMethods Delayed Stock Quote service endpoint URL is
<tt>http://66.28.98.121:9090/soap</tt> and the SOAP action required is
<tt>""</tt> (two quotes). You can change the endpoint and action dynamically. The endpoint and action are the second and third parameters of the <i>soap_call_ns1__getQuote</i>. When NULL, the values specified in the header file will be used.
<div class="p"><!----></div>
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include <tt>"soapH.h"</tt> // obtain the generated stub <br />
#include <tt>"net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding.nsmap"</tt> // obtain the namespace mapping table <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; // gSOAP runtime environment <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;quote; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); // initialize runtime environment (only once) <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns1__getQuote(&amp;soap, NULL, NULL, <tt>"IBM"</tt>, &amp;quote) == SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout &lt;&lt; "Current IBM Stock Quote = " &lt;&lt; quote &lt;&lt; std::endl; <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;// an error occurred <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // display the SOAP fault message on the stderr stream <br />
&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // delete deserialized class instances (for C++ only) <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // remove deserialized data and clean up <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // detach the gSOAP environment <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
When successful, the stub returns <i>SOAP_OK</i> and
<i>quote</i> contains the latest stock quote. Otherwise, an error occurred and
the SOAP fault is displayed with the <i>soap_print_fault</i> function.
<div class="p"><!----></div>
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include <tt>"soapnet_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBindingProxy.h"</tt> // get proxy <br />
#include <tt>"net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding.nsmap"</tt> // obtain the namespace mapping table <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;net q; // "net" is the proxy class with a name that is the short name of the service <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;r; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(q.ns1__getQuote("IBM", r) == SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout &lt;&lt; r &lt;&lt; std::endl; <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(q.soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
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
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns1 service name: net_DOT_xmethods_DOT_services_DOT_stockquote_DOT_StockQuoteBinding
</td></tr></table><br></i>
to use a more suitable name. The name will control the file name of the proxy class file and the XML namespace mapping table.
<div class="p"><!----></div>
The following functions can be used to explicitly setup a gSOAP runtime environment (<i><b>struct</b>&nbsp;soap</i>):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function</b></font> </td><td width="351"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soap_init(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Initializes a runtime environment (required only once) </td></tr>
<tr><td><i>soap_init1(<b>struct</b>&nbsp;soap *soap, soap_mode iomode)</i> </td><td width="351">Initializes a runtime environment and set in/out mode flags </td></tr>
<tr><td><i>soap_init2(<b>struct</b>&nbsp;soap *soap, soap_mode imode, soap_mode omode)</i> </td><td width="351">Initializes a runtime environment and set separate in/out mode flags </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_new()</i> </td><td width="351">Allocates, initializes, and returns a pointer to a runtime environment </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_new1(soap_mode iomode)</i> </td><td width="351">Allocates, initializes, and returns a pointer to a runtime environment and set in/out mode flags </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_new2(soap_mode imode, soap_mode omode)</i> </td><td width="351">Allocates, initializes, and returns a pointer to a runtime environment and set separate in/out mode flags </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_copy(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Allocates a new runtime environment and copies contents of
the argument environment such that the new environment does not share data with the argument environment </td></tr>
<tr><td><i>soap_done(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Reset, close communications, and remove callbacks </td></tr></table>
</td></tr></table><br></span>
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.
<div class="p"><!----></div>
When the example client application is invoked, the SOAP request is performed by the stub routine <i>soap_call_ns1__getQuote</i>, which
generates the following SOAP RPC request message:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
POST /soap HTTP/1.1 <br />
Host: services.xmethods.net <br />
Content-Type: text/xml <br />
Content-Length: 529 <br />
SOAPAction: "" <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns1="urn:xmethods-delayed-quotes" <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;ns1:getQuote&#62; <br />
&lt;symbol&#62;IBM&lt;/symbol&#62; <br />
&lt;/ns1:getQuote&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
The XMethods Delayed Stock Quote service responds with the SOAP response message:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
HTTP/1.1 200 OK <br />
Date: Sat, 25 Aug 2001 19:28:59 GMT <br />
Content-Type: text/xml <br />
Server: Electric/1.0 <br />
Connection: Keep-Alive <br />
Content-Length: 491 <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/&#187; <br />
&lt;soap:Body&#62; <br />
&lt;n:getQuoteResponse xmlns:n="urn:xmethods-delayed-quotes&#187; <br />
&lt;Result xsi:type="xsd:float&#187;41.81&lt;/Result&#62; <br />
&lt;/n:getQuoteResponse&#62; <br />
&lt;/soap:Body&#62; <br />
&lt;/soap:Envelope&#62;
</td></tr></table><br></tt>
The server's SOAP RPC response is parsed by the stub. The stub routine further demarshalls the data of <tt>Result</tt>
element of the SOAP response and stores it in the <i>quote</i> parameter of <i>soap_call_ns1__getQuote</i>.
<div class="p"><!----></div>
A client program can invoke a remote method at any time and multiple times if necessary. Consider for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
... <br />
<b>struct</b>&nbsp;soap soap; <br />
<b>float</b>&nbsp;quotes[3]; char *myportfolio[] = {<tt>"IBM"</tt>, <tt>"MSDN"</tt>}; <br />
soap_init(&amp;soap); // need to initialize only once <br />
<b>for</b>&nbsp;(<b>int</b>&nbsp;i = 0; i &lt; 3; i++) <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns1__getQuote(&amp;soap, <tt>"http://services.xmethods.net:80/soap"</tt>, <tt>""</tt>, myportfolio[i], &amp;quotes[i]) != SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
<b>if</b>&nbsp;(soap.error) // an error occurred <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
soap_end(&amp;soap); // clean up all deserialized data <br />
...
</td></tr></table><br></i>
This client composes an array of stock quotes by calling the <i>ns1__getQuote</i> stub routine for each symbol in a portfolio array.
<div class="p"><!----></div>
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.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.2">
7.1.2</a>&nbsp;&nbsp;<font color="#0000FF">Namespace Considerations</font></h4><a name="sec:namespace">
</a>
<div class="p"><!----></div>
The declaration of the <i>ns1__getQuote</i> function prototype (discussed in the previous section) uses the namespace prefix
<i>ns1__</i> of the remote method namespace, which is distinguished by a <b>pair of underscores</b> 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.&nbsp;to distinguish identical remote method names used
by different services.
<div class="p"><!----></div>
Note that the XML response of the XMethods Delayed Stock Quote service example uses the <b>namespace prefix</b> <tt>n</tt> which is
bound to the <b>namespace name</b> <tt>urn:xmethods-delayed-quotes</tt> through the <tt>xmlns:n="urn:xmethods-delayed-quotes</tt>
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 <b>namespace mapping table</b> 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 <b>not</b> 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&nbsp;<a href="#sec:directives">18.2</a>.
<div class="p"><!----></div>
The namespace mapping table for the Delayed Stock Quote client is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name"} <br />
&nbsp;&nbsp;&nbsp;{<font color="#FF0000">"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"</font>}, // MUST be first <br />
&nbsp;&nbsp;&nbsp;{<font color="#0000FF">"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"</font>}, // MUST be second <br />
&nbsp;&nbsp;&nbsp;{<font color="#FF00FF">"xsi", "http://www.w3.org/2001/XMLSchema-instance"</font>}, // MUST be third <br />
&nbsp;&nbsp;&nbsp;{<font color="#00FFFF">"xsd", "http://www.w3.org/2001/XMLSchema"</font>}, // 2001 XML Schema <br />
&nbsp;&nbsp;&nbsp;{<font color="#00FF00">"ns1", "urn:xmethods-delayed-quotes"</font>}, // given by the service description <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} // end of table <br />
};
</td></tr></table><br></i>
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 <tt>ns1</tt>, which is bound to <tt>urn:xmethods-delayed-quotes</tt> by the namespace mapping table shown
above, is used by the generated stub routine to encode the <i>getQuote</i> request. This is performed automatically by the gSOAP
compiler by using the <i>ns1</i> prefix of the <i>ns1__getQuote</i> method name specified in the <i>getQuote.h</i> header file. In
general, if a function name of a remote method, <i><b>struct</b></i> name, <i><b>class</b></i> name, <i><b>enum</b></i> name, or field name of a
<i><b>struct</b></i> or <i><b>class</b></i> has a pair of underscores, the name has a namespace prefix that must be defined in the namespace
mapping table.
<div class="p"><!----></div>
The namespace mapping table will be output as part of the SOAP Envelope by the stub routine. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Envelope xmlns:<font color="#FF0000">SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"</font> <br />
&nbsp;&nbsp;&nbsp;xmlns:<font color="#0000FF">SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"</font> <br />
&nbsp;&nbsp;&nbsp;xmlns:<font color="#FF00FF">xsi="http://www.w3.org/2001/XMLSchema-instance"</font> <br />
&nbsp;&nbsp;&nbsp;xmlns:<font color="#00FFFF">xsd="http://www.w3.org/2001/XMLSchema"</font> <br />
&nbsp;&nbsp;&nbsp;xmlns:<font color="#00FF00">ns1="urn:xmethods-delayed-quotes"</font> <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle=<font color="#0000FF">"http://schemas.xmlsoap.org/soap/encoding/"</font>&#62; <br />
...
</td></tr></table><br></tt>
The namespace bindings will be used by a SOAP service to validate the SOAP request.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.3">
7.1.3</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example2">
</a>
<div class="p"><!----></div>
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "getQuote.h": <br />
<b>int</b>&nbsp;ns1__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result); <br />
<b>int</b>&nbsp;ns2__getQuote(<b>char</b>&nbsp;*ticker, <b>char</b>&nbsp;*&amp;quote);
</td></tr></table><br></i>
Recall that the namespace prefix is always separated from the name of a remote method by a pair of underscores (<i>__</i>).
<div class="p"><!----></div>
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.
<div class="p"><!----></div>
The namespace prefix convention can also be applied to <i><b>class</b></i> declarations that contain SOAP compound values
that share the same name but have different namespaces that refer to different XML Schemas. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;<font color="#FF0000">e__Address</font> // an electronic address <br />
{ <br />
&nbsp;&nbsp;&nbsp;char *email; <br />
&nbsp;&nbsp;&nbsp;char *url; <br />
}; <br />
<b>class</b>&nbsp;<font color="#0000FF">s__Address</font> // a street address <br />
{ <br />
&nbsp;&nbsp;&nbsp;char *street; <br />
&nbsp;&nbsp;&nbsp;int number; <br />
&nbsp;&nbsp;&nbsp;char *city; <br />
};
</td></tr></table><br></i>
The namespace prefix is separated from the name of a data type by a pair of underscores (<i>__</i>).
<div class="p"><!----></div>
An instance of <i><font color="#FF0000">e__Address</font></i> is encoded by the generated serializer for this type as an Address element with namespace prefix <i><font color="#FF0000">e</font></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font color="#FF0000">e:Address</font> xsi:type="<font color="#FF0000">e:Address</font>"&#62; <br />
&lt;email xsi:type="string"&#62;me@home&lt;/email&#62; <br />
&lt;url xsi:type="string"&#62;www.me.com&lt;/url&#62; <br />
&lt;/<font color="#FF0000">e:Address</font>&#62;
</td></tr></table><br></tt>
While an instance of <i><font color="#0000FF">s__Address</font></i> is encoded by the generated serializer for this type as an Address element with namespace prefix <i><font color="#0000FF">s</font></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font color="#0000FF">s:Address</font> xsi:type="<font color="#0000FF">s:Address</font>"&#62; <br />
&lt;street xsi:type="string"&#62;Technology Drive&lt;/street&#62; <br />
&lt;number xsi:type="int"&#62;5&lt;/number&#62; <br />
&lt;city xsi:type="string"&#62;Softcity&lt;/city&#62; <br />
&lt;/<font color="#0000FF">s:Address</font>&#62;
</td></tr></table><br></tt>
The namespace mapping table of the client program must have entries for <i><font color="#FF0000">e</font></i> and <i><font color="#0000FF">s</font></i> that refer to the XML Schemas of the data types:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;{"<font color="#FF0000">e</font>", "http://www.me.com/schemas/electronic-address"}, <br />
&nbsp;&nbsp;&nbsp;{"<font color="#0000FF">s</font>", "http://www.me.com/schemas/street-address"}, <br />
...
</td></tr></table><br></i>
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.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.4">
7.1.4</a>&nbsp;&nbsp;<font color="#0000FF">How to Generate C++ Client Proxy Classes</font></h4><a name="sec:proxy">
</a>
<div class="p"><!----></div>
Proxy classes for C++ client applications are automatically generated by the gSOAP compiler.
To illustrate the generation of a proxy class, the <i>getQuote.h</i> 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.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Content of file <tt>"getQuote.h"</tt>: <br />
//gsoap ns1 service name: Quote <br />
//gsoap ns1 service location: http://services.xmethods.net/soap <br />
//gsoap ns1 service namespace: urn:xmethods-delayed-quotes <br />
//gsoap ns1 service style: rpc <br />
//gsoap ns1 service encoding: encoded <br />
//gsoap ns1 service method-action: getQuote "" <br />
<b>int</b>&nbsp;ns1__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result);
</td></tr></table><br></i>
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 <i>soapcpp2</i> creates a new file <i>soapQuoteProxy.h</i> with the
following contents:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
<b>class</b>&nbsp;Quote <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap; <br />
&nbsp;&nbsp;&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint; <br />
&nbsp;&nbsp;&nbsp;Quote() { soap = soap_new(); endpoint = "http://services.xmethods.net/soap"; }; <br />
&nbsp;&nbsp;&nbsp;~Quote() { <b>if</b>&nbsp;(soap) { soap_destroy(soap); soap_end(soap); soap_done(soap); free((void*)soap); }}; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result) { <b>return</b>&nbsp;soap ? soap_call_ns1__getQuote(soap, endpoint, "", symbol, Result) : SOAP_EOM; }; <br />
};
</td></tr></table><br></i>
The gSOAP environment and endpoint are declared public to enable access for run-time customization.
<div class="p"><!----></div>
This generated proxy class can be included into a client application together with the generated namespace table as shown in this example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapQuoteProxy.h" // get proxy <br />
#include "Quote.nsmap" // get namespace bindings <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;Quote q; <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;r; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(q.ns1__getQuote("IBM", r) == SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout &lt;&lt; r &lt;&lt; std::endl; <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(q.soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
The <i>Quote</i> constructor allocates and initializes a gSOAP environment for the instance.
All the HTTP and SOAP/XML processing is hidden and performed on the background.
<div class="p"><!----></div>
You can use soapcpp2 compiler option <i>-n</i> together with <i>-p</i> 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&nbsp;<a href="#sec:options">8.1</a> and&nbsp;<a href="#sec:dylibs">18.34</a>, and you can use a C++ code <i><b>namespace</b></i> to create a namespace qualified proxy class, see Section&nbsp;<a href="#sec:codenamespace">18.33</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.5">
7.1.5</a>&nbsp;&nbsp;<font color="#0000FF">XSD Type Encoding Considerations</font></h4><a name="sec:encoding">
</a>
<div class="p"><!----></div>
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 <i><b>typedef</b></i> definitions in
the header file input to the gSOAP compiler. The type name defined by a <i><b>typedef</b></i> definition corresponds to an XML Schema
type (XSD type). For example, the following <i><b>typedef</b></i> declarations
define various built-in XSD types implemented as primitive C/C++ types:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of header file: <br />
... <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; // encode xsd__string value as the <span class="roman"><tt>xsd:string</tt></span> schema type <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__anyURI; // encode xsd__anyURI value as the <span class="roman"><tt>xsd:anyURI</tt></span> schema type <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; // encode xsd__float value as the <span class="roman"><tt>xsd:float</tt></span> schema type <br />
<b>typedef</b>&nbsp;<b>long</b>&nbsp;xsd__int; // encode xsd__int value as the <span class="roman"><tt>xsd:int</tt></span> schema type <br />
<b>typedef</b>&nbsp;<b>bool</b>&nbsp;xsd__boolean; // encode xsd__boolean value as the <span class="roman"><tt>xsd:boolean</tt></span> schema type <br />
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__positiveInteger; // encode xsd__positiveInteger value as the <span class="roman"><tt>xsd:positiveInteger</tt></span> schema type<br />
...
</td></tr></table><br></i>
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 <i>typedef</i>ed 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 <i><b>typedef</b></i>
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&nbsp;<a href="#sec:primclass">10.2.2</a> for alternative class
implementations of primitive XSD types which allows for the marshalling of polymorphic primitive types).
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.6">
7.1.6</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example3">
</a>
<div class="p"><!----></div>
Reconsider the <i>getQuote</i> example, now rewritten with explicit XSD types to illustrate the effect:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*<font color="#FF0000">xsd__string</font>; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;<font color="#0000FF">xsd__float</font>; <br />
<b>int</b>&nbsp;<font color="#00FF00">ns1__getQuote</font>(<font color="#FF0000">xsd__string</font> <font color="#FF00FF">symbol</font>, <font color="#0000FF">xsd__float</font> &amp;<font color="#00FFFF">Result</font>);
</td></tr></table><br></i>
This header file is compiled by the gSOAP stub and skeleton compiler and the compiler generates source code for the function
<i>soap_call_ns1__getQuote</i>, which is identical to the "old" proxy:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_call_ns1__getQuote(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*URL, <b>char</b>&nbsp;*action, <b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result);
</td></tr></table><br></i>
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.
<div class="p"><!----></div>
For example, when the client application calls the proxy, the proxy produces a SOAP request with an <tt>xsd:string</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;<font color="#00FF00">ns1:getQuote</font>&#62;&lt;<font color="#FF00FF">symbol</font> xsi:type="<font color="#FF0000">xsd:string</font>"&#62;IBM&lt;/<font color="#FF00FF">symbol</font>&#62; <br />
&lt;/<font color="#00FF00">ns1:getQuote</font>&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
...
</td></tr></table><br></tt>
The service response is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;soap:Body&#62; <br />
&lt;<font color="#00FF00">n:getQuote</font>Response xmlns:n="urn:xmethods-delayed-quotes&#187; <br />
&lt;<font color="#00FFFF">Result</font> xsi:type="<font color="#0000FF">xsd:float</font>&#187;41.81&lt;/<font color="#00FFFF">Result</font>&#62; <br />
&lt;/<font color="#00FF00">n:getQuote</font>Response&#62; <br />
&lt;/soap:Body&#62; <br />
...
</td></tr></table><br></tt>
The validation of this service response by the stub routine takes place by matching the namespace names (URIs) that are bound to the
<tt>xsd</tt> namespace prefix. The stub also expects the <tt>getQuoteResponse</tt> element to be associated with URI
<tt>urn:xmethods-delayed-quotes</tt> through the binding of the namespace prefix <tt>ns1</tt> in the namespace mapping table. The
service response uses namespace prefix <tt>n</tt> for the <tt>getQuoteResponse</tt> element. This namespace prefix is bound to the same
URI <tt>urn:xmethods-delayed-quotes</tt> 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.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.7">
7.1.7</a>&nbsp;&nbsp;<font color="#0000FF">How to Change the Response Element Name</font></h4><a name="sec:response">
</a>
<div class="p"><!----></div>
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 "<tt>Response</tt>". For example, the response element of <tt>getQuote</tt> is
<tt>getQuoteResponse</tt>.
<div class="p"><!----></div>
The response element name can be specified explicitly using a <i><b>struct</b></i> or <i><b>class</b></i> declaration in the header file. The
<i><b>struct</b></i> or <i><b>class</b></i> 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 <i><b>struct</b></i> or <i><b>class</b></i>. The use of a <i><b>struct</b></i> or a
<i><b>class</b></i> for the service response is fully SOAP 1.1 compliant. In fact, the absence of a <i><b>struct</b></i> or <i><b>class</b></i>
indicates to the gSOAP compiler to automatically generate a <i>struct</i> for the response which is internally used by a stub.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.8">
7.1.8</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example4">
</a>
<div class="p"><!----></div>
Reconsider the <i>getQuote</i> remote method specification which can be rewritten with an explicit declaration of a SOAP response
element as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*<font color="#FF0000">xsd__string</font>; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;<font color="#0000FF">xsd__float</font>; <br />
<b>struct</b>&nbsp;<font color="#FFFF00">ns1__getQuoteResponse</font> {<font color="#0000FF">xsd__float</font> <font color="#00FFFF">Result</font>;}; <br />
<b>int</b>&nbsp;<font color="#00FF00">ns1__getQuote</font>(<font color="#FF0000">xsd__string</font> <font color="#FF00FF">symbol</font>, <b>struct</b>&nbsp;<font color="#FFFF00">ns1__getQuoteResponse</font> &amp;r);
</td></tr></table><br></i>
The SOAP request is the same as before:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;<font color="#00FF00">ns1:getQuote</font>&#62;&lt;<font color="#FF00FF">symbol</font> xsi:type="<font color="#FF0000">xsd:string</font>"&#62;IBM&lt;/<font color="#FF00FF">symbol</font>&#62; <br />
&lt;/<font color="#00FF00">ns1:getQuote</font>&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
...
</td></tr></table><br></tt>
The difference is that the service response is required to match the specified <i>getQuoteResponse</i> name and its namespace URI:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;soap:Body&#62; <br />
&lt;<font color="#FFFF00">n:getQuoteResponse</font> xmlns:n='urn:xmethods-delayed-quotes'&#62; <br />
&lt;<font color="#00FFFF">Result</font> xsi:type='<font color="#0000FF">xsd:float</font>'&#62;41.81&lt;/<font color="#00FFFF">Result</font>&#62; <br />
&lt;/<font color="#FFFF00">n:getQuoteResponse</font>&#62; <br />
&lt;/soap:Body&#62; <br />
...
</td></tr></table><br></tt>
This use of a <i><b>struct</b></i> or <i><b>class</b></i> enables the adaptation of the default SOAP response element name and/or namespace URI when required.
<div class="p"><!----></div>
Note that the <i><b>struct</b></i> (or <i><b>class</b></i>) declaration may appear within the function prototype declaration. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*<font color="#FF0000">xsd__string</font>; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;<font color="#0000FF">xsd__float</font>; <br />
<b>int</b>&nbsp;<font color="#00FF00">ns1__getQuote</font>(<font color="#FF0000">xsd__string</font> <font color="#FF00FF">symbol</font>, <b>struct</b>&nbsp;<font color="#FFFF00">ns1__getQuoteResponse</font> {<font color="#0000FF">xsd__float</font> <font color="#00FFFF">Result</font>;} &amp;r);
</td></tr></table><br></i>
This example combines the declaration of the response element of the remote method with the function prototype of the remote method.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.9">
7.1.9</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify Multiple Output Parameters</font></h4><a name="sec:multiple">
</a>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler uses the convention that the
<b>last parameter</b> of the function prototype declaration of a remove method in a header file
is also the <b>only single output parameter</b> of the method.
All other parameters are considered input parameters of the remote method. To specify a remote method
with <b>multiple output parameters</b>, a <i><b>struct</b></i> or <i><b>class</b></i> must be declared for the remote method response, see
also&nbsp;<a href="#sec:response">7.1.7</a>. The fields of the <i><b>struct</b></i> or <i><b>class</b></i> 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
<i><b>struct</b></i> or <i><b>class</b></i>) 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&nbsp;<a href="#sec:anonymous">7.1.13</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.10">
7.1.10</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example5">
</a>
<div class="p"><!----></div>
As an example, consider a hypothetical remote method <i>getNames</i> with a single input parameter <i><font color="#FF00FF">SSN</font></i>
and two output parameters <i><font color="#FF0000">first</font></i> and <i><font color="#0000FF">last</font></i>. This can be specified as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "getNames.h": <br />
<b>int</b>&nbsp;<font color="#00FF00">ns3__getNames</font>(<b>char</b>&nbsp;*<font color="#FF00FF">SSN</font>, <b>struct</b>&nbsp;<font color="#FFFF00">ns3__getNamesResponse</font> {<b>char</b>&nbsp;*<font color="#FF0000">first</font>; <b>char</b>&nbsp;*<font color="#0000FF">last</font>;} &amp;r);
</td></tr></table><br></i>
The gSOAP stub and skeleton compiler takes this header file as input and generates source code for the function <i>soap_call_ns3__getNames</i>. When invoked by a client application, the proxy produces the SOAP request:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Envelope ... xmlns:ns3="urn:names" ...&#62; <br />
... <br />
&lt;<font color="#00FF00">ns3:getNames</font>&#62; <br />
&lt;<font color="#FF00FF">SSN</font>&#62;999 99 9999&lt;/<font color="#FF00FF">SSN</font>&#62; <br />
&lt;/<font color="#00FF00">ns3:getNames</font>&#62; <br />
...
</td></tr></table><br></tt>
The response by a SOAP service could be:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;<font color="#FFFF00">m:getNamesResponse</font> xmlns:m="urn:names"&#62; <br />
&lt;<font color="#FF0000">first</font>&#62;John&lt;/<font color="#FF0000">first</font>&#62; <br />
&lt;<font color="#0000FF">last</font>&#62;Doe&lt;/<font color="#0000FF">last</font>&#62; <br />
&lt;/<font color="#FFFF00">m:getNamesResponse</font>&#62; <br />
...
</td></tr></table><br></tt>
where <tt><font color="#FF0000">first</font></tt> and <tt><font color="#0000FF">last</font></tt> are the output parameters of the <i>getNames</i> remote method of the service.
<div class="p"><!----></div>
As another example, consider a remote method <i>copy</i> 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 <i><b>struct</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Content of file "copy.h": <br />
<b>int</b>&nbsp;<font color="#00FF00">X_rox__copy_name</font>(<b>char</b>&nbsp;*<font color="#FF00FF">name</font>, <b>struct</b>&nbsp;<font color="#FFFF00">X_rox__copy_nameResponse</font> {<b>char</b>&nbsp;*<font color="#FF0000">name</font>;} &amp;r);
</td></tr></table><br></i>
The use of a <i><b>struct</b></i> or <i><b>class</b></i> for the remote method response enables the declaration of remote methods that have
parameters that are passed both as input and output parameters.
<div class="p"><!----></div>
The gSOAP compiler takes the <i>copy.h</i> header file as input and generates the <i>soap_call_X_rox__copy_name</i> proxy. When invoked by a client application, the proxy produces the SOAP request:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Envelope ... xmlns:X-rox="urn:copy" ...&#62; <br />
... <br />
&lt;<font color="#00FF00">X-rox:copy-name</font>&#62; <br />
&lt;<font color="#FF00FF">name</font>&#62;SOAP&lt;/<font color="#FF00FF">name</font>&#62; <br />
&lt;/<font color="#00FF00">X-rox:copy-name</font>&#62; <br />
...
</td></tr></table><br></tt>
The response by a SOAP copy service could be something like:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;<font color="#FFFF00">m:copy-nameResponse</font> xmlns:m="urn:copy"&#62; <br />
&lt;<font color="#FF0000">name</font>&#62;SOAP&lt;/<font color="#FF0000">name</font>&#62; <br />
&lt;/<font color="#FFFF00">m:copy-nameResponse</font>&#62; <br />
...
</td></tr></table><br></tt>
The name will be parsed and decoded by the proxy and returned in the <i>name</i> field of the <i><b>struct</b>&nbsp;X_rox__copy_nameResponse &amp;r</i> parameter.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.11">
7.1.11</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify Output Parameters With struct/class Compound Data Types</font></h4><a name="sec:compound">
</a>
<div class="p"><!----></div>
If the single output parameter of a remote method is a complex data type such as a <i><b>struct</b></i> or <i><b>class</b></i> it is necessary to
specify the response element of the remote method as a <i><b>struct</b></i> or <i><b>class</b></i> <b>at all times</b>.
Otherwise, the output parameter will
be considered the response element (!), because of the response element specification convention used by gSOAP,
as discussed in&nbsp;<a href="#sec:response">7.1.7</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.12">
7.1.12</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example6">
</a>
<div class="p"><!----></div>
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 <i>getFlightInfo</i> and
the method has two string parameters: the airline code and flight number, both of which must be encoded as <tt>xsd:string</tt> types.
The method returns a <i>getFlightResponse</i> response element with a <i>return</i> output parameter that is of complex type
<i>FlightInfo</i>. The type <i>FlightInfo</i> is represented by a <i><b>class</b></i> in the header file, whose field names correspond to
the <i>FlightInfo</i> accessors:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "flight.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>class</b>&nbsp;ns2__FlightInfo <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;xsd__string airline; <br />
&nbsp;&nbsp;&nbsp;xsd__string flightNumber; <br />
&nbsp;&nbsp;&nbsp;xsd__string altitude; <br />
&nbsp;&nbsp;&nbsp;xsd__string currentLocation; <br />
&nbsp;&nbsp;&nbsp;xsd__string equipment; <br />
&nbsp;&nbsp;&nbsp;xsd__string speed; <br />
}; <br />
<b>struct</b>&nbsp;ns1__getFlightInfoResponse {ns2__FlightInfo _return;}; <br />
<b>int</b>&nbsp;ns1__getFlightInfo(xsd__string param1, xsd__string param2, <b>struct</b>&nbsp;ns1__getFlightInfoResponse &amp;r);
</td></tr></table><br></i>
The response element <i>ns1__getFlightInfoResponse</i> is explicitly declared and it has one field: <i>return_</i> of type
<i>ns2__FlightInfo</i>. Note that <i>return_</i> has a trailing underscore to avoid a name clash with the <i><b>return</b></i> keyword,
see Section&nbsp;<a href="#sec:idtrans">9.3</a> for details on the translation of C++ identifiers to XML element names.
<div class="p"><!----></div>
The gSOAP compiler generates the <i>soap_call_ns1__getFlightInfo</i> proxy. Here is an example fragment of a client application that uses this proxy to request flight information:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
... <br />
soap_init(&amp;soap); <br />
... <br />
soap_call_ns1__getFlightInfo(&amp;soap, <tt>"testvger.objectspace.com/soap/servlet/rpcrouter"</tt>, <br />
&nbsp;&nbsp;&nbsp;<tt>"urn:galdemo:flighttracker"</tt>, <tt>"UAL"</tt>, <tt>"184"</tt>, r); <br />
... <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns1", "urn:galdemo:flighttracker"}, <br />
&nbsp;&nbsp;&nbsp;{"ns2", "http://galdemo.flighttracker.com"}, <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
When invoked by a client application, the proxy produces the SOAP request:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
POST /soap/servlet/rpcrouter HTTP/1.1 <br />
Host: testvger.objectspace.com <br />
Content-Type: text/xml <br />
Content-Length: 634 <br />
SOAPAction: "urn:galdemo:flighttracker" <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns1="urn:galdemo:flighttracker" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns2="http://galdemo.flighttracker.com" <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;ns1:getFlightInfo xsi:type="ns1:getFlightInfo"&#62; <br />
&lt;param1 xsi:type="xsd:string"&#62;UAL&lt;/param1&#62; <br />
&lt;param2 xsi:type="xsd:string"&#62;184&lt;/param2&#62; <br />
&lt;/ns1:getFlightInfo&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
The Flighttracker service responds with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
HTTP/1.1 200 ok <br />
Date: Thu, 30 Aug 2001 00:34:17 GMT <br />
Server: IBM_HTTP_Server/1.3.12.3 Apache/1.3.12 (Win32) <br />
Set-Cookie: sesessionid=2GFVTOGC30D0LGRGU2L4HFA;Path=/ <br />
Cache-Control: no-cache="set-cookie,set-cookie2" <br />
Expires: Thu, 01 Dec 1994 16:00:00 GMT <br />
Content-Length: 861 <br />
Content-Type: text/xml; charset=utf-8 <br />
Content-Language: en <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema"&#62; <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;ns1:getFlightInfoResponse xmlns:ns1="urn:galdemo:flighttracker" <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&lt;return xmlns:ns2="http://galdemo.flighttracker.com" xsi:type="ns2:FlightInfo"&#62; <br />
&lt;equipment xsi:type="xsd:string"&#62;A320&lt;/equipment&#62; <br />
&lt;airline xsi:type="xsd:string"&#62;UAL&lt;/airline&#62; <br />
&lt;currentLocation xsi:type="xsd:string"&#62;188 mi W of Lincoln, NE&lt;/currentLocation&#62; <br />
&lt;altitude xsi:type="xsd:string"&#62;37000&lt;/altitude&#62; <br />
&lt;speed xsi:type="xsd:string"&#62;497&lt;/speed&#62; <br />
&lt;flightNumber xsi:type="xsd:string"&#62;184&lt;/flightNumber&#62; <br />
&lt;/return&#62; <br />
&lt;/ns1:getFlightInfoResponse&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
The proxy returns the service response in variable <i>r</i> of type <i><b>struct</b>&nbsp;ns1__getFlightInfoResponse</i> and this information can be displayed by the client application with the following code fragment:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
cout &lt;&lt; r.return_.equipment &lt;&lt; " flight " &lt;&lt; r.return_.airline &lt;&lt; r.return_.flightNumber <br />
&nbsp;&nbsp;&nbsp; &lt;&lt; " traveling " &lt;&lt; r.return_.speed &lt;&lt; " mph " &lt;&lt; " at " &lt;&lt; r.return_.altitude <br />
&nbsp;&nbsp;&nbsp; &lt;&lt; " ft, is located " &lt;&lt; r.return_.currentLocation &lt;&lt; endl;
</td></tr></table><br></i>
This code displays the service response as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<tt>A320 flight UAL184 traveling 497 mph at 37000 ft, is located 188 mi W of Lincoln, NE</tt>
</td></tr></table><br></span>
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.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.13">
7.1.13</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify Anonymous Parameter Names</font></h4><a name="sec:anonymous">
</a>
<div class="p"><!----></div>
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:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>int</b>&nbsp;ns1__getQuote(xsd__string, xsd__float&amp;);
</td></tr></table><br></i>
To make parameter names explicitly anonymous on the receiving side (client or service),
the parameter names should start with an underscore (<i>_</i>) in the function prototype in the header file.
<div class="p"><!----></div>
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>int</b>&nbsp;ns1__getQuote(xsd__string symbol, xsd__float &amp;_return);
</td></tr></table><br></i>
Or, alternatively with a response <i><b>struct</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of "getQuote.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>struct</b>&nbsp;ns1__getQuoteResponse {xsd__float _return;}; <br />
<b>int</b>&nbsp;ns1__getQuote(xsd__string symbol, <b>struct</b>&nbsp;ns1__getQuoteResponse &amp;r);
</td></tr></table><br></i>
In this example, <i>_return</i> 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.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: when anonymous parameter names are used, the order of the parameters in the function prototype of a remote method is
significant.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.14">
7.1.14</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify a Method with No Input Parameters</font></h4>
<div class="p"><!----></div>
To specify a remote method that has no input parameters, just provide a function prototype with one parameter which is the output
parameter. However, some C/C++ compilers (notably Visual C++<sup><span class="roman">TM</span></sup>) will not compile and complain about an empty
<i><b>struct</b></i>. This <i><b>struct</b></i> is generated by gSOAP to contain the SOAP request message. To fix this, provide one input
parameter of type <i><b>void</b>*</i> (gSOAP can not serialize <i>void*</i> data). For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns3__SOAPService <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;ID; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*owner; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*description; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*homepageURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*endpoint; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*SOAPAction; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*methodNamespaceURI; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*serviceStatus; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*methodName; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*dateCreated; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*downloadURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*wsdlURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*instructions; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*contactEmail; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*serverImplementation; <br />
}; <br />
<b>struct</b>&nbsp;ArrayOfSOAPService {<b>struct</b>&nbsp;ns3__SOAPService *__ptr; <b>int</b>&nbsp;__size;}; <br />
<b>int</b>&nbsp;ns__getAllSOAPServices(<b>void</b>&nbsp;*_, <b>struct</b>&nbsp;ArrayOfSOAPService &amp;_return);
</td></tr></table><br></i>
The <i>ns__getAllSOAPServices</i> method has one <i><b>void</b>*</i> input parameter which is ignored by the serializer to produce the
request message.
<div class="p"><!----></div>
Most C/C++ compilers allow empty <i><b>struct</b></i>s and therefore the <i><b>void</b>*</i> parameter is not required.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.1.15">
7.1.15</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify a Method with No Output Parameters</font></h4>
<div class="p"><!----></div>
To specify a remote method that has no output parameters, just provide a function prototype with a response struct that is
empty. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns__event { off, on, stand_by }; <br />
<b>int</b>&nbsp;ns__signal(<b>enum</b>&nbsp;ns__event in, <b>struct</b>&nbsp;ns__signalResponse { } *out);
</td></tr></table><br></i>
Since the response struct is empty, no output parameters are specified.
Most C/C++ compilers allow empty <i><b>struct</b></i>s. For those that don't, use a <i><b>void</b>*</i> parameter in the struct.
This parameter is not (de)serialized.
<div class="p"><!----></div>
Some SOAP resources refer to SOAP RPC with empty responses as <b>one way</b> SOAP messaging. However, we refer to one-way massaging
by asynchronous explicit send and receive operations as described in Section&nbsp;<a href="#sec:oneway1">7.3</a>. The latter view of one-way SOAP messaging is also in line with Basic Profile 1.0.
<div class="p"><!----></div>
<h3><a name="tth_sEc7.2">
7.2</a>&nbsp;&nbsp;<font color="#0000FF">How to Use the gSOAP Stub and Skeleton Compiler to Build SOAP Web Services</font></h3>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler generates <b>skeleton</b> routines in C++ source form for each of the remote methods specified
as function prototypes in the header file processed by the gSOAP compiler. The skeleton routines can be readily used to implement
the remote methods in a new SOAP Web service. The compound data types used by the input and output parameters of SOAP remote
methods must be declared in the header file, such as structs, classes, arrays, and pointer-based data structures (graphs) that are
used as the data types of the parameters of a remote method. The gSOAP compiler automatically generates serializers and
deserializers for the data types to enable the generated skeleton routines to encode and decode the contents of the parameters of
the remote methods. The gSOAP compiler also generates a remote method request dispatcher routine that will serve requests by
calling the appropriate skeleton when the SOAP service application is installed as a CGI application on a Web server.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.1">
7.2.1</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example7">
</a>
<div class="p"><!----></div>
The following example specifies three remote methods to be implemented by a new SOAP Web service:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "calc.h": <br />
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__double; <br />
<b>int</b>&nbsp;ns__add(xsd__double a, xsd__double b, xsd__double &amp;result); <br />
<b>int</b>&nbsp;ns__sub(xsd__double a, xsd__double b, xsd__double &amp;result); <br />
<b>int</b>&nbsp;ns__sqrt(xsd__double a, xsd__double &amp;result); <br />
</td></tr></table><br></i>
The <i>add</i> and <i>sub</i> methods are intended to add and subtract two double floating point numbers stored in input parameters
<i>a</i> and <i>b</i> and should return the result of the operation in the <i>result</i> output parameter. The <i>qsrt</i> method is
intended to take the square root of input parameter <i>a</i> and to return the result in the output parameter <i>result</i>.
The <i>xsd__double</i> type is recognized by the gSOAP compiler as the <tt>xsd:double</tt> XSD Schema data type.
The use of <i><b>typedef</b></i> is a convenient way to associate primitive C types with primitive XML Schema data types.
<div class="p"><!----></div>
To generate the skeleton routines, the gSOAP compiler is invoked from the command line with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 calc.h</i>
</td></tr></table><br></span>
The compiler generates the skeleton routines for the <i>add</i>, <i>sub</i>, and <i>sqrt</i> remote methods specified in the
<i>calc.h</i> header file. The skeleton routines are respectively, <i>soap_serve_ns__add</i>, <i>soap_serve_ns__sub</i>, and
<i>soap_serve_ns__sqrt</i> and saved in the file <i>soapServer.cpp</i>. The generated file <i>soapC.cpp</i> contains serializers
and deserializers for the skeleton. The compiler also generates a service dispatcher: the <i>soap_serve</i> function handles
client requests on the standard input stream and dispatches the remote method requests to the appropriate skeletons to serve the
requests. The skeleton in turn calls the remote method implementation function. The function prototype of the remote method
implementation function is specified in the header file that is input to the gSOAP compiler.
<div class="p"><!----></div>
Here is an example Calculator service application that uses the generated <i>soap_serve</i> routine to handle client requests:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "calc.cpp": <br />
#include "soapH.h" <br />
#include &lt; math.h &gt; // for sqrt() <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); // use the remote method request dispatcher <br />
} <br />
// Implementation of the "add" remote method: <br />
<b>int</b>&nbsp;ns__add(<b>struct</b>&nbsp;soap *soap, <b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;result = a + b; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
// Implementation of the "sub" remote method: <br />
<b>int</b>&nbsp;ns__sub(<b>struct</b>&nbsp;soap *soap, <b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;result = a - b; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
// Implementation of the "sqrt" remote method: <br />
<b>int</b>&nbsp;ns__sqrt(<b>struct</b>&nbsp;soap *soap, <b>double</b>&nbsp;a, <b>double</b>&nbsp;&amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(a &gt; = 0) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = sqrt(a); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_receiver_fault(soap, "Square root of negative number", "I can only take the square root of a non-negative number"); <br />
} <br />
// As always, a namespace mapping table is needed: <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name"} <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns", "urn:simple-calc"}, // bind "ns" namespace prefix <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
Note that the remote methods have an extra input parameter which is a pointer to the gSOAP runtime environment.
The implementation of the remote methods MUST return a SOAP error code. The code <i>SOAP_OK</i> denotes success, while
<i>SOAP_FAULT</i> denotes an exception with details that can be defined by the user. The exception description can be assigned to
the <i>soap</i><tt>-&gt;</tt><i>fault</i><tt>-&gt;</tt><i>faultstring</i> string and details can be assigned to the
<i>soap</i><tt>-&gt;</tt><i>fault</i><tt>-&gt;</tt><i>detail</i> string. This is SOAP 1.1 specific. SOAP 1.2 requires
the <i>soap</i><tt>-&gt;</tt><i>fault</i><tt>-&gt;</tt><i>SOAP_ENV__Reason</i> and the
<i>soap</i><tt>-&gt;</tt><i>fault</i><tt>-&gt;</tt><i>SOAP_ENV__Detail</i> strings to be assigned.
Better is to use the
<i>soap_receiver_fault</i> function that allocates a fault struct and sets the SOAP Fault string and details
regardless of the SOAP 1.1 or SOAP 1.2 version used. The <i>soap_receiver_fault</i> function returns
<i>SOAP_FAULT</i>, i.e.&nbsp;an application-specific fault. The fault exception will be passed on to the client of this service.
<div class="p"><!----></div>
This service application can be readily installed as a CGI application. The service description would be:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td>Endpoint URL: </td><td>the URL of the CGI application </td></tr>
<tr><td>SOAP action: </td><td>"" (2 quotes) </td></tr>
<tr><td>Remote method namespace: </td><td><tt>urn:simple-calc</tt> </td></tr>
<tr><td>Remote method name: </td><td><tt>add</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Input parameters: </td><td><tt>a</tt> of type <tt>xsd:double</tt> and <tt>b</tt> of type <tt>xsd:double</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Output parameter: </td><td><tt>result</tt> of type <tt>xsd:double</tt> </td></tr>
<tr><td>Remote method name: </td><td><tt>sub</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Input parameters: </td><td><tt>a</tt> of type <tt>xsd:double</tt> and <tt>b</tt> of type <tt>xsd:double</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Output parameter: </td><td><tt>result</tt> of type <tt>xsd:double</tt> </td></tr>
<tr><td>Remote method name: </td><td><tt>sqrt</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Input parameter: </td><td><tt>a</tt> of type <tt>xsd:double</tt> </td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;Output parameter: </td><td><tt>result</tt> of type <tt>xsd:double</tt> or a SOAP Fault
</td></tr></table>
</td></tr></table><br></span>
The <i>soapcpp2</i> compile generates a WSDL file for this service, see Section&nbsp;<a href="#sec:wsdl">7.2.8</a>.
<div class="p"><!----></div>
Unless the CGI application inspects and checks the environment variable <i>SOAPAction</i> which contains the SOAP action request by
a client, the SOAP action is ignored by the CGI application. SOAP actions are specific to the SOAP protocol and provide a means
for routing requests and for security reasons (e.g.&nbsp;firewall software can inspect SOAP action headers to grant or deny the
SOAP request. Note that this requires the SOAP service to check the SOAP action header as well to match it with the remote method.)
<div class="p"><!----></div>
The header file input to the gSOAP compiler does not need to be modified to generate client stubs for accessing this
service. Client applications can be developed by using the same header file as for which the service application
was developed. For example, the <i>soap_call_ns__add</i> stub routine is available from the <i>soapClient.cpp</i> file after invoking
the gSOAP compiler on the <i>calc.h</i> header file. As a result, client and service applications can be developed without
the need to know the details of the SOAP encoding used.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.2">
7.2.2</a>&nbsp;&nbsp;<font color="#0000FF">MSVC++ Builds</font></h4>
<div class="p"><!----></div>
<ul>
<li> Win32 builds need winsock.dll (MS Visual C++ "wsock32.lib")
To do this in Visual C++ 6.0, go to "Project", &#223;ettings", select the "Link"
tab (the project file needs to be selected in the file view) and add
"wsock32.lib" to the &#214;bject/library modules" entry.
<div class="p"><!----></div>
</li>
<li> Use files with extension .cpp only (don't mix .c with .cpp).
<div class="p"><!----></div>
</li>
<li> Turn pre-compiled headers off.
<div class="p"><!----></div>
</li>
<li> When creating a new project, you can specify a custom build step to automatically invoke the gSOAP compiler on a gSOAP header file. In this way you can incrementally build a new service by adding new operations and data types to the header file. To specify a custom build step, select the "Project" menu item "Settings" and select the header file in the File view pane. Select the "Custom Build" tab and enter '<i>soapcpp2.exe "$(inputPath)"</i>' in the "Command" pane. Enter '<i>soapStub.h soapH.h soapC.cpp soapClient.cpp soapServer.cpp soapClientLib.cpp soapServerLib.cpp</i>'. Don't forget to add the <i>soapXYZProxy.h soapXYZProxy.cpp soapXYZObject.h soapXYZObject.cpp</i> files that are generated for C++ class proxies and server objects named XYZ. Click &#214;K". Run the soapcpp2 compiler once to generate these files (you can simply do this by selecting your header file and select "Compile"). Add the files to your project. Each time you make a change to the header file, the project sources are updated automatically.
<div class="p"><!----></div>
</li>
<li> You may want to use the WinInet interface available in the <i>mod_gsoap</i> directory of the gSOAP package to simplify Internet access and deal with encryption, proxies, and authentication. API instructions are included in the source.
<div class="p"><!----></div>
</li>
<li> For the PocketPC, run the <i>wsdl2h</i> WSDL parser with option <i>-s</i> to prevent the generation of STL code. In addition, <i>time_t</i> serialization is not supported, which means that you should add the following line to <i>typemap.dat</i> indicating a mapping of <i>xsd__dateTime</i> to <i><b>char</b>*</i>: <tt>xsd__dateTime = - char* - char*</tt>.
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.3">
7.2.3</a>&nbsp;&nbsp;<font color="#0000FF">How to Create a Stand-Alone gSOAP Service</font></h4>
<div class="p"><!----></div>
The deployment of a Web service as a CGI application is an easy means to provide your service on the Internet.
gSOAP services can also run as stand-alone services on any port by utilizing the built-in HTTP and TCP/IP stacks.
The stand-alone services can be run on port 80 thereby providing Web server capabilities restricted to SOAP RPC.
<div class="p"><!----></div>
To create a stand-alone service, only the <i>main</i> routine of the service needs to be modified as follows. Instead of just calling the
<i>soap_serve</i> routine, the <i>main</i> routine is changed into:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;m, s; // master and slave sockets <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, <tt>"machine.cs.fsu.edu"</tt>, 18083, 100); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(m &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Socket&nbsp;connection&nbsp;successful:&nbsp;master&nbsp;socket&nbsp;=&nbsp;%d\n"</tt>, m); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(<b>int</b>&nbsp;i = 1; ; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(s &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"%d:&nbsp;accepted&nbsp;connection&nbsp;from&nbsp;IP=%d.%d.%d.%d&nbsp;socket=%d"</tt>, i, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(soap.ip &gt;&gt; 24)&amp;0xFF, (soap.ip &gt;&gt; 16)&amp;0xFF, (soap.ip &gt;&gt; 8)&amp;0xFF, soap.ip&amp;0xFF, s); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_serve(&amp;soap) != SOAP_OK) // process RPC request <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // print error <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"request&nbsp;served\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // clean up class instances <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // clean up everything and close socket <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // close master socket and detach environment <br />
}
</td></tr></table><br></i>
The <i>soap_serve</i> dispatcher handles one request or multiple requests when HTTP keep-alive is enabled (with the <i>SOAP_IO_KEEPALIVE</i> flag see Section&nbsp;<a href="#sec:keepalive">18.11</a>).
<div class="p"><!----></div>
The gSOAP functions that can be used are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="301"><font color="#FF0000"><b>Function</b></font> </td><td width="301"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td width="301"><i>soap_init(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Initializes gSOAP runtime environment (required once) </td></tr>
<tr><td width="301"><i>soap_bind(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*host, <b>int</b>&nbsp;port, <b>int</b>&nbsp;backlog)</i> </td><td width="301">Returns master socket (backlog = max.&nbsp;queue
size for requests). When <i>host==NULL</i>: host is the machine on which the service runs </td></tr>
<tr><td width="301"><i>soap_accept(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Returns slave socket </td></tr>
<tr><td width="301"><i>soap_end(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Clean up deserialized data (except class instances) and temporary data </td></tr>
<tr><td width="301"><i>soap_free(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Clean up temporary data only </td></tr>
<tr><td width="301"><i>soap_destroy(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Clean up deserialized class instances (note: this function will be renamed with option <i>-n</i> </td></tr>
<tr><td width="301"><i>soap_done(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="301">Reset: close master/slave sockets and remove callbacks </td></tr>
<tr><td width="301"></td><td width="301">(see Section&nbsp;<a href="#sec:callback">18.7</a> </td></tr></table>
</td></tr></table><br></span>
The <i>host</i> name in <i>soap_bind</i> may be NULL to indicate that the current host should be used.
<div class="p"><!----></div>
The <i>soap.accept_timeout</i> attribute of the gSOAP run-time environment specifies the timeout value for a non-blocking
<i>soap_accept(&amp;soap)</i> call. See Section&nbsp;<a href="#sec:timeout">18.17</a> for more details on timeout management.
<div class="p"><!----></div>
See Section&nbsp;<a href="#sec:memory">8.13</a> for more details on memory management.
<div class="p"><!----></div>
A client application connects to this stand-alone service with the endpoint
<i>machine.cs.fsu.edu:18083</i>.
A client may use the <i>http://</i> prefix. When absent, no HTTP header is send and no HTTP-based information will be communicated
to the service.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.4">
7.2.4</a>&nbsp;&nbsp;<font color="#0000FF">How to Create a Multi-Threaded Stand-Alone Service</font></h4><a name="sec:mt">
</a>
<div class="p"><!----></div>
Multi-threading a Web Service is essential when the response times for handling requests by the service are (potentially) long or when keep-alive is enabled, see Section&nbsp;<a href="#sec:keepalive">18.11</a>.
In case of long response times, the latencies introduced by the unrelated requests may become prohibitive for a successful
deployment of a stand-alone service. When HTTP keep-alive is enabled, a client may not close the socket on time, thereby preventing other clients from connecting.
<div class="p"><!----></div>
gSOAP 2.0 and higher is thread safe and supports the implementation of multi-threaded stand-alone services in which
a thread is used to handle a request.
<div class="p"><!----></div>
The following example illustrates the use of threads to improve the quality of service by handling new requests in separate threads:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include &lt; pthread.h &gt; <br />
#define BACKLOG (100) // Max. request backlog <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;**argv) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; 2) // no args: assume this is a CGI application <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); // serve request, one thread, CGI style <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // dealloc C++ data <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // dealloc data and clean up <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.send_timeout = 60; // 60 seconds <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.recv_timeout = 60; // 60 seconds <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.accept_timeout = 3600; // server stops after 1 hour of inactivity <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.max_keep_alive = 100; // max keep-alive sequence <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;*process_request(<b>void</b>*); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *tsoap; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_t tid; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;port = atoi(argv[1]); // first command-line arg is port <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOAP_SOCKET m, s; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, port, BACKLOG); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(m)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Socket&nbsp;connection&nbsp;successful&nbsp;%d\n"</tt>, m); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(s)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.errnum) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"server&nbsp;timed&nbsp;out\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Thread&nbsp;%d&nbsp;accepts&nbsp;socket&nbsp;%d&nbsp;connection&nbsp;from&nbsp;IP&nbsp;%d.%d.%d.%d\n"</tt>, i, s, (soap.ip &gt;&gt; 24)&amp;0xFF,
(soap.ip &gt;&gt; 16)&amp;0xFF, (soap.ip &gt;&gt; 8)&amp;0xFF, soap.ip&amp;0xFF); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tsoap = soap_copy(&amp;soap); // make a safe copy <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!tsoap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid, NULL, (<b>void</b>*(*)(<b>void</b>*))process_request, (<b>void</b>*)tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // detach soap struct <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>void</b>&nbsp;*process_request(<b>void</b>&nbsp;*soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;pthread_detach(pthread_self()); <br />
&nbsp;&nbsp;&nbsp;soap_serve((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_destroy((<b>struct</b>&nbsp;soap*)soap); // dealloc C++ data <br />
&nbsp;&nbsp;&nbsp;soap_end((<b>struct</b>&nbsp;soap*)soap); // dealloc data and clean up <br />
&nbsp;&nbsp;&nbsp;soap_done((<b>struct</b>&nbsp;soap*)soap); // detach soap struct <br />
&nbsp;&nbsp;&nbsp;free(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
}
</td></tr></table><br></i>
Note: the code does not wait for threads to join the main thread upon program termination.
<div class="p"><!----></div>
The <i>soap_serve</i> dispatcher handles one request or multiple requests when
HTTP keep-alive is set with <i>SOAP_IO_KEEPALIVE</i>. The
<i>soap.max_keep_alive</i> value can be set to the maximum keep-alive calls
allowed, which is important to avoid a client from holding a thread
indefinitely. The send and receive timeouts are set to avoid (intentionally)
slow clients from holding a socket connection too long. The accept timeout is used
to let the server terminate automatically after a period of inactivity.
<div class="p"><!----></div>
The following example uses a pool of servers to limit the machine's resource utilization:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include &lt; pthread.h &gt; <br />
#define BACKLOG (100) // Max. request backlog <br />
#define MAX_THR (10) // Max. threads to serve requests <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;**argv) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; 2) // no args: assume this is a CGI application <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); // serve request, one thread, CGI style <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // dealloc C++ data <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // dealloc data and clean up <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap_thr[MAX_THR]; // each thread needs a runtime environment <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_t tid[MAX_THR]; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;port = atoi(argv[1]); // first command-line arg is port <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOAP_SOCKET m, s; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;i; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, port, BACKLOG); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(m)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Socket&nbsp;connection&nbsp;successful&nbsp;%d\n"</tt>, m); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_thr[i] = NULL; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(s)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.errnum) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>continue</b>; // retry<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Server&nbsp;timed&nbsp;out\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Thread&nbsp;%d&nbsp;accepts&nbsp;socket&nbsp;%d&nbsp;connection&nbsp;from&nbsp;IP&nbsp;%d.%d.%d.%d\n"</tt>, i, s, (soap.ip &gt;&gt; 24)&amp;0xFF,
(soap.ip &gt;&gt; 16)&amp;0xFF, (soap.ip &gt;&gt; 8)&amp;0xFF, soap.ip&amp;0xFF); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_thr[i]) // first time around <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_thr[i] = soap_copy(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_thr[i]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); // could not allocate <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b>// recycle soap environment <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_join(tid[i], NULL); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Thread <tt>%</tt>d completed<tt>\</tt>n", i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(soap_thr[i]); // deallocate C++ data of old thread <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(soap_thr[i]); // deallocate data of old thread <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_thr[i]<tt>-&gt;</tt>socket = s; // new socket fd <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid[i], NULL, (<b>void</b>*(*)(<b>void</b>*))soap_serve, (<b>void</b>*)soap_thr[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_thr[i]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_done(soap_thr[i]); // detach context <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(soap_thr[i]); // free up <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
The following functions can be used to setup a gSOAP runtime environment (<i><b>struct</b>&nbsp;soap</i>):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function</b></font> </td><td width="351"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soap_init(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Initializes a runtime environment (required only once) </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_new()</i> </td><td width="351">Allocates, initializes, and returns a pointer to a runtime environment </td></tr>
<tr><td><i><b>struct</b>&nbsp;soap *soap_copy(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Allocates a new runtime environment and copies contents of
the argument environment such that the new environment does not share data with the argument environment </td></tr>
<tr><td><i>soap_done(<b>struct</b>&nbsp;soap *soap)</i> </td><td width="351">Reset, close communications, and remove callbacks </td></tr></table>
</td></tr></table><br></span>
A new environment is initiated for each thread to guarantee exclusive access
to runtime environments.
<div class="p"><!----></div>
For clean termination of the server, the master socket can be closed and callbacks removed with <i>soap_done(<b>struct</b>&nbsp;soap *soap)</i>.
<div class="p"><!----></div>
The advantage of the code shown above is that the machine cannot be overloaded with requests, since the number of active services is limited. However, threads are still started and terminated. This overhead can be eliminated using a queue of requests (open sockets) as is shown in the code below.
<div class="p"><!----></div>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include &lt; pthread.h &gt; <br />
#define BACKLOG (100) // Max. request backlog <br />
#define MAX_THR (10) // Size of thread pool <br />
#define MAX_QUEUE (1000) // Max. size of request queue <br />
SOAP_SOCKET queue[MAX_QUEUE]; // The global request queue of sockets <br />
<b>int</b>&nbsp;head = 0, tail = 0; // Queue head and tail <br />
<b>void</b>&nbsp;*process_queue(<b>void</b>*); <br />
<b>int</b>&nbsp;enqueue(SOAP_SOCKET); <br />
SOAP_SOCKET dequeue(); <br />
pthread_mutex_t queue_cs; <br />
pthread_cond_t queue_cv; <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;**argv) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; 2) // no args: assume this is a CGI application <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); // serve request, one thread, CGI style <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // dealloc C++ data <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // dealloc data and clean up <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap_thr[MAX_THR]; // each thread needs a runtime environment <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_t tid[MAX_THR]; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;port = atoi(argv[1]); // first command-line arg is port <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOAP_SOCKET m, s; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;i; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, port, BACKLOG); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(m)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Socket&nbsp;connection&nbsp;successful&nbsp;%d\n"</tt>, m); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_init(&amp;queue_cs, NULL); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_init(&amp;queue_cv, NULL); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_thr[i] = soap_copy(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Starting&nbsp;thread&nbsp;%d\n"</tt>, i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid[i], NULL, (<b>void</b>*(*)(<b>void</b>*))process_queue, (<b>void</b>*)soap_thr[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(s)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.errnum) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>continue</b>; // retry <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Server&nbsp;timed&nbsp;out\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Thread&nbsp;%d&nbsp;accepts&nbsp;socket&nbsp;%d&nbsp;connection&nbsp;from&nbsp;IP&nbsp;%d.%d.%d.%d\n"</tt>, i, s, (soap.ip &gt;&gt; 24)&amp;0xFF, (soap.ip &gt;&gt; 16)&amp;0xFF, (soap.ip &gt;&gt; 8)&amp;0xFF, soap.ip&amp;0xFF); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>while</b>&nbsp;(enqueue(s) == SOAP_EOM) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>while</b>&nbsp;(enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_THR; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Waiting&nbsp;for&nbsp;thread&nbsp;%d&nbsp;to&nbsp;terminate...&nbsp;"</tt>, i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_join(tid[i], NULL); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"terminated\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_done(soap_thr[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(soap_thr[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_destroy(&amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_destroy(&amp;queue_cv); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>void</b>&nbsp;*process_queue(<b>void</b>&nbsp;*soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *tsoap = (<b>struct</b>&nbsp;soap*)soap; <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tsoap<tt>-&gt;</tt>socket = dequeue(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(tsoap<tt>-&gt;</tt>socket)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"served\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
} <br />
<b>int</b>&nbsp;enqueue(SOAP_SOCKET sock) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;status = SOAP_OK; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;next; <br />
&nbsp;&nbsp;&nbsp;pthread_mutex_lock(&amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;next = tail + 1; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(next &gt; = MAX_QUEUE) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next = 0; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(next == head) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = SOAP_EOM; <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue[tail] = sock; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tail = next; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;pthread_cond_signal(&amp;queue_cv); <br />
&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(&amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;status; <br />
} <br />
SOAP_SOCKET dequeue() <br />
{ <br />
&nbsp;&nbsp;&nbsp;SOAP_SOCKET sock; <br />
&nbsp;&nbsp;&nbsp;pthread_mutex_lock(&amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;pthread_cond_wait(&amp;queue_cv, &amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;sock = queue[head++]; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(head &gt; = MAX_QUEUE) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;head = 0; <br />
&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(&amp;queue_cs); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;sock; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.5">
7.2.5</a>&nbsp;&nbsp;<font color="#0000FF">How to Pass Application Data to Service Methods</font></h4>
<div class="p"><!----></div>
The <i><b>void</b>&nbsp;*soap.user</i> field can be used to pass application data to service methods. This field should be set before the <i>soap_serve()</i> call. The service method can access this field to use the application-dependent data. The following example shows how a non-static database handle is initialized and passed to the service methods:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;database_handle_type database_handle; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap);
&nbsp;&nbsp;&nbsp;soap.user = (void*)database_handle; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); // call the remove method dispatcher to handle request <br />
&nbsp;&nbsp;&nbsp;... <br />
} <br />
<b>int</b>&nbsp;ns__myMethod(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;fetch((database_handle_type*)soap<tt>-&gt;</tt>user); <br />// get data
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></span>
Another way to pass application data around in a more organized way is accomplished with plugins, see Section&nbsp;<a href="#sec:plugins">18.36</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.6">
7.2.6</a>&nbsp;&nbsp;<font color="#0000FF">Some Web Service Implementation Issues</font></h4>
<div class="p"><!----></div>
The same client header file specification issues apply to the specification and implementation of a SOAP Web service. Refer to
<ul>
<li> <a href="#sec:namespace">7.1.2</a> for namespace considerations.
<div class="p"><!----></div>
</li>
<li> <a href="#sec:encoding">7.1.5</a> for an explanation on how to change the encoding of the primitive types.
<div class="p"><!----></div>
</li>
<li> <a href="#sec:response">7.1.7</a> for a discussion on how the response element format can be controlled.
<div class="p"><!----></div>
</li>
<li> <a href="#sec:multiple">7.1.9</a> for details on how to pass multiple output parameters from a remote method.
<div class="p"><!----></div>
</li>
<li> <a href="#sec:compound">7.1.11</a> for passing complex data types as output parameters.
<div class="p"><!----></div>
</li>
<li> <a href="#sec:anonymous">7.1.13</a> for anonymizing the input and output parameter names.
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.7">
7.2.7</a>&nbsp;&nbsp;<font color="#0000FF">How to Generate C++ Server Object Classes</font></h4><a name="sec:object">
</a>
<div class="p"><!----></div>
Server object classes for C++ server applications are automatically generated by the gSOAP compiler.
We illustrate the generation of an object class with a calculator example.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Content of file <tt>"calc.h"</tt>: <br />
//gsoap ns service name: Calculator <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://www.cs.fsu.edu/~engelen/calc.cgi <br />
//gsoap ns schema namespace: urn:calc <br />
//gsoap ns service method-action: add "" <br />
<b>int</b>&nbsp;ns__add(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result);
<b>int</b>&nbsp;ns__sub(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result);
<b>int</b>&nbsp;ns__mul(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result);
<b>int</b>&nbsp;ns__div(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result);
</td></tr></table><br></i>
The first three directives provide the service name which is used to name the service class, the service location (endpoint), and
the schema. The fourth directive defines the optional SOAPAction for the method, which is a string associated with SOAP 1.1 operations.
Compilation of this header file with the gSOAP compiler <i>soapcpp2</i> creates a new file <i>soapCalculatorObject.h</i> with the
following contents:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
<b>class</b>&nbsp;Calculator : <b>public</b>&nbsp;soap <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;Quote() { soap_init(<b>this</b>); }; <br />
&nbsp;&nbsp;&nbsp;~Quote() { soap_destroy(<b>this</b>); soap_end(<b>this</b>); soap_done(<b>this</b>); }}; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;serve() { <b>return</b>&nbsp;soap_serve(<b>this</b>); }; <br />
};
</td></tr></table><br></i>
This generated server object class can be included into a server application together with the generated namespace table as shown in this example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapCalculatorObject.h" // get server object <br />
#include "Calculator.nsmap" // get namespace bindings <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;Calculator c; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;c.serve(); // calls <i>soap_serve</i> to serve as CGI application (using stdin/out) <br />
} <br />
<b>int</b>&nbsp;ns__add(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;result = a + b; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
... sub(), mul(), and div() implementations ...
</td></tr></table><br></i>
You can use soapcpp2 compiler option <i>-n</i> together with <i>-p</i> to create a local namespaces table to avoid link conflict when you need to combine multiple tables and/or multiple servers, see also Sections&nbsp;<a href="#sec:options">8.1</a> and&nbsp;<a href="#sec:dylibs">18.34</a>, and you can use a C++ code <i><b>namespace</b></i> to create a namespace qualified server object class, see Section&nbsp;<a href="#sec:codenamespace">18.33</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.8">
7.2.8</a>&nbsp;&nbsp;<font color="#0000FF">How to Generate WSDL Service Descriptions</font></h4><a name="sec:wsdl">
</a>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler <i>soapcpp2</i> generates WSDL (Web Service Description Language) service descriptions and XML Schema files
when processing a header file. The compiler produces one WSDL file for a set of remote methods. The names of the function
prototypes of the remote methods must use the same namespace prefix and the namespace prefix is used to name the WSDL file. If
multiple namespace prefixes are used to define remote methods, multiple WSDL files will be created and each file describes the set
of remote methods belonging to a namespace prefix.
<div class="p"><!----></div>
In addition to the generation of the <tt>ns.wsdl</tt> file, a file with a namespace mapping table is generated by the gSOAP
compiler. An example mapping table is shown below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", \"http://www.w3.org/*/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", \"http://www.w3.org/*/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns", "http://tempuri.org"}, <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
This file can be incorporated in the
client/service application, see Section&nbsp;<a href="#sec:nstable">9.4</a> for details on namespace mapping tables.
<div class="p"><!----></div>
To deploy a Web service, copy the compiled CGI service application to the designated CGI directory of your Web server.
Make sure the proper file permissions are set (<tt>chmod 755 calc.cgi</tt> for Unix/Linux).
You can then publish the WSDL file on the Web by placing it in the appropriate Web server directory.
<div class="p"><!----></div>
The gSOAP compiler also generates XML Schema files for all C/C++
complex types (e.g.&nbsp;<i><b>struct</b></i>s and <i><b>class</b></i>es) when declared with a namespace prefix.
These files are named <tt>ns.xsd</tt>, where <tt>ns</tt> is the namespace prefix used in the declaration of the complex type.
The XML Schema files do not have to be published as the WSDL file already contains the appropriate XML Schema definitions.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.9">
7.2.9</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example8">
</a>
<div class="p"><!----></div>
For example, suppose the following methods are defined in the header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__double; <br />
<b>int</b>&nbsp;ns__add(xsd__double a, xsd__double b, xsd__double &amp;result); <br />
<b>int</b>&nbsp;ns__sub(xsd__double a, xsd__double b, xsd__double &amp;result); <br />
<b>int</b>&nbsp;ns__sqrt(xsd__double a, xsd__double &amp;result); <br />
</td></tr></table><br></i>
Then, one WSDL file will be created with the file name <tt>ns.wsdl</tt> that describes all three remote methods:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;definitions name="Service" <br />
&nbsp;&nbsp;&nbsp;xmlns="http://schemas.xmlsoap.org/wsdl/" <br />
&nbsp;&nbsp;&nbsp;targetNamespace="http://location/Service.wsdl" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP="http://schemas.xmlsoap.org/wsdl/soap/" <br />
&nbsp;&nbsp;&nbsp;xmlns:WSDL="http://schemas.xmlsoap.org/wsdl/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:tns="http://location/Service.wsdl" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns="http://tempuri.org"&#62; <br />
&lt;types&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;schema <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns="http://www.w3.org/2000/10/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;targetNamespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;complexType name="addResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="result" type="double" minOccurs="0" maxOccurs="1"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;anyAttribute namespace="##other"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/complexType&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;complexType name="subResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="result" type="double" minOccurs="0" maxOccurs="1"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;anyAttribute namespace="##other"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/complexType&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;complexType name="sqrtResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="result" type="double" minOccurs="0" maxOccurs="1"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/all&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;anyAttribute namespace="##other"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/complexType&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/schema&#62; <br />
&lt;/types&#62; <br />
&lt;message name="addRequest"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="a" type="xsd:double"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="b" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;message name="addResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="result" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;message name="subRequest"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="a" type="xsd:double"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="b" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;message name="subResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="result" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;message name="sqrtRequest"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="a" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;message name="sqrtResponse"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;part name="result" type="xsd:double"/&#62; <br />
&lt;/message&#62; <br />
&lt;portType name="ServicePortType"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="add"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input message="tns:addRequest"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output message="tns:addResponse"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="sub"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input message="tns:subRequest"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output message="tns:subResponse"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="sqrt"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input message="tns:sqrtRequest"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output message="tns:sqrtResponse"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&lt;/portType&#62; <br />
&lt;binding name="ServiceBinding" type="tns:ServicePortType"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;SOAP:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="add"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:operation soapAction="http://tempuri.org#add"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/output&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="sub"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:operation soapAction="http://tempuri.org#sub"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/output&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;operation name="sqrt"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:operation soapAction="http://tempuri.org#sqrt"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/input&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;output&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:body use="encoded" namespace="http://tempuri.org" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/output&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/operation&#62; <br />
&lt;/binding&#62; <br />
&lt;service name="Service"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;port name="ServicePort" binding="tns:ServiceBinding"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP:address location="http://location/Service.cgi"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/port&#62; <br />
&lt;/service&#62; <br />
&lt;/definitions&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.10">
7.2.10</a>&nbsp;&nbsp;<font color="#0000FF">How to Parse and Import WSDL Service Descriptions to Develop Clients and Servers</font></h4><a name="sec:wsdlin">
</a>
<div class="p"><!----></div>
Note: see <i>README.txt</i> in the <i>wsdl</i> directory for installation
instructions for the WSDL parser and importer.
<div class="p"><!----></div>
The creation of SOAP Web Services applications from a WSDL service description is a
two-step process.
<div class="p"><!----></div>
First, execute <i>wsdl2h <u><span class="roman">file</span></u>.wsdl</i> which generates the
a C++ header file <i><u><span class="roman">file</span></u>.h</i>
(use <i>wsdl2h -c <u><span class="roman">file</span></u>.wsdl</i> to generate pure C code).
You can provide a URL instead of a file name, when applicable.
The generated header file is a Web service specification that contains the parameter types and service function definitions.
The functions are represented as function prototypes. The file contains various annotations related to the Web service.
The header file must be processed by the gSOAP compiler. You cannot use it with a C/C++ compiler directly.
<div class="p"><!----></div>
Second, the header file <i><u><span class="roman">file</span></u>.h</i> is processed by the
gSOAP compiler by executing <i>soapcpp2 -i <u><span class="roman">file</span></u>.h</i>. This
creates the C/C++ source files to build a client application,
see&nbsp;<a href="#sec:client">7.1</a>. In addition, this generates a client proxy object
declared in <i>soap<u><span class="roman">Service</span></u>Proxy.h</i>, where
<span class="roman"><u>Service</u></span> is the name of the service defined in the WSDL. To
use this object, include the <i>soap<u><span class="roman">Service</span></u>Proxy.h</i> and
<i><u><span class="roman">Service</span></u>.nsmap</i> files in your C++ client application. The
<span class="roman"><u>Service</u></span> class provides the remote Web service methods as class
members.
<div class="p"><!----></div>
Consider the following example commands (entered at the command prompt):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
$ wsdl2h -o XMethodsQuery.h http://www.xmethods.net/wsdl/query.wsdl <br />
... <br />
$ soapcpp2 -i XMethodsQuery.h
</td></tr></table><br></span>
The first command generates <i>XMethodsQuery.h</i> from the WSDL at the specified URL.
The header file is then processed by the gSOAP compiler to generate the stubs
and skeletons.
See XMethodsQuery.h for the types and service functions. A C++ client application may
use the generated <i>soapXMethodsQuerySoapProxy.h</i> class and
<i>XMethodsQuerySoap.nsmap</i> XML namespace table to access the Web
service. Both need to be <i>#include</i>-d in your source. Then compile and link
the <i>soapC.cpp</i>, <i>soapClient.cpp</i>, and <i>stdsoap2.cpp</i> sources to complete the build.
<div class="p"><!----></div>
When parsing a WSDL, the output file name is the WSDL input file name with
extension <i>.h</i> instead of <i>.wsdl</i>. When an input file is absent or a WSDL file
from a Web location is accessed, the header output will be produced on the
standard output. Schema files (<i>.xsd</i>) can also be parsed and processed.
<div class="p"><!----></div>
The <i>wsdl2h</i> command-line options are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Option</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>-a</i> </td><td>generate indexed struct names for local elements with anonymous types </td></tr>
<tr><td><i>-c</i> </td><td>generate C source code </td></tr>
<tr><td><i>-d</i> </td><td>use DOM to populate xs:any and xsd:anyType elements </td></tr>
<tr><td><i>-e</i> </td><td>don't qualify enum names </td></tr>
<tr><td></td><td>This option is for backward compatibility with gSOAP 2.4.1 and earlier. </td></tr>
<tr><td></td><td>The option does not produce code that conforms to WS-I Basic Profile 1.0a. </td></tr>
<tr><td><i>-f</i> </td><td>generate flat C++ class hierarchy for schema extensions </td></tr>
<tr><td><i>-g</i> </td><td>generate global top-level element declarations </td></tr>
<tr><td><i>-h</i> </td><td>print help information </td></tr>
<tr><td><i>-I path</i> </td><td>use path to find files </td></tr>
<tr><td><i>-l</i> </td><td>include license information in output </td></tr>
<tr><td><i>-m</i> </td><td>use xsd.h module to import primitive types </td></tr>
<tr><td><i>-n name</i> </td><td>use <i>name</i> as the base namespace prefix name instead of <i>ns</i> </td></tr>
<tr><td><i>-N name</i> </td><td>use <i>name</i> as the base namespace prefix name for service namespaces </td></tr>
<tr><td><i>-o file</i> </td><td>output to file </td></tr>
<tr><td><i>-p</i> </td><td>create polymorphic types with C++ inheritance hierarchy with base <i>xsd__anyType</i> </td></tr>
<tr><td></td><td>This is automatically performed when WSDL contains polymorphic definitions </td></tr>
<tr><td><i>-r host:port</i> </td><td>connect via proxy host and port </td></tr>
<tr><td><i>-s</i> </td><td>don't generate STL code (no std::string and no std::vector) </td></tr>
<tr><td><i>-t file</i> </td><td>use type map file instead of the default file typemap.dat </td></tr>
<tr><td><i>-u</i> </td><td>don't generate unions </td></tr>
<tr><td><i>-v</i> </td><td>verbose output </td></tr>
<tr><td><i>-w</i> </td><td>always wrap response parameters in a response struct </td></tr>
<tr><td><i>-x</i> </td><td>don't generate <i>_XML any/anyAttribute</i> extensibility elements </td></tr>
<tr><td><i>-y</i> </td><td>generate typedef synonyms for structs and enums </td></tr>
<tr><td><i>-?</i> </td><td>print help information </td></tr></table>
</td></tr></table><br></span>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.11">
7.2.11</a>&nbsp;&nbsp;<font color="#0000FF">The typemap.dat File</font></h4><a name="sec:typemap">
</a>
<div class="p"><!----></div>
A <i>typemap.dat</i> file for <i>wsdl2h</i> contains custom XML Schema and C/C++
type bindings. An internal table is used by default.
<div class="p"><!----></div>
An example typemap file is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
# This file contains custom definitions of the XML Schema types and <br />
# C/C++ types for your project, and XML namespace prefix definitions. <br />
# The wsdl2h WSDL importer consults this file to determine bindings. <br />
<br />
<tt>[</tt> <br />
// This comment will be included in the generated .h file <br />
// You can include any additional declarations, includes, imports, etc. <br />
// within <tt>[</tt> <tt>]</tt> sections. The brackets MUST appear at the start of a line <br />
<tt>]</tt> <br />
# XML namespace prefix definitions can be provided to override the <br />
# default choice of ns1, ns2, ... prefixes. For example: <br />
<br />
i = "http://www.soapinterop.org/" <br />
s = "http://www.soapinterop.org/xsd" <br />
<br />
# Type definitions are of the form:
# type = declaration <font face="symbol">|</font
> use <font face="symbol">|</font
> pointer-use <br />
# where <br />
# type is the XML Schema type (or an application type in a namespace <br />
# that has a prefix definition given as above). <br />
# declaration is an optional C/C++ type declaration <br />
# use is how the type is referred to in code <br />
# pointer-use is how the type should be referred to as a pointer (opt) <br />
# Example XML Schema and C/C++ type bindings: <br />
<br />
xsd__int = <font face="symbol">|</font
> int <br />
xsd__string = <font face="symbol">|</font
> char* <font face="symbol">|</font
> char* <br />
xsd__boolean = enum xsd__boolean false_, true_ ; <font face="symbol">|</font
> enum xsd__boolean <br />
xsd__base64Binary = class xsd__base64Binary unsigned char *__ptr; int __size; ; <font face="symbol">|</font
> xsd__base64Binary <font face="symbol">|</font
> xsd__base64Binary <br />
# You can extend structs and classes with member data and functions. <br />
# For example, adding a constructor to ns__myClass:
ns__myClass = $ ns__myClass(); <br />
# The general form is
# class_name = $ member; <br />
</td></tr></table><br></tt>
The <i>i</i> and <i>s</i> prefixes are declared such that the header file output by the WSDL parser will use these to produce C/C++ code.
XML Schema types are associated with an optional C/C++ type declaration, a use reference, and a pointer-use reference. The pointer-use reference of the <i>xsd__byte</i> type for example, is <i><b>int</b>*</i> because <i><b>char</b>*</i> is reserved for strings.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.2.12">
7.2.12</a>&nbsp;&nbsp;<font color="#0000FF">How to Use Client Functionalities Within a Service</font></h4>
<div class="p"><!----></div>
A gSOAP service implemented with CGI may make direct client calls to other services from within its service operations, without setting up a new context. A stand-alone service application must setup a new soap struct context, e.g.&nbsp;using <i>soap_copy</i> and delete it after the call.
<div class="p"><!----></div>
The server-side client call is best illustrated with an example. The following example is a
more sophisticated example that combines the functionality of two Web services
into one new SOAP Web service. The service provides a currency-converted stock
quote. To serve a request, the service in turn requests the stock quote and
the currency-exchange rate from two XMethods services.
<div class="p"><!----></div>
In addition to being a client of two XMethods services, this service
application can also be used as a client of itself to test the implementation.
As a client invoked from the command-line, it will return a currency-converted
stock quote by connecting to a copy of itself installed as a CGI application on
the Web to retrieve the quote after which it will print the quote on the
terminal.
<div class="p"><!----></div>
The header file input to the gSOAP compiler is given below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "quotex.h": <br />
<b>int</b>&nbsp;ns1__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;result); // XMethods delayed stock quote service remote method <br />
<b>int</b>&nbsp;ns2__getRate(<b>char</b>&nbsp;*country1, <b>char</b>&nbsp;*country2, <b>float</b>&nbsp;&amp;result); // XMethods currency-exchange service remote method <br />
<b>int</b>&nbsp;ns3__getQuote(<b>char</b>&nbsp;*symbol, <b>char</b>&nbsp;*country, <b>float</b>&nbsp;&amp;result); // the new currency-converted stock quote service <br />
</td></tr></table><br></i>
The <i>quotex.cpp</i> client/service application source is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "quotex.cpp": <br />
#include "soapH.h" // include generated proxy and SOAP support <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;**argv) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;q; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; = 2) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<b>if</b>&nbsp;(soap_call_ns3__getQuote(&amp;soap, <tt>"http://www.cs.fsu.edu/~engelen/quotex.cgi"</tt>, <tt>""</tt>, argv[1], argv[2], q)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<tt>"\nCompany&nbsp;%s:&nbsp;%f&nbsp;(%s)\n"</tt>, argv[1], q, argv[2]); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>int</b>&nbsp;ns3__getQuote(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*symbol, <b>char</b>&nbsp;*country, <b>float</b>&nbsp;&amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;q, r; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;socket = soap<tt>-&gt;</tt>socket; // save socket (stand-alone service only, does not support keep-alive) <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns1__getQuote(soap, <tt>"http://services.xmethods.net/soap"</tt>, <tt>""</tt>, symbol, &amp;q) == 0 &amp;&amp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_call_ns2__getRate(soap, <tt>"http://services.xmethods.net/soap"</tt>, NULL, <tt>"us"</tt>, country, &amp;r) == 0) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = q*r; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>socket = socket; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>socket = socket; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_FAULT; // pass soap fault messages on to the client of this app <br />
} <br />
/* Since this app is a combined client-server, it is put together with <br />
* one header file that describes all remote methods. However, as a consequence we <br />
* have to implement the methods that are not ours. Since these implementations are <br />
* never called (this code is client-side), we can make them dummies as below. <br />
*/ <br />
<b>int</b>&nbsp;ns1__getQuote(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;result) <br />
{ <b>return</b>&nbsp;SOAP_NO_METHOD; } // dummy: will never be called <br />
<b>int</b>&nbsp;ns2__getRate(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*country1, <b>char</b>&nbsp;*country2, <b>float</b>&nbsp;&amp;result) <br />
{ <b>return</b>&nbsp;SOAP_NO_METHOD; } // dummy: will never be called <br />
<br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns1", "urn:xmethods-delayed-quotes"}, <br />
&nbsp;&nbsp;&nbsp;{"ns2", "urn:xmethods-CurrencyExchange"}, <br />
&nbsp;&nbsp;&nbsp;{"ns3", "urn:quotex"}, <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
To compile:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 quotex.h</i> <br />
<i>g++ -o quotex.cgi quotex.cpp soapC.cpp soapClient.cpp soapServer.cpp stdsoap2.cpp -lsocket -lxnet -lnsl</i>
</td></tr></table><br></span>
Note: under Linux and Mac OS X you can often omit the <tt>-l</tt> libraries.
<div class="p"><!----></div>
The <i>quotex.cgi</i> executable is installed as a CGI application on the Web by
copying it in the designated directory specific to your Web server. After
this, the executable can also serve to test the service. For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>quotex.cgi IBM uk</i>
</td></tr></table><br></span>
returns the quote of <i>IBM</i> in <i>uk</i> pounds by communicating the request
and response quote from the CGI application. See
<a href="http://xmethods.com/detail.html?id=5"><tt>http://xmethods.com/detail.html?id=5</tt></a> for details on the currency
abbreviations.
<div class="p"><!----></div>
When combining clients and service functionalities, it is required to use one
header file input to the compiler. As a consequence, however, stubs and
skeletons are available for <b>all</b> remote methods, while the client part
will only use the stubs and the service part will use the skeletons. Thus,
dummy implementations of the unused remote methods need to be given which are
never called.
<div class="p"><!----></div>
Three WSDL files are created by gSOAP: <tt>ns1.wsdl</tt>, <tt>ns2.wsdl</tt>, and
<tt>ns3.wsdl</tt>. Only the <tt>ns3.wsdl</tt> file is required to be published as it
contains the description of the combined service, while the others are
generated as a side-effect (and in case you want to develop these separate
services).
<div class="p"><!----></div>
<h3><a name="tth_sEc7.3">
7.3</a>&nbsp;&nbsp;<font color="#0000FF">How to Use gSOAP for Asynchronous One-Way Message Passing</font></h3><a name="sec:oneway1">
</a>
<div class="p"><!----></div>
SOAP RPC client-server interaction is synchronous: the client blocks until the server responds to the request.
gSOAP also supports asynchronous one-way message passing and the interoperable synchronous one-way message passing over HTTP. The two styles are similar, but only the latter is interoperable and is compliant to Basic Profile 1.0. The interoperable synchronous one-way message passing style over HTTP is discussed in Section&nbsp;<a href="#sec:oneway2">7.4</a> below.
<div class="p"><!----></div>
SOAP messaging routines are declared as function prototypes, just like remote methods for SOAP RPC. However, the output parameter is a
<i><b>void</b></i> type to indicate the absence of a return value.
<div class="p"><!----></div>
For example, the following header file specifies a event message for SOAP messaging:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__event(<b>int</b>&nbsp;eventNo, <b>void</b>&nbsp;dummy);
</td></tr></table><br></i>
The gSOAP stub and skeleton compiler generates the following functions in <i>soapClient.cpp</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_send_ns__event(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;URL, <b>const</b>&nbsp;<b>char</b>&nbsp;action, <b>int</b>&nbsp;event); <br />
<b>int</b>&nbsp;soap_recv_ns__event(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;ns__event *dummy); <br />
</td></tr></table><br></i>
The <i>soap_send_ns__event</i> function transmits the message to the destination URL by opening a socket and sending the SOAP encoded
message. The socket will remain
open after the send and has to be closed with <i>soap_closesock()</i>. The open socket connection can also be used to obtain a service
response, e.g. with a <i>soap_recv</i> function call.
<div class="p"><!----></div>
The <i>soap_recv_ns__event</i> function waits for a SOAP message on the currently open socket (<i>soap.socket</i>) and fills the
<i><b>struct</b>&nbsp;ns__event</i> with the <i>ns__event</i> parameters (e.g. <i><b>int</b>&nbsp;eventNo</i>).
The <i><b>struct</b>&nbsp;ns__event</i> is automatically created by gSOAP and is a mirror image of the <i>ns__event</i> parameters:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__event <br />
{ <b>int</b>&nbsp;eventNo; <br />
}
</td></tr></table><br></i>
The gSOAP generated <i>soapServer.cpp</i> code includes a skeleton routine to accept the message.
(The skeleton routine does not respond with a SOAP response message.)
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_serve_ns__event(<b>struct</b>&nbsp;soap *soap);
</td></tr></table><br></i>
The skeleton routine calls the user-implemented <i>ns__event(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;eventNo)</i> routine (note the absence of the void
parameter!).
<div class="p"><!----></div>
As usual, the skeleton will be automatically called by the remote method request dispatcher that handles both the remote method
requests (RPCs) and messages:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
main() <br />
{ soap_serve(soap_new()); <br />
} <br />
<b>int</b>&nbsp;ns__event(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;eventNo) <br />
{ <br />
&nbsp;&nbsp;&nbsp;... // handle event <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc7.4">
7.4</a>&nbsp;&nbsp;<font color="#0000FF">One-Way Message Passing over HTTP</font></h3><a name="sec:oneway2">
</a>
<div class="p"><!----></div>
One-way SOAP message passing over HTTP as defined by the SOAP specification and Basic Profile 1.0 is synchrounous, meaning that the server must respond with an HTTP OK header and an empty body. To implement synchrounous one-way messaging, the same setup for asynchrounous one-way messaing discussed in Section&nbsp;<a href="#sec:oneway1">7.3</a> is used, but with one simple addition at the client and server side.
<div class="p"><!----></div>
At the server side, we need to return an empty HTTP OK response. This is accomplished as follows. For each one-way operation implemented in C/C++, we replace the <i><b>return</b>&nbsp;SOAP_OK</i> with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__event(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;eventNo) <br />
{ <br />
&nbsp;&nbsp;&nbsp;... // handle event <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_send_empty_response(soap); <br />
}
</td></tr></table><br></i>
At the client side, the empty response header must be parsed as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>if</b>&nbsp;(soap_send_ns__event(soap, eventNo) != SOAP_OK <br />
&nbsp;&nbsp;&nbsp;<font face="symbol">|</font
><font face="symbol">|</font
> soap_recv_empty_response(soap) != SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(soap, stderr); <br />
...
</td></tr></table><br></i>
The synchronous (and asynchronous) one-way messaging supports HTTP keep-alive and chunking.
<div class="p"><!----></div>
<h3><a name="tth_sEc7.5">
7.5</a>&nbsp;&nbsp;<font color="#0000FF">How to Use the SOAP Serializers and Deserializers to Save and Load Application Data</font></h3>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler generates serializers and deserializers for all user-defined data structures that are
specified in the header file input to the compiler. The serializers and deserializers can be found in the generated
<i>soapC.cpp</i> file. These serializers and deserializers can be used separately by an application without the need to build a
full client or service application. This is useful for applications that need to save or export their data in XML or need to
import or load data stored in XML format.
<div class="p"><!----></div>
The following attributes can be set to control the destination and source for serialization and deserialization:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Variable</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i><b>int</b>&nbsp;soap.socket</i> </td><td>socket file descriptor for input and output or -1 </td></tr>
<tr><td><i>ostream *soap.os</i> </td><td>(C++ only) output stream used for send operations </td></tr>
<tr><td><i>istream *soap.is</i> </td><td>(C++ only) input stream used for receive operations </td></tr>
<tr><td><i><b>int</b>&nbsp;soap.sendfd</i> </td><td>when <i>soap_socket</i> &lt; 0, this fd is used for send operations </td></tr>
<tr><td><i><b>int</b>&nbsp;soap.recvfd</i> </td><td>when <i>soap_socket</i> &lt; 0, this fd is used for receive operations </td></tr></table>
</td></tr></table><br></span>
The following initializing and finalizing functions can be used:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i><b>void</b>&nbsp;soap_begin_send(<b>struct</b>&nbsp;soap*)</i> </td><td>start a send/write phase </td></tr>
<tr><td><i><b>int</b>&nbsp;soap_end_send(<b>struct</b>&nbsp;soap*)</i> </td><td>flush the buffer </td></tr>
<tr><td><i><b>int</b>&nbsp;soap_begin_recv(<b>struct</b>&nbsp;soap*)</i> </td><td>start a rec/read phase (if an HTTP header is present, parse it first) </td></tr>
<tr><td><i><b>int</b>&nbsp;soap_end_recv(<b>struct</b>&nbsp;soap*)</i> </td><td>perform a id/href consistency check on deserialized data </td></tr></table>
</td></tr></table><br></span>
These operations do not open or close the connections. The application should open and close connections or files and set the <i>soap.socket</i>, <i>soap.os</i> or <i>soap.sendfd</i>, <i>soap.is</i> or <i>soap.recvfd</i> streams or descriptors.
When <i>soap.socket</i> &lt; 0 and none of the streams and descriptors are set, then the standard input and output will be used.
<div class="p"><!----></div>
See also Section&nbsp;<a href="#sec:flags">8.12</a> to control the I/O buffering and content encoding such as compression and DIME encoding.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.5.1">
7.5.1</a>&nbsp;&nbsp;<font color="#0000FF">Serializing a Data Type</font></h4><a name="sec:serialize">
</a>
<div class="p"><!----></div>
To serialize a data type to a stream, two functions should be called to prepare
for serialization of the data and to send the data, respectively. The first function,
<i>soap_serialize</i>, analyzes pointers and determines if multi-references
are required to encode the data and if cycles are present the object graph.
The second function, <i>soap_put</i>, produces the XML output on a stream.
<div class="p"><!----></div>
The <i>soap_serialize</i> and <i>soap_put</i> function names are specific to a
data type. For example, <i>soap_serialize_float(&amp;soap, &amp;d)</i> is called to
serialize an <i><b>float</b></i> value and <i>soap_put_float(&amp;soap, &amp;d,
"number", NULL)</i> is called to output the floating point value in SOAP tagged
with the name <tt>&lt;number&#62;</tt>. To initialize data, the <i>soap_default</i>
function of a data type can be used. For example,
<i>soap_default_float(&amp;soap, &amp;d)</i> initializes the float to 0.0. The
<i>soap_default</i> functions are useful to initialize complex data types such
as arrays, <i><b>struct</b></i>s, and <i><b>class</b></i> instances. Note that the
<i>soap_default</i> functions do not need the gSOAP runtime environment as a
first parameter.
<div class="p"><!----></div>
The following table lists the type naming conventions used by gSOAP:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Type</b></font> </td><td><font color="#FF0000"><b>Type Name</b></font> </td></tr>
<tr><td><i><b>char</b>*</i> </td><td><i>string</i> </td></tr>
<tr><td><i>wchar_t*</i> </td><td><i>wstring</i> </td></tr>
<tr><td><i><b>char</b></i> </td><td><i>byte</i> </td></tr>
<tr><td><i><b>bool</b></i> </td><td><i>bool</i> </td></tr>
<tr><td><i><b>double</b></i> </td><td><i>double</i> </td></tr>
<tr><td><i><b>int</b></i> </td><td><i>int</i> </td></tr>
<tr><td><i><b>float</b></i> </td><td><i>float</i> </td></tr>
<tr><td><i><b>long</b></i> </td><td><i>long</i> </td></tr>
<tr><td><i>LONG64</i> </td><td><i>LONG64</i> (Win32) </td></tr>
<tr><td><i><b>long</b>&nbsp;<b>long</b></i> </td><td><i>LONG64</i> (Unix/Linux) </td></tr>
<tr><td><i><b>short</b></i> </td><td><i>short</i> </td></tr>
<tr><td><i>time_t</i> </td><td><i>time</i> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>char</b></i> </td><td><i>unsignedByte</i> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>int</b></i> </td><td><i>unsignedInt</i> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b></i> </td><td><i>unsignedLong</i> </td></tr>
<tr><td><i>ULONG64</i> </td><td><i>unsignedLONG64</i> (Win32)</td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b></i> </td><td><i>unsignedLONG64</i> (Unix/Linux) </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>short</b></i> </td><td><i>unsignedShort</i> </td></tr>
<tr><td><i><u><span class="roman">T</span></u><span class="roman">[</span><u><span class="roman">N</span></u><span class="roman">]</span></i> </td><td><i>Array<u><span class="roman">N</span></u>Of<u><span class="roman">Type</span></u></i> where <u>Type</u> is the type name of <u>T</u> </td></tr>
<tr><td><i><u><span class="roman">T</span></u>*</i> </td><td><i>PointerTo<u><span class="roman">Type</span></u></i> where <u>Type</u> is the type name of <u>T</u> </td></tr>
<tr><td><i><b>struct</b>&nbsp;Name</i> </td><td><i>Name</i> </td></tr>
<tr><td><i><b>class</b>&nbsp;Name</i> </td><td><i>Name</i> </td></tr>
<tr><td><i><b>enum</b>&nbsp;Name</i> </td><td><i>Name</i> </td></tr></table>
</td></tr></table><br></span>
Consider for example the following C code with a declaration of <i>p</i> as a
pointer to a <i><b>struct</b>&nbsp;ns__Person</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__Person { <b>char</b>&nbsp;*name; } *p;
</td></tr></table><br></i>
To serialize <i>p</i>, its address is passed to the function
<i>soap_serialize_PointerTons__Person</i> generated for this type by the
gSOAP compiler:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_serialize_PointerTons__Person(&amp;soap, &amp;p);
</td></tr></table><br></i>
The <b>address of</b> <i>p</i> is passed, so the serializer can determine whether
<i>p</i> was already serialized and to discover cycles in graph data structures.
To generate the output, the address of <i>p</i> is passed to the function
<i>soap_put_PointerTons__Person</i> together with the name of an XML element
and an optional type string (to omit a type, use <i>NULL</i>):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_begin_send(&amp;soap); <br />
soap_put_PointerTons__Person(&amp;soap, &amp;p, "ns:element-name", "ns:type-name"); <br />
soap_end_send(&amp;soap);
</td></tr></table><br></i>
This produces:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:element-name xmlns:SOAP-ENV="..." xmlns:SOAP-ENC="..." xmlns:ns="..." <br />
&nbsp;&nbsp;&nbsp;... xsi:type="ns:type-name"&#62; <br />
&lt;name xsi:type="xsd:string"&#62;...&lt;/name&#62; <br />
&lt;/ns:element-name&#62;
</td></tr></table><br></tt>
The serializer is initialized with the <i>soap_begin_send(soap)</i> function
and closed with <i>soap_end_send(soap)</i>. All temporary data structures and
data structures deserialized on the heap are destroyed with the
<i>soap_end()</i> function. The <i>soap_free()</i> function can be used to
remove the temporary data only and keep the deserialized data on the heap.
Temporary data structures are only created if the encoded data uses pointers.
Each pointer in the encoded data has an internal hash table entry to determine
all multi-reference parts and cyclic parts of the complete data structure.
<div class="p"><!----></div>
You can assign an
output stream to <i>soap.os</i> or a file descriptor to <i>soap.sendfd</i>.
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap.sendfd = open(file, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR); <br />
soap_serialize_PointerTons__Person(&amp;soap, &amp;p); <br />
soap_begin_send(&amp;soap); <br />
soap_put_PointerTons__Person(&amp;soap, &amp;p, "ns:element-name", "ns:type-name"); <br />
soap_end_send(&amp;soap);
</td></tr></table><br></i>
The <i>soap_serialize</i> function is optional. It MUST be used when
the object graph contains cycles.
It MUST be called to preserved the logical coherence of pointer-based
data structures, where pointers may refer to co-referenced objects.
By calling <i>soap_serialize</i>, data structures shared through pointers are serialized only once and
referenced in XML using id-refs attributes.
This actual id-refs used depend on the SOAP encoding. To turn off SOAP encoding,
remove or avoid using the SOAP-ENV and SOAP-ENC namespace bindings in the namespace table.
In addition, the <i>SOAP_XML_TREE</i> and <i>SOAP_XML_GRAPH</i> flags can be used
to control the output.
<div class="p"><!----></div>
To save the data as an XML tree (with one root) without any id-ref attributes, use the
<i>SOAP_XML_TREE</i> flag. The data structure MUST NOT contain pointer-based cycles.
<div class="p"><!----></div>
To preserve the exact structure of the data object graph and create XML with one root, use
the <i>SOAP_XML_GRAPH</i> output-mode flag (see
Section&nbsp;<a href="#sec:flags">8.12</a>). Use this flag and the <i>soap_serialize</i> function
to prepare the serialization of data with in-line id-ref attributes.
Using the <i>SOAP_XML_GRAPH</i> flag assures the preservation of the logical structure of the data
<div class="p"><!----></div>
For example, to encode the contents of two variables <i>var1</i> and <i>var2</i> that may
share data throug pointer structures,
the serializers are called before the output routines:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<u><span class="roman">T1</span></u> var1; <br />
<u><span class="roman">T2</span></u> var2; <br />
<b>struct</b>&nbsp;soap soap; <br />
... <br />
soap_init(&amp;soap); // initialize <br />
<font size="+1"><span class="roman">[</span></font>soap_omode(&amp;soap, flags);<font size="+1"><span class="roman">]</span></font> // set output-mode flags (e.g. SOAP_ENC_XML<tt>|</tt>SOAP_ENC_ZLIB) <br />
soap_begin(&amp;soap); // start new (de)serialization phase <br />
soap_set_omode(&amp;soap, SOAP_XML_GRAPH); <br />
soap_serialize_<u><span class="roman">Type1</span></u>(&amp;soap, &amp;var1); <br />
soap_serialize_<u><span class="roman">Type2</span></u>(&amp;soap, &amp;var2); <br />
... <br />
<font size="+1"><span class="roman">[</span></font>soap.socket = a_socket_file_descriptor;<font size="+1"><span class="roman">]</span></font> // when using sockets <br />
<font size="+1"><span class="roman">[</span></font>soap.os = an_output_stream;<font size="+1"><span class="roman">]</span></font> // C++ <br />
<font size="+1"><span class="roman">[</span></font>soap.sendfd = an_output_file_descriptor;<font size="+1"><span class="roman">]</span></font> // C <br />
soap_begin_send(&amp;soap); <br />
soap_put_<u><span class="roman">Type1</span></u>(&amp;soap, &amp;var1, "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name1", "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1"); <br />
soap_put_<u><span class="roman">Type2</span></u>(&amp;soap, &amp;var2, "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name2", "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name2"); <br />
... <br />
soap_end_send(&amp;soap); // flush <br />
soap_end(&amp;soap); // remove temporary data structures after phase <br />
soap_done(&amp;soap); // finalize last use of this environment <br />
...
</td></tr></table><br></i>
where <u>Type1</u> is the type name of <u>T1</u> and
<u>Type2</u> is the type name of <u>T2</u> (see table above). The
strings <i><font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1</i> and
<i><font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name2</i> describe the schema types of the
elements. Use <i>NULL</i> to omit this type information.
<div class="p"><!----></div>
For serializing class instances, method invocations MUST be used instead of function calls, for example
<i>obj.soap_serialize(&amp;soap)</i> and <i>obj.soap_put(&amp;soap, "elt", "type")</i>. This ensures that the proper serializers are used for
serializing instances of derived classes.
<div class="p"><!----></div>
You can serialize a class instance to a stream as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
myClass obj; <br />
soap_init(&amp;soap); // initialize <br />
soap_begin(&amp;soap); // start new (de)serialization phase <br />
soap_set_omode(&amp;soap, SOAP_XML_GRAPH); <br />
obj.serialize(&amp;soap); <br />
soap.os = cout; // send to cout <br />
soap_begin_send(&amp;soap); <br />
obj.put(&amp;soap, "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name1", "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1"); <br />
... <br />
soap_end_send(&amp;soap); // flush <br />
soap_end(&amp;soap); // remove temporary data structures after phase <br />
soap_done(&amp;soap); // finalize last use of this environment
</td></tr></table><br></i>
When you declare a soap struct pointer as a data member in a class, you can overload the <tt>&lt;&lt;</tt> operator to serialize the class to streams:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
ostream &amp;operator<tt>&lt;&lt;</tt>(ostream &amp;o, <b>const</b>&nbsp;myClass &amp;e) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!e.soap) <br />
&nbsp;&nbsp;&nbsp;... error: need a soap struct to serialize (could use global struct) ... <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ostream *os = e.soap<tt>-&gt;</tt>os; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.soap<tt>-&gt;</tt>os = &amp;o; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_set_omode(e.soap, SOAP_XML_GRAPH);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.serialize(e.soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_begin_send(e.soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.put(e.soap, "myClass", NULL); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end_send(e.soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.soap<tt>-&gt;</tt>os = os; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_clr_omode(e.soap, SOAP_XML_GRAPH); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;o; <br />
}
</td></tr></table><br></i>
Of course, when you construct an instance you must set its soap struct to a valid environment. Deserialized class instances with a soap struct data member will have their soap structs set automatically, see Section&nbsp;<a href="#sec:classmemory">8.13.2</a>.
<div class="p"><!----></div>
In principle, XML output for a data structure can be produced with <i>soap_put</i>
without calling the <i>soap_serialize</i> function first.
In this case, the result is similar to <i>SOAP_XML_TREE</i> which
means that no id-refs are output. Cycles in the data structure will crash the serialization
algorithm, even when the <i>SOAP_XML_GRAPH</i> is set.
<div class="p"><!----></div>
Consider the following <i><b>struct</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "tricky.h": <br />
<b>struct</b>&nbsp;Tricky<br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;*p; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;n; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;*q; <br />
};
</td></tr></table><br></i>
The following fragment initializes the pointer fields <i>p</i> and <i>q</i> to the value of field <i>n</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
<b>struct</b>&nbsp;Tricky X; <br />
X.n = 1; <br />
X.p = &amp;X.n; <br />
X.q = &amp;X.n; <br />
soap_init(&amp;soap); <br />
soap_begin(&amp;soap); <br />
soap_serialize_Tricky(&amp;soap, &amp;X); <br />
soap_put_Tricky(&amp;soap, &amp;X, <tt>"Tricky"</tt>, NULL); <br />
soap_end(&amp;soap); // Clean up temporary data used by the serializer
</td></tr></table><br></i>
What is special about this data structure is that <i>n</i> is 'fixed' in the <i>Tricky</i> structure, and <i>p</i> and <i>q</i> both point to <i>n</i>. The gSOAP serializers strategically place the id-ref attributes such that <i>n</i> will be identified as the primary data source, while <i>p</i> and <i>q</i> are serialized with ref/href attributes.
<div class="p"><!----></div>
The resulting output is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;Tricky xsi:type="Tricky"&#62; <br />
&lt;p href="#2"/&#62;
&lt;n xsi:type="int"&#62;1&lt;/n&#62;
&lt;q href="#2"/&#62;
&lt;r xsi:type="int"&#62;2&lt;/r&#62;
&lt;/Tricky&#62;
&lt;id id="2" xsi:type="int"&#62;1&lt;/id&#62;
</td></tr></table><br></tt>
which uses an independent element at the end to represent the multi-referenced integer, assuming the <i>SOAP-ENV</i> and <i>SOAP-ENC</i> namespaces indicate SOAP 1.1 encoding.
<div class="p"><!----></div>
With the <i>SOAP_XML_GRAPH</i> flag the output is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;Tricky xsi:type="Tricky"&#62; <br />
&lt;p href="#2"/&#62;
&lt;n id="2" xsi:type="int"&#62;1&lt;/n&#62;
&lt;q href="#2"/&#62;
&lt;/Tricky&#62;
</td></tr></table><br></tt>
In this case, the XML is self-contained and multi-referenced data is accurately serialized.
The gSOAP generated deserializer for this data type will be able to accurately reconstruct the data from the XML (on the heap).
<div class="p"><!----></div>
<h4><a name="tth_sEc7.5.2">
7.5.2</a>&nbsp;&nbsp;<font color="#0000FF">Deserializing a Data Type</font></h4><a name="sec:deserialize">
</a>
<div class="p"><!----></div>
To deserialize a data type, its <i>soap_get</i> function is used. The outline of a program that deserializes two variables <i>var1</i> and <i>var2</i> is for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<u><span class="roman">T1</span></u> var1; <br />
<u><span class="roman">T2</span></u> var2; <br />
<b>struct</b>&nbsp;soap soap; <br />
... <br />
soap_init(&amp;soap); // initialize at least once <br />
<font size="+1"><span class="roman">[</span></font>soap_imode(&amp;soap, flags);<font size="+1"><span class="roman">]</span></font> // set input-mode flags <br />
soap_begin(&amp;soap); // begin new decoding phase <br />
<font size="+1"><span class="roman">[</span></font>soap.is = an_input_stream;<font size="+1"><span class="roman">]</span></font> // C++ <br />
<font size="+1"><span class="roman">[</span></font>soap.recvfd = an_input_file_desriptpr;<font size="+1"><span class="roman">]</span></font> // C <br />
soap_begin_recv(&amp;soap); // if HTTP/MIME/DIME/GZIP headers are present, parse them <br />
<b>if</b>&nbsp;(!soap_get_<u><span class="roman">Type1</span></u>(&amp;soap, &amp;var1, "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name1", "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1")) <br />
&nbsp;&nbsp;&nbsp;... error ... <br />
<b>if</b>&nbsp;(!soap_get_<u><span class="roman">Type2</span></u>(&amp;soap, &amp;var2, "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name2", "<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1")) <br />
&nbsp;&nbsp;&nbsp;... error ... <br />
... <br />
soap_end_recv(&amp;soap); // check consistency of id/hrefs <br />
soap_destroy(&amp;soap); // remove deserialized class instances <br />
soap_end(&amp;soap); // remove temporary data, including the decoded data on the heap <br />
soap_done(&amp;soap); // finalize last use of the environment
</td></tr></table><br></i>
The strings <i><font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name1</i> and
<i><font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>type-name2</i> are the schema types of the elements
and should match the <tt>xsi:type</tt> attribute of the receiving message. To omit
the match, use <i>NULL</i> as the type. For class instances, method invocation
can be used instead of a function call if the object is already instantiated,
i.e. <i>obj.soap_get(&amp;soap, "...", "...")</i>.
<div class="p"><!----></div>
The <i>soap_begin</i> call resets the deserializers. The <i>soap_destroy</i>
and <i>soap_end</i> calls remove the temporary data structures <b>and</b> the
decoded data that was placed on the heap.
<div class="p"><!----></div>
To remove temporary data while retaining the deserialized data on the heap, the
function <i>soap_free</i> should be called instead of <i>soap_destroy</i> and
<i>soap_end</i>.
<div class="p"><!----></div>
One call to the <i>soap_get_Type</i> function of a type <i>Type</i> scans the
entire input to process its XML content and to capture SOAP 1.1 independent
elements (which contain multi-referenced objects). As a result, <i>soap.error</i> will set to <i>SOAP_EOF</i>.
Also storing
multiple objects into one file will fail to decode them properly with multiple <i>soap_get</i> calls. A well-formed XML document should
only have one root anyway, so don't save multiple objects into one file. If you
must save multiple objects, create a linked list or an array of objects and save
the linked list or array. You could use the <i>soap_in_Type</i> function instead of the <i>soap_get_Type</i> function. The <i>soap_in_Type</i> function parses one XML element at a time.
<div class="p"><!----></div>
You can deserialize class instances from a stream as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
myClass obj; <br />
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); // initialize <br />
soap_begin(&amp;soap); // begin new decoding phase <br />
soap.is = cin; // read from cin <br />
soap_begin_recv(&amp;soap); // if HTTP header is present, parse it <br />
<b>if</b>&nbsp;(!obj.get(&amp;soap, "myClass", NULL) <br />
&nbsp;&nbsp;&nbsp;... error ... <br />
soap_end_recv(&amp;soap); // check consistency of id/hrefs <br />
... <br />
soap_destroy(&amp;soap); // remove deserialized class instances <br />
soap_end(&amp;soap); // remove temporary data, including the decoded data on the heap <br />
soap_done(&amp;soap); // finalize last use of the environment
</td></tr></table><br></i>
When you declare a soap struct pointer as a data member in a class, you can overload the <tt>&gt;&gt;</tt> operator to parse and deserialize a class instance from a stream:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
istream &amp;operator<tt>&gt;&gt;</tt>(istream &amp;i, myClass &amp;e) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!e.soap) <br />
&nbsp;&nbsp;&nbsp;... error: need soap struct to deserialize (could use global struct)... <br />
&nbsp;&nbsp;&nbsp;istream *is = e.soap<tt>-&gt;</tt>is; <br />
&nbsp;&nbsp;&nbsp;e.soap<tt>-&gt;</tt>is = &amp;i; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_begin_recv(e.soap) <tt>||</tt> e.in(e.soap, NULL, NULL) <tt>||</tt> soap_end_recv(e.soap)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... error ... <br />
&nbsp;&nbsp;&nbsp;e.soap<tt>-&gt;</tt>is = is; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;i; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.5.3">
7.5.3</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4><a name="sec:example9">
</a>
<div class="p"><!----></div>
As an example, consider the following data type declarations:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "person.h": <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__Name; <br />
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>int</b>&nbsp;xsd__unsignedInt; <br />
<b>enum</b>&nbsp;ns__Gender {male, female}; <br />
<b>class</b>&nbsp;ns__Address <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;xsd__string street; <br />
&nbsp;&nbsp;&nbsp;xsd__unsignedInt number; <br />
&nbsp;&nbsp;&nbsp;xsd__string city; <br />
}; <br />
<b>class</b>&nbsp;ns__Person <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;xsd__Name name; <br />
&nbsp;&nbsp;&nbsp;<b>enum</b>&nbsp;ns__Gender gender; <br />
&nbsp;&nbsp;&nbsp;ns__Address address; <br />
&nbsp;&nbsp;&nbsp;ns__Person *mother; <br />
&nbsp;&nbsp;&nbsp;ns__Person *father; <br />
};
</td></tr></table><br></i>
The following program uses these data types to write to standard output a data structure that contains the data of a person named "John" living at Downing st. 10 in Londen. He has a mother
"Mary" and a father "Stuart". After initialization, the class instance for "John" is serialized and encoded in XML to the
standard output stream using gzip compression (requires the Zlib library, compile sources with -DWITH_GZIP):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "person.cpp": <br />
#include "soapH.h" <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;ns__Person mother, father, john; <br />
&nbsp;&nbsp;&nbsp;mother.name = <tt>"Mary"</tt>; <br />
&nbsp;&nbsp;&nbsp;mother.gender = female; <br />
&nbsp;&nbsp;&nbsp;mother.address.street = <tt>"Downing&nbsp;st."</tt>; <br />
&nbsp;&nbsp;&nbsp;mother.address.number = 10; <br />
&nbsp;&nbsp;&nbsp;mother.address.city = <tt>"London"</tt>; <br />
&nbsp;&nbsp;&nbsp;mother.mother = NULL; <br />
&nbsp;&nbsp;&nbsp;mother.father = NULL; <br />
&nbsp;&nbsp;&nbsp;father.name = <tt>"Stuart"</tt>; <br />
&nbsp;&nbsp;&nbsp;father.gender = male; <br />
&nbsp;&nbsp;&nbsp;father.address.street = <tt>"Main&nbsp;st."</tt>; <br />
&nbsp;&nbsp;&nbsp;father.address.number = 5; <br />
&nbsp;&nbsp;&nbsp;father.address.city = <tt>"London"</tt>; <br />
&nbsp;&nbsp;&nbsp;father.mother = NULL; <br />
&nbsp;&nbsp;&nbsp;father.father = NULL; <br />
&nbsp;&nbsp;&nbsp;john.name = <tt>"John"</tt>; <br />
&nbsp;&nbsp;&nbsp;john.gender = male; <br />
&nbsp;&nbsp;&nbsp;john.address = mother.address; <br />
&nbsp;&nbsp;&nbsp;john.mother = &amp;mother; <br />
&nbsp;&nbsp;&nbsp;john.father = &amp;father; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_omode(&amp;soap, SOAP_ENC_ZLIB | SOAP_XML_GRAPH); // see&nbsp;<a href="#sec:flags">8.12</a> <br />
&nbsp;&nbsp;&nbsp;soap_begin(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_begin_send(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;john.soap_serialize(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;john.soap_put(&amp;soap, <tt>"johnnie"</tt>, NULL); <br />
&nbsp;&nbsp;&nbsp;soap_end_send(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); <br />
} <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns", "urn:person"}, // Namespace URI of the "Person" data type <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
The header file is processed and the application compiled on Linux/Unix with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 person.h</i> <br />
<i>g++ -DWITH_GZIP -o person person.cpp soapC.cpp stdsoap2.cpp -lsocket -lxnet -lnsl -lz</i>
</td></tr></table><br></span>
(Depending on your system configuration, the libraries <i>libsocket.a</i>,
<i>libxnet.a</i>, <i>libnsl.a</i>
are required. Compiling on Linux typically does not require the inclusion of those
libraries.)
See&nbsp;<a href="#sec:compression">18.25</a> for details on compression with gSOAP.
<div class="p"><!----></div>
Running the <i>person</i> application results in the compressed XML output:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;johnnie xsi:type="ns:Person" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns="urn:person" <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&lt;name xsi:type="xsd:Name"&#62;John&lt;/name&#62; <br />
&lt;gender xsi:type="ns:Gender"&#62;male&lt;/gender&#62; <br />
&lt;address xsi:type="ns:Address"&#62; <br />
&lt;street id="3" xsi:type="xsd:string"&#62;Dowling st.&lt;/street&#62; <br />
&lt;number xsi:type="unsignedInt"&#62;10&lt;/number&#62; <br />
&lt;city id="4" xsi:type="xsd:string"&#62;London&lt;/city&#62; <br />
&lt;/address&#62; <br />
&lt;mother xsi:type="ns:Person"&#62; <br />
&lt;name xsi:type="xsd:Name"&#62;Mary&lt;/name&#62; <br />
&lt;gender xsi:type="ns:Gender"&#62;female&lt;/gender&#62; <br />
&lt;address xsi:type="ns:Address"&#62; <br />
&lt;street href="#3"/&#62; <br />
&lt;number xsi:type="unsignedInt"&#62;5&lt;/number&#62; <br />
&lt;city href="#4"/&#62; <br />
&lt;/address&#62; <br />
&lt;/mother&#62; <br />
&lt;father xsi:type="ns:Person"&#62; <br />
&lt;name xsi:type="xsd:Name"&#62;Stuart&lt;/name&#62; <br />
&lt;gender xsi:type="ns:Gender"&#62;male&lt;/gender&#62; <br />
&lt;address xsi:type="ns:Address"&#62; <br />
&lt;street xsi:type="xsd:string"&#62;Main st.&lt;/street&#62; <br />
&lt;number xsi:type="unsignedInt"&#62;13&lt;/number&#62; <br />
&lt;city href="#4"/&#62; <br />
&lt;/address&#62; <br />
&lt;/father&#62; <br />
&lt;/johnnie&#62;
</td></tr></table><br></tt>
The following program fragment decodes this content from standard input and reconstructs the original data structure on the heap:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;ns__Person *mother, *father, *john = NULL; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_imode(&amp;soap, SOAP_ENC_ZLIB); // optional: gzip is detected automatically <br />
&nbsp;&nbsp;&nbsp;soap_begin(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_begin_recv(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_get_ns__Person(&amp;soap, john, "johnnie", NULL) == NULL) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... error ... <br />
&nbsp;&nbsp;&nbsp;mother = john<tt>-&gt;</tt>mother; <br />
&nbsp;&nbsp;&nbsp;father = john<tt>-&gt;</tt>father; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_end_recv(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_free(&amp;soap); // Clean up temporary data but keep deserialized data <br />
} <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns", "urn:person"}, // Namespace URI of the "Person" data type <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
};
</td></tr></table><br></i>
It is REQUIRED to either pass <i>NULL</i> to the <i>soap_get</i> routine, or a valid pointer to a data structure that can
hold the decoded content. The following example explicitly passes <i>NULL</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
&nbsp;&nbsp;&nbsp;john = soap_get_ns__Person(&amp;soap, NULL, "johnnie", NULL); <br />
</td></tr></table><br></i>
Note: the second <i>NULL</i> parameter indicates that the schema type attribute of the receiving message can be ignored.
The deserializer stores the SOAP contents on the heap, and returns the address. The allocated storage is released with the
<i>soap_end</i> call, which removes all temporary and deserialized data from the heap, or with the <i>soap_free</i> call, which removes all
temporary data only.
<div class="p"><!----></div>
Alternatively, the XML content can be decoded within an existing allocated data structure.
The following program fragment decodes the SOAP content in a <i><b>struct</b>&nbsp;ns__Person</i> allocated on the stack:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
main() <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;ns__Person *mother, *father, john; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_imode(&amp;soap, SOAP_ENC_ZLIB); // optional <br />
&nbsp;&nbsp;&nbsp;soap_begin(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_begin_recv(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_default_ns__Person(&amp;soap, &amp;john); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_get_ns__Person(&amp;soap, &amp;john, "johnnie", NULL) == NULL) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... error ... <br />
&nbsp;&nbsp;&nbsp;... <br />
} <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
&nbsp;&nbsp;&nbsp;...
</td></tr></table><br></i>
Note the use of <i>soap_default_ns__Person</i>. This routine is generated by the gSOAP stub and skeleton compiler and assigns default
values to the fields of <i>john</i>.
<div class="p"><!----></div>
<h4><a name="tth_sEc7.5.4">
7.5.4</a>&nbsp;&nbsp;<font color="#0000FF">Serializing and Deserializing Class Instances to Streams</font></h4>
<div class="p"><!----></div>
C++ applications can define appropriate stream operations on objects for (de)serialization of objects on streams.
This is best illustrated with an example.
Consider the class
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;ns__person <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap; // we need this, see below <br />
&nbsp;&nbsp;&nbsp;ns__person(); <br />
&nbsp;&nbsp;&nbsp;~ns__person(); <br />
};
</td></tr></table><br></i>
The <i><b>struct</b>&nbsp;soap</i> member is used to bind the instances to a gSOAP
environment for (de)serialization. We use the gSOAP compiler from the command
prompt to generate the class (de)serializers (assuming that <i>person.h</i>
contains the class declaration):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 person.h</i>
</td></tr></table><br></span>
gSOAP generates the (de)serializers and an instantiation function for the class
<i>soap_new_ns__person(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;array)</i> to instantiate
one or more objects and associate them with a gSOAP environment. The
<i>array</i> parameter should be -1 to instantiate one object or should be the
number of objects to instantiate as an array of objects.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include "ns.nsmap" <br />
... <br />
<b>struct</b>&nbsp;soap *soap = soap_new(); <br />
ns__person *p = soap_new_ns__person(soap, -1); <br />
... <br />
cout &lt;&lt; p; // serialize p in XML <br />
... <br />
in &gt;&gt; p; // parse XML and deserialize p <br />
... <br />
soap_destroy(soap); // deletes p too <br />
soap_end(soap); <br />
soap_done(soap);
</td></tr></table><br></i>
The stream operations are implemented as follows
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
ostream &amp;<b>operator</b><tt>&lt;&lt;</tt>(ostream &amp;o, <b>const</b>&nbsp;ns__person &amp;p) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!p<tt>-&gt;</tt>soap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;o; // need a gSOAP environment to serialize <br />
&nbsp;&nbsp;&nbsp;p.soap<tt>-&gt;</tt>os = &amp;o; <br />
&nbsp;&nbsp;&nbsp;soap_omode(p.soap, SOAP_XML_GRAPH); // XML tree or graph <br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>soap_serialize(p.soap); <br />
&nbsp;&nbsp;&nbsp;soap_begin_send(p.soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(p<tt>-&gt;</tt>soap_put(p.soap, "person", NULL) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | | soap_end_send(p.soap)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; // handle I/O error <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;o; <br />
} <br />
istream &amp;<b>operator</b><tt>&gt;&gt;</tt>(istream &amp;i, ns__person &amp;p) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!p<tt>-&gt;</tt>soap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;o; // need a gSOAP environment to parse XML and deserialize <br />
&nbsp;&nbsp;&nbsp;p.soap<tt>-&gt;</tt>is = &amp;i; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_begin_recv(p.soap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | | p<tt>-&gt;</tt>soap_in(p.soap, NULL, NULL) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | | soap_end_recv(p.soap)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; // handle I/O error <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;i; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h4><a name="tth_sEc7.5.5">
7.5.5</a>&nbsp;&nbsp;<font color="#0000FF">How to Specify Default Values for Omitted Data</font></h4>
<div class="p"><!----></div>
The gSOAP compiler generates <i>soap_default</i> functions for all data types. The default values of the primitive types can be
easily changed by defining any of the following macros in the <i>stdsoap2.h</i> file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define SOAP_DEFAULT_bool <br />
#define SOAP_DEFAULT_byte <br />
#define SOAP_DEFAULT_double <br />
#define SOAP_DEFAULT_float <br />
#define SOAP_DEFAULT_int <br />
#define SOAP_DEFAULT_long <br />
#define SOAP_DEFAULT_LONG64 <br />
#define SOAP_DEFAULT_short <br />
#define SOAP_DEFAULT_string <br />
#define SOAP_DEFAULT_time <br />
#define SOAP_DEFAULT_unsignedByte <br />
#define SOAP_DEFAULT_unsignedInt <br />
#define SOAP_DEFAULT_unsignedLong <br />
#define SOAP_DEFAULT_unsignedLONG64 <br />
#define SOAP_DEFAULT_unsignedShort <br />
#define SOAP_DEFAULT_wstring
</td></tr></table><br></i>
Instead of adding these to <i>stdsoap2.h</i>, you can also compile with option <i>-DWITH_SOAPDEFS_H</i> and include your
definitions in file <i>userdefs.h</i>.
The absence of a data value in a receiving SOAP message will result in the assignment of a default value to a primitive type upon
deserialization.
<div class="p"><!----></div>
Default values can also be assigned to individual <i><b>struct</b></i> and <i><b>class</b></i> fields of primitive type. For example,
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;MyRecord <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name = "Unknown"; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;value = 9999; <br />
&nbsp;&nbsp;&nbsp;<b>enum</b>&nbsp;Status { active, passive } status = passive; <br />
}
</td></tr></table><br></i>
Default values are assigned to the fields on receiving a SOAP/XML message in which the data values are absent.
<div class="p"><!----></div>
Because method requests and responses are essentially structs, default values can also be assigned to method parameters. The
default parameter values do not control the parameterization of C/C++ function calls, i.e. all actual parameters must be present
when calling a function. The default parameter values are used in case an inbound request or response message lacks the XML
elements with parameter values. For example, a Web service can use default values to fill-in absent parameters in a
SOAP/XML request:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__login(<b>char</b>&nbsp;*uid = "anonymous", <b>char</b>&nbsp;*pwd = "guest", <b>bool</b>&nbsp;granted);
</td></tr></table><br></i>
When the request message lacks uid and pwd parameters, e.g.:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns="http://tempuri.org"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;SOAP-ENV:Body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ns:login&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ns:login&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
then the service uses the default values.
In addition, the default values will show up in the SOAP/XML request and response message examples generated by the gSOAP
compiler.
<div class="p"><!----></div>
<h2><a name="tth_sEc8">
8</a>&nbsp;&nbsp;<font color="#0000FF">Using the gSOAP Stub and Skeleton Compiler</font></h2>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler is invoked from the command line and optionally takes the name of a header file as an
argument or, when the file name is absent, parses the standard input:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 <font size="+1"><span class="roman">[</span></font>aheaderfile.h<font size="+1"><span class="roman">]</span></font></i>
</td></tr></table><br></span>
where <i>aheaderfile.h</i> is a standard C++ header file. The compiler acts as a preprocessor and produces C++ source files that
can be used to build SOAP client and Web service applications in C++. The files generated by the compiler are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>File Name</b></font> </td><td width="501"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soapStub.h</i> </td><td width="501">A modified and annotated header file produced from the input header file </td></tr>
<tr><td><i>soapH.h</i> </td><td width="501">Main header file to be included by all client and service sources </td></tr>
<tr><td><i>soapC.cpp</i> </td><td width="501">Serializers and deserializers for the specified data structures </td></tr>
<tr><td><i>soapClient.cpp</i> </td><td width="501">Client stub routines for remote operations </td></tr>
<tr><td><i>soapServer.cpp</i> </td><td width="501">Service skeleton routines </td></tr>
<tr><td><i>soapClientLib.cpp</i> </td><td width="501">Client stubs combined with local static (de)serializers </td></tr>
<tr><td><i>soapServerLib.cpp</i> </td><td width="501">Service skeletons combined with local static (de)serializers </td></tr>
<tr><td><i>soapXYZProxy.h</i> </td><td width="501">A C++ proxy object (can be used instead of soapClient.cpp) </td></tr>
<tr><td><i>soapXYZProxy.cpp</i> </td><td width="501">Implementation of C++ proxy object </td></tr>
<tr><td><i>soapXYZObject.h</i> </td><td width="501">A C++ server object (can be used instead of soapServer.cpp) </td></tr>
<tr><td><i>soapXYZObject.cpp</i> </td><td width="501">Implementation of C++ server object </td></tr>
<tr><td><i>.xsd</i> </td><td width="501">An <i>ns.xsd</i> file is generated with an XML Schema for each namespace prefix <i>ns</i> used by a data structure in the header
file input to the compiler, see Section&nbsp;<a href="#sec:wsdl">7.2.8</a> </td></tr>
<tr><td><i>.wsdl</i> </td><td width="501">A <i>ns.wsdl</i> file is generated with an WSDL description for each namespace prefix <i>ns</i> used by a remote method in the
header file input to the compiler, see Section&nbsp;<a href="#sec:wsdl">7.2.8</a> </td></tr>
<tr><td><i>.xml</i> </td><td width="501">Several SOAP/XML request and response files are generated. These are example message files are valid provided
that sufficient schema namespace directives are added to the header file or the generated .nsmap namespace table for the
client/service is not modified by hand </td></tr>
<tr><td><i>.nsmap</i> </td><td width="501">A <i>ns.nsmap</i> file is generated for each namespace prefix <i>ns</i> used by a remote method in the
header file input to the compiler, see Section&nbsp;<a href="#sec:wsdl">7.2.8</a>. The file contains a namespace mapping table that can be used in the client/service sources </td></tr></table>
</td></tr></table><br></span>
Both client and service applications are developed from a header file that specifies the remote methods. If client and
service applications are developed with the same header file, the applications are guaranteed to be compatible because the stub and skeleton routines use
the same serializers and deserializers to encode and decode the parameters. Note that when client and service applications are developed together, an application developer does
not need to know the details of the internal SOAP encoding used by the client and service.
<div class="p"><!----></div>
The <i>soapClientLib.cpp</i> and <i>soapServerLib.cpp</i> can be used to build (dynamic) client and server libraries. The serialization routines are local (static) to avoid link symbol conflicts. You must create a separate library for SOAP Header and Fault handling, as described in Section&nbsp;<a href="#sec:dylibs">18.34</a>.
<div class="p"><!----></div>
The following files are part of the gSOAP package and are required to build client and service applications:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>File Name</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>stdsoap2.h</i> </td><td>Header file of <i>stdsoap2.cpp</i> runtime library </td></tr>
<tr><td><i>stdsoap2.c</i> </td><td>Runtime C library with XML parser and run-time support routines </td></tr>
<tr><td><i>stdsoap2.cpp</i> </td><td>Runtime C++ library identical to <i>stdsoap2.c</i> </td></tr></table>
</td></tr></table><br></span>
<div class="p"><!----></div>
<h3><a name="tth_sEc8.1">
8.1</a>&nbsp;&nbsp;<font color="#0000FF">Compiler Options</font></h3><a name="sec:options">
</a>
<div class="p"><!----></div>
The compiler supports the following options:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Option</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>-1</i> </td><td>Use SOAP 1.1 namespaces and encodings (default) </td></tr>
<tr><td><i>-2</i> </td><td>Use SOAP 1.2 namespaces and encodings </td></tr>
<tr><td><i>-C</i> </td><td>Generate client-side code only </td></tr>
<tr><td><i>-S</i> </td><td>Generate server-side code only </td></tr>
<tr><td><i>-L</i> </td><td>Do not generate soapClientLib/soapServerLib </td></tr>
<tr><td><i>-a</i> </td><td>use value of SOAPAction HTTP header to dispatch method at server side </td></tr>
<tr><td><i>-c</i> </td><td>Generate pure C code </td></tr>
<tr><td><i>-d &lt; path &gt; </i> </td><td>Save sources in directory specified by <i> &lt; path &gt; </i> </td></tr>
<tr><td><i>-e</i> </td><td>Generate SOAP RPC encoding style bindings </td></tr>
<tr><td><i>-h</i> </td><td>Print a brief usage message </td></tr>
<tr><td><i>-i</i> </td><td>Generate service proxies and objects inherited from soap struct </td></tr>
<tr><td><i>-I &lt; path &gt; </i> </td><td>Use <i> &lt; path &gt; </i> (or paths separated with `:') for <i>#import</i> </td></tr>
<tr><td><i>-l</i> </td><td>Generate linkable modules (experimental) </td></tr>
<tr><td><i>-m</i> </td><td>Generate Matlab<sup><span class="roman">tm</span></sup> code for MEX compiler </td></tr>
<tr><td><i>-n</i> </td><td>When used with <i>-p</i>, enables multi-client and multi-server builds: </td></tr>
<tr><td></td><td>Sets compiler option <i>WITH_NONAMESPACES</i>, see Section&nbsp;<a href="#sec:compilerflags">8.11</a> </td></tr>
<tr><td></td><td>Saves the namespace mapping table with name <i> &lt; name &gt; _namespaces</i> instead of <i>namespaces</i> </td></tr>
<tr><td></td><td>Renames <i>soap_serve()</i> into <i> &lt; name &gt; _serve()</i> and <i>soap_destroy()</i> into <i> &lt; name &gt; _destroy()</i> </td></tr>
<tr><td><i>-p &lt; name &gt; </i> </td><td>Save sources with file name prefix <i> &lt; name &gt; </i> instead of "<i>soap</i>" </td></tr>
<tr><td><i>-t</i> </td><td>Generates code to send typed messages (with the <tt>xsi:type</tt> attribute) </td></tr>
<tr><td><i>-v</i> </td><td>Display version info</td></tr>
<tr><td><i>-w</i> </td><td>Do not generate WSDL and schema files </td></tr>
<tr><td><i>-x</i> </td><td>Do not generate sample XML message files </td></tr></table>
</td></tr></table><br></span>
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -cd '../projects' -pmy file.h</i>
</td></tr></table><br></span>
Saves the sources:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>../projects/myH.h</i> <br />
<i>../projects/myC.c</i> <br />
<i>../projects/myClient.c</i> <br />
<i>../projects/myServer.c</i> <br />
<i>../projects/myStub.h</i> <br />
</td></tr></table><br></span>
MS Windows users can use the usual "<i>/</i>" for options, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 /cd '..\projects' /pmy file.h</i>
</td></tr></table><br></span>
Compiler options <i>c, i, n, l, w</i> can be set in the gSOAP header file using the <i>//gsoapopt</i> directive. For example,
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Generate pure C and do not produce WSDL output: <br />
//gsoapopt cw <br />
<b>int</b>&nbsp;ns__myMethod(<b>char</b>*,<b>char</b>**); // takes a string and returns a string
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc8.2">
8.2</a>&nbsp;&nbsp;<font color="#0000FF">SOAP 1.1 Versus SOAP 1.2</font></h3>
<div class="p"><!----></div>
gSOAP supports SOAP 1.1 by default. SOAP 1.2 support is automatically turned on when the appropriate SOAP 1.2 namespace is used
in the namespace mapping table:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://www.w3.org/2002/06/soap-envelope"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://www.w3.org/2002/06/soap-encoding"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema"},
&nbsp;&nbsp;&nbsp;... <br />
}
</td></tr></table><br></i>
gSOAP Web services and clients can automatically switch from SOAP 1.1 to SOAP 1.2 by providing the SOAP 1.2 namespace
as a pattern in the third column of a namespace table:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/2002/06/soap-encoding"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/2002/06/soap-envelope"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema"},
&nbsp;&nbsp;&nbsp;... <br />
}
</td></tr></table><br></i>
This way, gSOAP Web services can respond to either SOAP 1.1 or SOAP 1.2 requests. gSOAP will automatically return SOAP 1.2 responses for SOAP 1.2 requests.
<div class="p"><!----></div>
The gSOAP <i>soapcpp2</i> compiler generates a <i>.nsmap</i> file with <i>SOAP-ENV</i> and <i>SOAP-ENC</i> namespace patterns similar to the above.
Since clients issue a send first, they will always use SOAP 1.1 for requests when the namespace table is similar as shown above.
Clients can accept SOAP 1.2 responses by inspecting the response message.
To restrict gSOAP services and clients to SOAP 1.2 and to generate SOAP 1.2 service WSDLs, use <i>soapcpp2</i>
compiler option <i>-2</i> to generate SOAP 1.2 conformant <i>.nsmap</i> and <i>.wsdl</i> files.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: SOAP 1.2 does not support partially transmitted arrays. So the <i>__offset</i> field of a dynamic array is meaningless.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: SOAP 1.2 requires the use of <i>SOAP_ENV__Code</i>, <i>SOAP_ENV__Reason</i>, and <i>SOAP_ENV__Detail</i> fields
in a <i>SOAP_ENV__Fault</i> fault struct, while SOAP 1.1 uses <i>faultcode</i>, <i>faultstring</i>, and <i>detail</i> fields.
Use <i>soap_receiver_fault_subcode(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*subcode, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring, <b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2
fault at the server-side with a fault subcode (SOAP 1.2).
Use <i>soap_sender_fault_subcode(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*subcode, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring, <b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2
unrecoverable Bad Request fault at the server-side with a fault subcode (SOAP 1.2).
<div class="p"><!----></div>
<h3><a name="tth_sEc8.3">
8.3</a>&nbsp;&nbsp;<font color="#0000FF">The soapdefs.h Header File</font></h3><a name="sec:soapdefs">
</a>
<div class="p"><!----></div>
The <i>soapdefs.h</i> header file is included in <i>stdsoap2.h</i> when compiling with option <i>-DWITH_SOAPDEFS_H</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_SOAPDEFS_H -c stdsoap2.cpp</i>
</td></tr></table><br></span>
The <i>soapdefs.h</i> file allows users to include definitions and add includes without requiring changes to <i>stdsoap2.h</i>.
For example,
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of soapdefs.h <br />
#include &lt; ostream &gt; <br />
#define SOAP_BUFLEN 20480 // use large send/recv buffer <br />
</td></tr></table><br></i>
The following header file can now refer to <i>ostream</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>extern</b>&nbsp;<b>class</b>&nbsp;ostream; // ostream can't be (de)serialized, but need to be declared to make it visible to gSOAP <br />
<b>class</b>&nbsp;ns__myClass <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(ostream &amp;s) <b>const</b>; // need ostream here <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
See also Section&nbsp;<a href="#sec:transient">18.3</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.4">
8.4</a>&nbsp;&nbsp;<font color="#0000FF">How to Build Modules and Libraries with the gSOAP #module Directive</font></h3><a name="sec:module">
</a>
<div class="p"><!----></div>
The <i>#module</i> directive is used to build modules. A library can be build from a module and linked with multiple Web services applications. The directive should appear at the top of the header file and has the following format:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#module "<i>name</i>" <br />
</td></tr></table><br></i>
where <i>name</i> is a unique name for the module. The name is case insensitive and MUST not exceed 4 characters in length.
The rest of the content of the header file should include type declarations and optionally the declarations of remote methods and SOAP Headers/Faults. When the gSOAP compiler processes the header file module, it will generate the source codes for a library. The Web services application that uses the library should use a header file that imports the module with the <i>#import</i> directive.
<div class="p"><!----></div>
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
/* Contents of module.h */ <br />
#module "test" <br />
<b>long</b>; <br />
<b>char</b>*; <br />
<b>struct</b>&nbsp;ns__S <br />
{ ... }
</td></tr></table><br></i>
The <i>module.h</i> header file declares a <b>long</b>, <b>char</b>*, and a <i><b>struct</b>&nbsp;ns__X</i>. The module name is "test", so the gSOAP compiler produces a <i>testC.cpp</i> file with the (de)serializers for these types. The <i>testC.cpp</i> library can be separately compiled and linked with an application that is built from a header file that imports "module.h" using <i>#import "module.h"</i>. You should also compile <i>testClient.cpp</i> when you want to build a library that includes the remote methods that you defined in the module header file.
<div class="p"><!----></div>
A module MUST be imported into another header file to use it and you cannot use a module alone to build a SOAP or XML application. That is, the top most header file in the import tree SHOULD NOT be a module.
<div class="p"><!----></div>
When multiple modules are linked, the types that they declare MUST be declared in one module only to avoid name clashes and link errors. You cannot create two modules that share the same type declaration and link the modules. When necessary, you should consider creating a module hierarchy such that types are declared only once and by only one module when these modules must be linked.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.5">
8.5</a>&nbsp;&nbsp;<font color="#0000FF">How to use the gSOAP #import Directive</font></h3><a name="sec:import">
</a>
<div class="p"><!----></div>
The <i>#import</i> directive is used to include gSOAP header files into other gSOAP header files for processing with
the gSOAP compiler <i>soapcpp2</i>.
The C <i>#include</i> directive cannot be used to include gSOAP header files.
The <i>#include</i> directive is reserved to control the post-gSOAP compilation process, see&nbsp;<a href="#sec:pragmas">8.6</a>.
<div class="p"><!----></div>
The <i>#import</i> directive is used for two purposes: you can use it to include the contents of a header file into another header file and you can use it to import a module, see&nbsp;<a href="#sec:module">8.4</a>.
<div class="p"><!----></div>
An example of the <i>#import</i> directive:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import "mydefs.gsoap" <br />
<b>int</b>&nbsp;ns__mymethod(xsd__string in, xsd__int *out);
</td></tr></table><br></i>
where <i>"mydefs.gsoap"</i> is a gSOAP header file that defines <i>xsd__string</i> and <i>xsd__int</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>int</b>&nbsp;xsd__int;
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc8.6">
8.6</a>&nbsp;&nbsp;<font color="#0000FF">How to Use #include and #define Directives</font></h3><a name="sec:pragmas">
</a>
<div class="p"><!----></div>
The <i>#include</i> and <i>#define</i> directives are normally ignored by the gSOAP compiler.
The use of the directives is enabled with the <i>-i</i> option of the gSOAP compiler, see Section&nbsp;<a href="#sec:options">8.1</a>.
However, the gSOAP compiler will not actually parse the contents of the header files provided by the <i>#include</i> directives in a header file.
Instead, the <i>#include</i> and <i>#define</i> directives will be added to the generated <i>soapH.h</i> header file <b>before</b>
any other header file is included. Therefore, <i>#include</i> and <i>#define</i> directives can be used to control the C/C++
compilation process of the sources of an application.
<div class="p"><!----></div>
The following example header file refers to <i>ostream</i> by including <i> &lt; ostream &gt; </i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include &lt; ostream &gt; <br />
#define WITH_COOKIES // use HTTP cookie support (you must compile stdsoap2.cpp with -DWITH_COOKIES) <br />
#define WITH_OPENSSL // enable HTTPS (SSL) support (you must compile stdsoap2.cpp with -DWITH_OPENSSL) <br />
#define SOAP_DEFAULT_float FLT_NAN // use NaN instead of 0.0 <br />
<b>extern</b>&nbsp;<b>class</b>&nbsp;ostream; // ostream can't be (de)serialized, but need to be declared to make it visible to gSOAP <br />
<b>class</b>&nbsp;ns__myClass <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(ostream &amp;s) <b>const</b>; // need ostream here <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
This example also uses <i>#define</i> directives for various settings.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: Note that the use of <i>#define</i> in the header file does not automatically result in compiling
<i>stdsoap2.cpp</i> with these directives. You MUST use the <i>-DWITH_COOKIES</i> and <i>-DWITH_OPENSSL</i> options when
compiling <i>stdsoap2.cpp</i> before linking the object file with your codes. As an alternative, you can use <i>#define
WITH_SOAPDEFS_H</i> and put the <i>#define</i> directives in the <i>soapdefs.h</i> file.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.7">
8.7</a>&nbsp;&nbsp;<font color="#0000FF">Compiling a gSOAP Client</font></h3>
<div class="p"><!----></div>
After invoking the gSOAP stub and skeleton compiler on a header file description of a service, the client application can be compiled on a Linux machine as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp</i>
</td></tr></table><br></span>
Or on a Unix machine:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl</i>
</td></tr></table><br></span>
(Depending on your system configuration, the libraries <i>libsocket.a</i>,
<i>libxnet.a</i>, <i>libnsl.a</i> or dynamic <i>*.so</i> versions of those libraries are required.)
<div class="p"><!----></div>
The <i>myclient.cpp</i> file must include <i>soapH.h</i> and must define a global namespace mapping table. A typical client program layout with namespace mapping table is shown below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "myclient.cpp" <br />
#include "soapH.h"; <br />
... <br />
// A remote method invocation: <br />
&nbsp;&nbsp;&nbsp;soap_call_some_remote_method(...); <br />
... <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name"} <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns1", "urn:my-remote-method"}, <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
}; <br />
...
</td></tr></table><br></i>
A mapping table is generated by the gSOAP compiler that can be used in the source, see Section&nbsp;<a href="#sec:wsdl">7.2.8</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.8">
8.8</a>&nbsp;&nbsp;<font color="#0000FF">Compiling a gSOAP Web Service</font></h3>
<div class="p"><!----></div>
After invoking the gSOAP stub and skeleton compiler on a header file description of the service, the server application can be compiled on a Linux machine as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myserver myserver.cpp stdsoap2.cpp soapC.cpp soapServer.cpp</i>
</td></tr></table><br></span>
Or on a Unix machine:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myserver myserver.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lsocket -lxnet -lnsl</i>
</td></tr></table><br></span>
(Depending on your system configuration, the libraries <i>libsocket.a</i>,
<i>libxnet.a</i>, <i>libnsl.a</i> or dynamic <i>*.so</i> versions of those libraries are required.)
<div class="p"><!----></div>
The <i>myserver.cpp</i> file must include <i>soapH.h</i> and must define a global namespace mapping table. A typical service program layout with namespace mapping table is shown below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "myserver.cpp" <br />
#include "soapH.h"; <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); <br />
} <br />
... <br />
// Implementations of the remote methods as C++ functions <br />
... <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name"} <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns1", "urn:my-remote-method"}, <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
}; <br />
...
</td></tr></table><br></i>
When the gSOAP service is compiled and installed as a CGI application, the <i>soap_serve</i> function acts as a service dispatcher. It listens to standard input and
invokes the method via a skeleton routine to serve a SOAP client request. After the request is served, the response is encoded in
SOAP and send to standard output. The method must be implemented in the server application and the type signature of the method
must be identical to the remote method specified in the header file. That is, the function prototype in the header file must be a
valid prototype of the method implemented as a C/C++ function.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.9">
8.9</a>&nbsp;&nbsp;<font color="#0000FF">Using gSOAP for Creating Web Services and Clients in Pure C</font></h3>
<div class="p"><!----></div>
The gSOAP compiler can be used to create pure C Web services and clients. The gSOAP stub and skeleton compiler
<i>soapcpp2</i> generates <i>.cpp</i> files by default. The compiler generates <i>.c</i> files with the <i>-c</i> option.
However, these files only use C syntax and data types <b>if</b> the header
file input to <i>soapcpp2</i> uses C syntax and data types. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c quote.h</i> <br />
<i>gcc -o quote quote.c stdsoap2.c soapC.c soapClient.c</i>
</td></tr></table><br></span>
Warnings will be issued by the compiler when C++ class declarations occur in the header file.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.10">
8.10</a>&nbsp;&nbsp;<font color="#0000FF">Limitations of gSOAP</font></h3><a name="sec:limitations">
</a>
<div class="p"><!----></div>
gSOAP is SOAP 1.1 and SOAP 1.2 compliant and supports SOAP RPC and document/literal operations.
<div class="p"><!----></div>
From the perspective of the C/C++ language, a few C++ language features are not supported by gSOAP and these features cannot be used in the specification of SOAP remote methods.
<div class="p"><!----></div>
There are certain limitations for the following C++ language constructs:
<dl compact="compact">
<dt><b>STL and STL templates</b></dt>
<dd> The gSOAP compiler supports STL strings <i>std::string</i> and <i>std::wstring</i> (see Section&nbsp;<a href="#sec:strings">10.2.6</a>) and the STL containers <i>std::deque</i>, <i>std::list</i>, <i>std::vector</i>, and <i>std::set</i>, (see Section&nbsp;<a href="#sec:templates">10.10.8</a>).</dd>
<dt><b>Templates</b></dt>
<dd> The gSOAP compiler is a preprocessor that cannot determine the template instantations used by the main program, nor can it generate templated code. You can however implement containers similar to the STL containers.</dd>
<dt><b>Multiple inheritance</b></dt>
<dd> Single class inheritance is supported. Multiple inheritance cannot be supported due to limitations of the SOAP protocol.</dd>
<dt><b>Abstract methods</b></dt>
<dd> A class must be instantiatable to allow decoding of instances of the class.</dd>
<dt><b>Directives</b></dt>
<dd> Directives and pragmas such as <i>#include</i> and <i>#define</i> are interpreted by the gSOAP compiler.
However, the interpretation is different compared to the usual handling of directives, see Section&nbsp;<a href="#sec:pragmas">8.6</a>. If necessary, a traditional C++
preprocessor can be used for the interpretation of directives. For example, Unix and Linux users can use "<tt>cpp -B</tt>"
to expand the header file, e.g. <tt>cpp -B myfile.h - soapcpp2</tt>.
Use the gSOAP <i>#import</i> directive to import gSOAP header files, see&nbsp;<a href="#sec:import">8.5</a>.</dd>
<dt><b>C and C++ programming statements</b></dt>
<dd> All class methods of a class should be declared within the class declaration in the header file, but the methods should not be implemented in code. All class method implementations must be defined within another C++ source file and linked to the application.</dd>
</dl>
The following data types require some attention to ensure they are serialized:
<dl compact="compact">
<dt><b><i><b>union</b></i> types</b></dt>
<dd> A <i><b>union</b></i> data type can not be serialized unless run-time information is associated with a <i><b>union</b></i> in a struct/class as discussed in Section&nbsp;<a href="#sec:union">10.6</a>. An alternative is to use a <i><b>struct</b></i> with a pointer type for each field. Because <i>NULL</i> pointers are not encoded, the resulting encoding will appear as a union type if only one pointer field is valid (i.e.&nbsp;non-<i>NULL</i>) at the time that the data type is encoded.</dd>
<dt><b><i><b>void</b></i> and <i><b>void</b>*</i> types</b></dt>
<dd> The <i><b>void</b></i> data type cannot be serialized unless run-time type information is associated with the pointer using a <i><b>int</b>&nbsp;__type</i> field in the struct/class that contains the <i><b>void</b>*</i>. The <i><b>void</b>*</i> data type is typically used to point to some object or to some array of some type of objects at run-time. The compiler cannot determine the type of data pointed to and the size of the array pointed to. A struct or class with a <i><b>void</b>*</i> field can be augmented to support the (de)serialization of the <i><b>void</b>*</i> using a <i><b>int</b>&nbsp;__type</i> field as described in Section&nbsp;<a href="#sec:void">10.8</a>.</dd>
<dt><b>Pointers to sequences of elements in memory</b></dt>
<dd> Any pointer, except for C strings which are pointers to a sequence of
characters, are treated by the compiler as if the pointer points to <b>only one element in memory</b> at run-time. Consequently,
the encoding and decoding routines will ignore any subsequent elements that follow the first in memory. For the same reason,
arrays of undetermined length, e.g.&nbsp;<i><b>float</b>&nbsp;a[]</i> cannot be used. gSOAP supports dynamic arrays using a special type convention,
see Section&nbsp;<a href="#sec:dynarray">10.10</a>.</dd>
<dt><b>Uninitialized pointers</b></dt>
<dd> Obviously, all pointers that are part of a data structure must be valid or <i>NULL</i> to enable
serialization of the data structure at run time.</dd>
</dl>
There are a number of programming solutions that can be adopted to circumvent these limitations. Instead of using <i><b>void</b>*</i>, a program
can in some cases be modified to use a pointer to a known type. If the pointer is intended to point to different types of objects, a generic
base class can be declared and the pointer is declared to point to the base class. All the other types are declared to be derived
classes of this base class. For pointers that point to a sequence of elements in memory dynamic arrays should be used instead,
see <a href="#sec:dynarray">10.10</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.11">
8.11</a>&nbsp;&nbsp;<font color="#0000FF">Compile Time Flags</font></h3><a name="sec:compilerflags">
</a>
<div class="p"><!----></div>
The following macros (<i>#define</i>s) can be used to enable certain optional features:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Macro</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>WITH_SOAPDEFS_H</i> </td><td>includes the <i>soapdefs.h</i> file for custom settings, see Section&nbsp;<a href="#sec:soapdefs">8.3</a> </td></tr>
<tr><td><i>WITH_COOKIES</i> </td><td>enables HTTP cookies, see Sections&nbsp;<a href="#sec:clientcookie">18.26</a>&nbsp;<a href="#sec:servercookie">18.27</a> </td></tr>
<tr><td><i>WITH_OPENSSL</i> </td><td>enables OpenSSL, see Sections&nbsp;<a href="#sec:clientopenssl">18.20</a>&nbsp;<a href="#sec:serveropenssl">18.19</a> </td></tr>
<tr><td><i>WITH_IPV6</i> </td><td>enables IPv6 support </td></tr>
<tr><td><i>WITH_TCPFIN</i> </td><td>use TCP FIN after sends when socket is ready to close </td></tr>
<tr><td><i>WITH_FASTCGI</i> </td><td>enables FastCGI, see Sections&nbsp;<a href="#sec:fastcgi">18.29</a> </td></tr>
<tr><td><i>WITH_GZIP</i> </td><td>enables gzip and deflate compression, see Section&nbsp;<a href="#sec:compression">18.25</a> </td></tr>
<tr><td><i>WITH_ZLIB</i> </td><td>enables deflate compression only, see Section&nbsp;<a href="#sec:compression">18.25</a> </td></tr>
<tr><td><i>WITH_UDP</i> </td><td>enables UDP support (SOAP-over-UDP), see Section&nbsp;<a href="#sec:udp">17</a> </td></tr>
<tr><td><i>WITH_FAST</i> </td><td>(obsolete) </td></tr>
<tr><td><i>WITH_NOIO</i> </td><td>eliminates need for file IO and BSD socket library, see Section&nbsp;<a href="#sec:noio">18.31</a> </td></tr>
<tr><td><i>WITH_NOHTTP</i> </td><td>eliminates HTTP stack to reduce code size </td></tr>
<tr><td><i>WITH_LEAN</i> </td><td>creates a small-footprint executable, see Section&nbsp;<a href="#sec:lean">18.30</a> </td></tr>
<tr><td><i>WITH_LEANER</i> </td><td>creates an even smaller footprint executable, see Section&nbsp;<a href="#sec:lean">18.30</a> </td></tr>
<tr><td><i>WITH_NONAMESPACES</i></td><td>omit initialization of soap struct with global <i>namespaces</i> table </td></tr>
<tr><td></td><td>and you MUST explicitly initialize <i>soap.namespaces</i> to point to a table </td></tr>
<tr><td></td><td>see also Section&nbsp;<a href="#sec:nstable">9.4</a> </td></tr>
<tr><td><i>WITH_NOGLOBAL</i> </td><td>omit SOAP Header and Fault serialization code </td></tr>
<tr><td><i>WITH_CDATA</i> </td><td>retain the parsed CDATA sections in literal XML strings (no conversion) </td></tr>
<tr><td><i>WITH_CASEINSENSITIVETAGS</i> </td><td>enable case insensitive XML parsing </td></tr></table>
</td></tr></table><br></span>
<font color="#FF0000"><b>Caution</b></font>: it is important that the macros MUST be consistently defined to
compile the sources, such as <i>stdsoap2.cpp</i>, <i>soapC.cpp</i>,
<i>soapClient.cpp</i>, <i>soapServer.cpp</i>, and all application sources that
include <i>stdsoap2.h</i> or <i>soapH.h</i>. If the macros are not consistently
used, the application will crash due to a mismatches in the declaration and
access of the gSOAP environment.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.12">
8.12</a>&nbsp;&nbsp;<font color="#0000FF">Run Time Flags</font></h3><a name="sec:flags">
</a>
<div class="p"><!----></div>
gSOAP provides flags to control the input and output mode settings at runtime.
These flags are divided into four categories: transport (IO), content encoding
(ENC), XML marshalling (XML), and C/C++ data mapping (C).
<div class="p"><!----></div>
Although gSOAP is fully SOAP 1.1 compliant, some SOAP implementations may have
trouble accepting multi-reference data and/or require explicit nil data so
these flags can be used to put gSOAP in "safe mode". In addition, the
embedding (or inlining) of multi-reference data is adopted in the SOAP 1.2
specification, which gSOAP automatically supports when handling with SOAP 1.2
messages. The flags are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Flag</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>SOAP_IO_FLUSH</i> </td><td>Disable buffering and flush output (default for all file-based output) </td></tr>
<tr><td><i>SOAP_IO_BUFFER</i> </td><td>Enable buffering (default for all socket-oriented connections) </td></tr>
<tr><td><i>SOAP_IO_STORE</i> </td><td>Store entire message to calculate HTTP content length </td></tr>
<tr><td><i>SOAP_IO_CHUNK</i> </td><td>Use HTTP chunking </td></tr>
<tr><td><i>SOAP_IO_LENGTH</i> </td><td>Require apriori calculation of content length (this is automatic) </td></tr>
<tr><td><i>SOAP_IO_KEEPALIVE</i> </td><td>Attempt to keep socket connections alive (open) </td></tr>
<tr><td><i>SOAP_IO_UDP</i> </td><td>Use UDP (datagram) transport, maximum message length is <i>SOAP_BUFLEN</i> </td></tr>
<tr><td><i>SOAP_ENC_XML</i> </td><td>Use plain XML encoding without HTTP headers (useful with <i>SOAP_ENC_ZLIB</i>) </td></tr>
<tr><td><i>SOAP_ENC_DIME</i> </td><td>Use DIME encoding (automatic when DIME attachments are used) </td></tr>
<tr><td><i>SOAP_ENC_MIME</i> </td><td>Use MIME encoding (activate using <i>soap_set_mime</i>) </td></tr>
<tr><td><i>SOAP_ENC_MTOM</i> </td><td>Use MTOM XOP attachments (instead of DIME) </td></tr>
<tr><td><i>SOAP_ENC_ZLIB</i> </td><td>Compress encoding with Zlib (deflate or gzip format) </td></tr>
<tr><td><i>SOAP_ENC_SSL</i> </td><td>Encrypt encoding with SSL (automatic with "https:" endpoints) </td></tr>
<tr><td><i>SOAP_XML_INDENT</i> </td><td>Produce indented XML output </td></tr>
<tr><td><i>SOAP_XML_CANONICAL</i> </td><td>Produce canonical XML output </td></tr>
<tr><td><i>SOAP_XML_STRICT</i> </td><td>XML strict validation </td></tr>
<tr><td><i>SOAP_XML_TREE</i> </td><td>Serialize data as XML trees (no multi-ref, duplicate data when necessary) </td></tr>
<tr><td><i>SOAP_XML_GRAPH</i> </td><td>Serialize data as an XML graph with inline multi-ref (SOAP 1.2 default) </td></tr>
<tr><td><i>SOAP_XML_NIL</i> </td><td>Serialize NULL data as xsi:nil elements (omit by default) </td></tr>
<tr><td><i>SOAP_C_NOIOB</i> </td><td>Do not fault with <i>SOAP_IOB</i> </td></tr>
<tr><td><i>SOAP_C_UTFSTRING</i> </td><td>(De)serialize 8-bit strings "as is" (strings MUST have UTF-8 encoded content) </td></tr>
<tr><td><i>SOAP_C_MBSTRING</i> </td><td>Activate multibyte character support (depends on locale) </td></tr></table>
</td></tr></table><br></span>
The flags can be selectively turned on/off at any time, for example when
multiple Web services are accessed by a client that require special treatment.
<div class="p"><!----></div>
All flags are orthogonal, except
<i>SOAP_IO_FLUSH</i>,
<i>SOAP_IO_BUFFER</i>,
<i>SOAP_IO_STORE</i>, and
<i>SOAP_IO_CHUNK</i>
which are enumerations and only one of these I/O flags can be used. Also the
XML serialization flags
<i>SOAP_XML_TREE</i> and
<i>SOAP_XML_GRAPH</i> should not be mixed.
<div class="p"><!----></div>
The flags control the inbound and outbound message transport, encoding, and
(de)serialization. The following functions are used to set and reset the flags
for input and output modes:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soap_init2(<b>struct</b>&nbsp;soap *soap, int imode, int omode)</i> </td><td>Initialize the runtime and set flags </td></tr>
<tr><td><i>soap_imode(<b>struct</b>&nbsp;soap *soap, int imode)</i> </td><td>Set all input mode flags </td></tr>
<tr><td><i>soap_omode(<b>struct</b>&nbsp;soap *soap, int omode)</i> </td><td>Set all output mode flags </td></tr>
<tr><td><i>soap_set_imode(<b>struct</b>&nbsp;soap *soap, int imode)</i> </td><td>Enable input mode flags </td></tr>
<tr><td><i>soap_set_omode(<b>struct</b>&nbsp;soap *soap, int omode)</i> </td><td>Enable output mode flags </td></tr>
<tr><td><i>soap_clr_imode(<b>struct</b>&nbsp;soap *soap, int omode)</i> </td><td>Disable input mode flags </td></tr>
<tr><td><i>soap_clr_omode(<b>struct</b>&nbsp;soap *soap, int omode)</i> </td><td>Disable output mode flags </td></tr></table>
</td></tr></table><br></span>
The default setting is <i>SOAP_IO_DEFAULT</i> for both input and output modes.
<div class="p"><!----></div>
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init2(&amp;soap, SOAP_IO_KEEPALIVE, <br />
&nbsp;&nbsp;&nbsp;SOAP_IO_KEEPALIVE | SOAP_ENC_ZLIB | SOAP_XML_TREE | SOAP_XML_CANONICAL); <br />
<b>if</b>&nbsp;(soap_call_ns__myMethod(&amp;soap, ...)) <br />
...
</td></tr></table><br></i>
sends a compressed client request with keep-alive enabled and all data serialized as canonical XML trees.
<div class="p"><!----></div>
In many cases, setting the input mode will have no effect, especially with HTTP
transport because gSOAP will determine the optimal input buffering and the
encoding used for an inbound message. The flags that have an effect on
handling inbound messages are <i>SOAP_IO_KEEPALIVE</i>, <i>SOAP_ENC_SSL</i>
(but automatic when "https:" endpoints are used or <i>soap_ssl_accept</i>),
<i>SOAP_C_NOIOB</i>, <i>SOAP_C_UTFSTRING</i>, and <i>SOAP_C_MBSTRING</i>.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: The <i>SOAP_XML_TREE</i> serialization flag can be used to
improve interoperability with SOAP implementations that are not fully SOAP 1.1
compliant. However, a tree serialization will duplicate data when necessary
and will crash the serializer for cyclic data structures.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.13">
8.13</a>&nbsp;&nbsp;<font color="#0000FF">Memory Management</font></h3><a name="sec:memory">
</a>
<div class="p"><!----></div>
Understanding gSOAP's run-time memory management is important to optimize
client and service applications by eliminating memory leaks and/or dangling
references.
<div class="p"><!----></div>
There are two forms of dynamic (heap) allocations made by gSOAP's runtime for
serialization and deserialization of data. Temporary data is created by the
runtime such as hash tables to keep pointer reference information for
serialization and hash tables to keep XML id/href information for
multi-reference object deserialization. Deserialized data is created upon
receiving SOAP messages. This data is stored on the heap and requires several
calls to the <i>malloc</i> library function to allocate space for the data and
<i><b>new</b></i> to create class instances. All such allocations are tracked by
gSOAP's runtime by linked lists for later deallocation. The linked list for
<i>malloc</i> allocations uses some extra space in each <i>malloc</i>ed block to
form a chain of pointers through the <i>malloc</i>ed blocks. A separate
<i>malloc</i>ed linked list is used to keep track of class instance allocations.
<div class="p"><!----></div>
gSOAP does not enforce a deallocation policy and the user can adopt a
deallocation policy that works best for a particular application. As a
consequence, deserialized data is never deallocated by the gSOAP runtime unless
the user explicitly forces deallocation by calling functions to deallocate data
collectively or individually.
<div class="p"><!----></div>
The deallocation functions are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function Call</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>soap_end(<b>struct</b>&nbsp;soap *soap)</i> </td><td>Remove temporary data and deserialized data except </td></tr>
<tr><td></td><td>class instances </td></tr>
<tr><td><i>soap_free(<b>struct</b>&nbsp;soap *soap)</i> </td><td>Remove temporary data only </td></tr>
<tr><td><i>soap_destroy(<b>struct</b>&nbsp;soap *soap)</i> </td><td>Remove all dynamically allocated class instances. </td></tr>
<tr><td></td><td>Need to be called before <i>soap_end()</i> </td></tr>
<tr><td><i>soap_dealloc(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*p)</i> </td><td>Remove malloced data at <i>p</i>. When <i>p==NULL</i>: remove all </td></tr>
<tr><td></td><td>dynamically allocated (deserialized) data except class instances </td></tr>
<tr><td><i>soap_delete(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*p)</i> </td><td>Remove class instance at <i>p</i>. When <i>p==NULL</i>: remove all </td></tr>
<tr><td></td><td>dynamically allocated (deserialized) class instances </td></tr>
<tr><td></td><td>(this is identical to calling soap_destroy(<b>struct</b>&nbsp;soap *soap)) </td></tr>
<tr><td><i>soap_unlink(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*p)</i> </td><td>Unlink data/object at <i>p</i> from gSOAP's deallocation chain </td></tr>
<tr><td></td><td>so gSOAP won't deallocate it </td></tr>
<tr><td><i>soap_done(<b>struct</b>&nbsp;soap *soap)</i> </td><td>Reset: close master/slave sockets and remove callbacks </td></tr>
<tr><td></td><td>(see Section&nbsp;<a href="#sec:callback">18.7</a> </td></tr></table>
</td></tr></table><br></span>
Temporary data (i.e.&nbsp;the hash tables) are automatically removed with calls to
the <i>soap_free</i> function which is made within <i>soap_end</i> and
<i>soap_done</i> or when the next call to a stub or skeleton routine is made to
send a message or receive a message. Deallocation of non-class based data is
straightforward: <i>soap_end</i> removes all dynamically allocated deserialized
data (data allocated with <i>soap_malloc</i>. That is, when the client/service
application does not use any class instances that are (de)marshalled, but uses
structs, arrays, etc., then calling the <i>soap_end</i> function is safe to
remove all deserialized data. The function can be called after processing the
deserialized data of a remote method call or after a number of remote method
calls have been made. The function is also typically called after
<i>soap_serve</i>, when the service finished sending the response to a client
and the deserialized client request data can be removed.
<div class="p"><!----></div>
Individual data objects can be unlinked from the deallocation chain if
necessary, to prevent deallocation by the collective <i>soap_end</i> or
<i>soap_destroy</i> functions.
<div class="p"><!----></div>
<h4><a name="tth_sEc8.13.1">
8.13.1</a>&nbsp;&nbsp;<font color="#0000FF">Memory Management Policies</font></h4>
<div class="p"><!----></div>
There are three situations to consider for memory deallocation policies for class instances:
<ol type="1">
<li> the program code deletes the class
instances and the class destructors in turn SHOULD delete and free any dynamically allocated data (deep deallocation) without
calling the <i>soap_end</i> and <i>soap_destroy</i> functions,
<div class="p"><!----></div>
</li>
<li> or the class
destructors SHOULD NOT deallocate any data and the <i>soap_end</i> and <i>soap_destroy</i> functions can be called to remove
the data.
<div class="p"><!----></div>
</li>
<li> or the class
destructors SHOULD mark their own deallocation and mark the deallocation of any other data deallocated by it's destructors
by calling the <i>soap_unlink</i> function. This allows
<i>soap_destroy</i> and <i>soap_end</i> to remove the remaining instances and data without causing duplicate deallocations.
<div class="p"><!----></div>
</li>
</ol>
It is advised to use pointers to class instances that are used within other structs and classes to avoid the creation of temporary
class instances during deserialization. The problem with temporary class instances is that the destructor of the temporary may affect data used by
other instances through the sharing of data parts accessed with pointers. Temporaries and even whole copies of class instances
can be created when deserializing SOAP multi-referenced objects.
A dynamic array of class instances is similar: temporaries may be created to fill the array upon deserialization. To avoid
problems, use dynamic arrays of pointers to class instances. This also enables the exchange of polymorphic arrays when the
elements are instances of classes in an inheritance hierarchy.
In addition, allocate data and class instances with <i>soap_malloc</i> and <i>soap_new_X</i> functions (more details below).
<div class="p"><!----></div>
To summarize, it is advised to pass class data types by pointer to a remote method. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;X { ... }; <br />
ns__remoteMethod(X *in, ...);
</td></tr></table><br></i>
Response elements that are class data types can be passed by reference, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;X { ... }; <br />
<b>class</b>&nbsp;ns__remoteMethodResponse { ... }; <br />
ns__remoteMethod(X *in, ns__remoteMethodResponse &amp;out);
</td></tr></table><br></i>
But dynamic arrays declared as class data types should use a pointer to a valid object that will be overwritten when the
function is called, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>int</b>&nbsp;xsd__int; <br />
<b>class</b>&nbsp;X { ... }; <br />
<b>class</b>&nbsp;ArrayOfint { xsd__int *__ptr; <b>int</b>&nbsp;__size; }; <br />
ns__remoteMethod(X *in, ArrayOfint *out);
</td></tr></table><br></i>
Or a reference to a valid or <i>NULL</i> pointer, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>int</b>&nbsp;xsd__int; <br />
<b>class</b>&nbsp;X { ... }; <br />
<b>class</b>&nbsp;ArrayOfint { xsd__int *__ptr; <b>int</b>&nbsp;__size; }; <br />
ns__remoteMethod(X *in, ArrayOfint *&amp;out);
</td></tr></table><br></i>
The gSOAP memory allocation functions can be used in client and/or service code to allocate temporary data that will be
automatically deallocated.
These functions are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Function Call</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i><b>void</b>&nbsp;*soap_malloc(<b>struct</b>&nbsp;soap *soap, size_t n)</i> </td><td>return pointer to <i>n</i> bytes </td></tr>
<tr><td><i><u><span class="roman">Class</span></u> *soap_new_<u><span class="roman">Class</span></u>(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;n)</i> </td><td>instantiate <i>n</i> <u><span class="roman">Class</span></u> objects </td></tr></table>
</td></tr></table><br></span>
The <i>soap_new_X</i> functions are generated by the gSOAP compiler for every class <i>X</i> in the header file.
Parameter <i>n</i> MUST be <i>-1</i> to instantiate a single object, or larger or equal to 0 to instantiate an array of <i>n</i> objects.
<div class="p"><!----></div>
Space allocated with <i>soap_malloc</i> will be released with the <i>soap_end</i> and <i>soap_dealloc</i> functions.
Objects instantiated with <i>soap_new_X(<b>struct</b>&nbsp;soap*)</i> are removed altogether with <i>soap_destroy(<b>struct</b>&nbsp;soap*)</i>.
Individual objects instantiated with <i>soap_new_X</i> are removed with <i>soap_delete_X(<b>struct</b>&nbsp;soap*, X*)</i>.
For example, the following service uses temporary data in the remote method implementation:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;... <br />
}
</td></tr></table><br></i>
An example remote method that allocates a temporary string is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__itoa(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;i, <b>char</b>&nbsp;**a) <br />
{ <br />
&nbsp;&nbsp;&nbsp;*a = (char*)soap_malloc(soap, 11); <br />
&nbsp;&nbsp;&nbsp;sprintf(*a, "%d", i); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
This temporary allocation can also be used to allocate strings for the SOAP Fault data structure. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__mymethod(...) <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(exception) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*msg = (<b>char</b>*)soap_malloc(soap, 1024); // allocate temporary space for detailed message <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sprintf(msg, "...", ...); // produce the detailed message <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_receiver_fault(soap, &#196;n exception occurred", msg); // return the server-side fault <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;... <br />
}
</td></tr></table><br></i>
Use <i>soap_receiver_fault(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring, <b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2 fault at the server-side.
Use <i>soap_sender_fault(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring,
<b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2 unrecoverable Bad Request fault
at the server-side. Sending clients are not supposed to retry messages after a
Bad Request, while errors at the receiver-side indicate temporary problems.
<div class="p"><!----></div>
The above functions do not include a SOAP 1.2 Subcode element. To include Subcode element, use <i>soap_receiver_fault_subcode(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*subcode, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring, <b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2 fault with Subcode at the server-side.
Use <i>soap_sender_fault_subcode(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*subcode, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring, <b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> to set a SOAP 1.1/1.2 unrecoverable Bad Request fault with Subcode at the server-side.
<div class="p"><!----></div>
gSOAP provides a function to duplicate a string into gSOAP's memory space:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i><b>char</b>&nbsp;*soap_strdup(<b>struct</b>&nbsp;soap *soap, const char *s)</i>
</td></tr></table><br></span>
The function allocates space for <i>s</i> with <i>soap_malloc</i>, copies the
string, and returns a pointer to the duplicated string. When <i>s</i> is NULL,
the function does not allocate and copy the string and returns NULL.
<div class="p"><!----></div>
<h4><a name="tth_sEc8.13.2">
8.13.2</a>&nbsp;&nbsp;<font color="#0000FF">Intra-Class Memory Management</font></h4><a name="sec:classmemory">
</a>
<div class="p"><!----></div>
When a class declaration has a <i><b>struct</b>&nbsp;soap *</i> field, this field will be set to point to the current gSOAP run-time environment by
gSOAP's deserializers and by the <i>soap_new_Class</i> functions.
This simplifies memory management for class instances.
The <i><b>struct</b>&nbsp;soap*</i> pointer is implicitly set by the gSOAP deserializer for
the class or explicitly by calling the <i>soap_new_X</i> function for class <i>X</i>.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;Sample <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap; // reference to gSOAP's run-time <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;Sample(); <br />
&nbsp;&nbsp;&nbsp;~Sample(); <br />
};
</td></tr></table><br></i>
The constructor and destructor for class <i>Sample</i> are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
Sample::Sample() <br />
{ this<tt>-&gt;</tt>soap = NULL; <br />
} <br />
Sample::~Sample() <br />
{ soap_unlink(this<tt>-&gt;</tt>soap, this); <br />
}
</td></tr></table><br></i>
The <i>soap_unlink()</i> call removes the object from gSOAP's deallocation chain.
In that way, <i>soap_destroy</i> can be safely called to remove all class instances.
The following code illustrates the explicit creation of a <i>Sample</i> object and cleanup:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap *soap = soap_new(); // new gSOAP runtime <br />
Sample *obj = soap_new_Sample(soap, -1); // new Sample object with obj<tt>-&gt;</tt>soap set to runtime <br />
... <br />
<b>delete</b>&nbsp;obj; // also calls soap_unlink to remove obj from the deallocation chain <br />
soap_destroy(soap); // deallocate all (other) class instances <br />
soap_end(soap); // clean up
</td></tr></table><br></i>
Here is another example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;ns__myClass <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap *soap; // set by soap_new_ns__myClass() <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;setName(<b>const</b>&nbsp;<b>char</b>&nbsp;*s); <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
Calls to <i>soap_new_ns__myClass(soap, n)</i> will set the <i>soap</i> field in the class instance to the current gSOAP
environment. Because the deserializers invoke the <i>soap_new</i> functions, the <i>soap</i> field of the <i>ns__myClass</i>
instances are set as well.
This mechanism is convenient when Web Service methods need to return objects that are instantiated in the methods.
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__myMethod(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;ns__myClass *p = soap_new_ns__myClass(soap, -1); <br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>setName("SOAP"); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>void</b>&nbsp;ns__myClass::ns__setName(<b>const</b>&nbsp;<b>char</b>&nbsp;*s) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name = (<b>char</b>*)soap_malloc(soap, strlen(s)+1); <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name = (<b>char</b>*)malloc(strlen(s)+1); <br />
&nbsp;&nbsp;&nbsp;strcpy(name, s); <br />
} <br />
ns__myClass::ns__myClass() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap = NULL; <br />
&nbsp;&nbsp;&nbsp;name = NULL; <br />
} <br />
ns__myClass::~ns__myClass() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap &amp;&amp; name) free(name); <br />
&nbsp;&nbsp;&nbsp;soap_unlink(soap, this); <br />
}
</td></tr></table><br></i>
Calling <i>soap_destroy</i> right after <i>soap_serve</i> in the Web Service will destroy all dynamically allocated
class instances.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.14">
8.14</a>&nbsp;&nbsp;<font color="#0000FF">Debugging</font></h3>
<div class="p"><!----></div>
To activate message logging for debugging, un-comment the <i>#define DEBUG</i> directive in <i>stdsoap2.h</i>. Compile the client and/or
server applications as described above (or simply use <i>g++ -DDEBUG ...</i> to compile with debugging activated). When the client and server applications run, they will log their activity in three
separate files:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>File</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td><i>SENT.log</i> </td><td>The SOAP content transmitted by the application </td></tr>
<tr><td><i>RECV.log</i> </td><td>The SOAP content received by the application </td></tr>
<tr><td><i>TEST.log</i> </td><td>A log containing various activities performed by the application </td></tr></table>
</td></tr></table><br></span>
<font color="#FF0000"><b>Caution</b></font>: The client and server applications may run slow due to the logging activity.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: When installing a CGI application on the Web with debugging activated, the log files may sometimes not be created due to file
access permission restrictions imposed on CGI applications. To get around this, create empty log files with universal write
permissions. Be careful about the security implication of this.
<div class="p"><!----></div>
You can test a service CGI application without deploying it on the Web.
To do this, create a client application for the service and activate message logging by this client.
Remove any old <i>SENT.log</i> file and run the client (which connects to the Web service or to another dummy, but valid address)
and copy the <i>SENT.log</i> file to another file, e.g. <i>SENT.tst</i>.
Then redirect the <i>SENT.tst</i> file to the service CGI application. For example,
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>myservice.cgi</i> &lt; <i>SENT.tst</i>
</td></tr></table><br></span>
This should display the service response on the terminal.
<div class="p"><!----></div>
The file names of the log files and the logging activity can be controlled at the application level. This allows the creation of
separate log files by separate services, clients, and threads.
For example, the following service logs all SOAP messages (but no debug messages) in separate directories:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
... <br />
soap_set_recv_logfile(&amp;soap, "logs/recv/service12.log"); // append all messages received in /logs/recv/service12.log <br />
soap_set_sent_logfile(&amp;soap, "logs/sent/service12.log"); // append all messages sent in /logs/sent/service12.log <br />
soap_set_test_logfile(&amp;soap, NULL); // no file name: do not save debug messages <br />
... <br />
soap_serve(&amp;soap); <br />
...
</td></tr></table><br></i>
Likewise, messages can be logged for individual client-side remote method calls.
<div class="p"><!----></div>
<h3><a name="tth_sEc8.15">
8.15</a>&nbsp;&nbsp;<font color="#0000FF">Required Libraries</font></h3>
<div class="p"><!----></div>
<ul>
<li> The socket library is essential and requires the inclusion of the appropriate libraries with the compile command for Sun
Solaris systems:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl</i>
</td></tr></table><br></span>
These library loading options are not required with Linux.
<div class="p"><!----></div>
</li>
<li> The gSOAP runtime uses the math library for the <tt>NaN</tt>, <tt>INF</tt>, and <tt>-INF</tt> floating point representations. The library
is not strictly necessary and the <i> &lt; math.h &gt; </i> header file import can be commented out from the <i>stdsoap2.h</i> header file.
The application can be linked without the <i>-lm</i> math library e.g. under Sun Solaris:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl</i>
</td></tr></table><br></span>
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h2><a name="tth_sEc9">
9</a>&nbsp;&nbsp;<font color="#0000FF">The gSOAP Remote Method Specification Format</font></h2>
<div class="p"><!----></div>
A SOAP remote method is specified as a C/C++ function prototype in a header
file. The function is REQUIRED to return <i><b>int</b></i>, which is used to represent
a SOAP error code, see Section&nbsp;<a href="#sec:errcodes">9.2</a>. Multiple remote methods MAY
be declared together in one header file.
<div class="p"><!----></div>
The general form of a SOAP remote method specification is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<font size="+1"><span class="roman">[</span></font><b>int</b><font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>method_name(<font size="+1"><span class="roman">[</span></font>inparam1, inparam2, ...,<font size="+1"><span class="roman">]</span></font> outparam);
</td></tr></table><br></i>
where
<dl compact="compact">
<dt><b><span class="roman"><i>namespace_prefix__</i></b></dt>
<dd> is the optional namespace prefix of the method (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>)</span></dd>
<dt><b><span class="roman"><i>method_name</i></b></dt>
<dd> it the remote method name (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>)</span></dd>
<dt><b><span class="roman"><i>inparam</i></b></dt>
<dd> is the declaration of an input parameter of the remote method</span></dd>
<dt><b><span class="roman"><i>outparam</i></b></dt>
<dd> is the declaration of the output parameter of the remote method</span></dd>
</dl>
This simple form can only pass a single, non-<i><b>struct</b></i> and non-<i><b>class</b></i>
type output parameter. See&nbsp;<a href="#sec:param">9.1</a> for passing multiple output
parameters. The name of the declared function <i>namespace_prefix__
method_name</i> must be unique and cannot match the name of a <i><b>struct</b></i>,
<i><b>class</b></i>, or <i><b>enum</b></i> declared in the same header file.
<div class="p"><!----></div>
The method request is encoded in SOAP as an XML element and the namespace prefix, method name, and input parameters are encoded using the format:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method_name xsi:type="<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method_name&#62; <br />
&lt;inparam-name1 xsi:type="..."&#62;...&lt;/inparam-name1&#62; <br />
&lt;inparam-name2 xsi:type="..."&#62;...&lt;/inparam-name2&#62; <br />
... <br />
&lt;/<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method_name&#62;
</td></tr></table><br></tt>
where the <tt>inparam-name</tt> accessors are the element-name representations of the <i>inparam</i> parameter name declarations, see
Section&nbsp;<a href="#sec:idtrans">9.3</a>. (The optional parts are shown enclosed in <font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">]</span></font>.)
<div class="p"><!----></div>
The XML response by the Web service is of the form:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-nameResponse xsi:type="<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-nameResponse&#62; <br />
&lt;outparam-name xsi:type="..."&#62;...&lt;/outparam-name&#62; <br />
&lt;/<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-nameResponse&#62;
</td></tr></table><br></tt>
where the <tt>outparam-name</tt> accessor is the element-name representation of the <i>outparam</i> parameter name declaration, see
Section&nbsp;<a href="#sec:idtrans">9.3</a>. By convention, the response element name is the method name ending in <tt>Response</tt>.
See&nbsp;<a href="#sec:param">9.1</a> on how to change the declaration if the service response element name is different.
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler generates a stub routine for the remote
method. This stub is of the form:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_call_<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>method_name(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*URL, <b>char</b>&nbsp;*action, <font size="+1"><span class="roman">[</span></font>inparam1, inparam2, ...,<font size="+1"><span class="roman">]</span></font> outparam);
</td></tr></table><br></i>
This proxy can be called by a client application to perform the remote method
call.
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler generates a skeleton routine for the
remote method. The skeleton function is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;soap_serve_<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>method_name(<b>struct</b>&nbsp;soap *soap);
</td></tr></table><br></i>
The skeleton routine, when called by a service application, will attempt to
serve a request on the standard input. If no request is present or if the
request does not match the method name, <i>SOAP_NO_METHOD</i> is returned.
The skeleton routines are automatically called by the generated
<i>soap_serve</i> routine that handles all requests.
<div class="p"><!----></div>
<h3><a name="tth_sEc9.1">
9.1</a>&nbsp;&nbsp;<font color="#0000FF">Remote Method Parameter Passing</font></h3><a name="sec:param">
</a>
<div class="p"><!----></div>
The input parameters of a remote method MUST be passed by value. Input
parameters cannot be passed by reference with the <i>&amp;</i> reference operator,
but an input parameter value MAY be passed by a pointer to the data. Of
course, passing a pointer to the data is preferred when the size of the data of
the parameter is large. Also, to pass instances of (derived) classes, pointers
to the instance need to be used to avoid passing the instance by value which
requires a temporary and prohibits passing derived class instances. When two
input parameter values are identical, passing them using a pointer has the
advantage that the value will be encoded only once as multi-reference (hence,
the parameters are aliases). When input parameters are passed using a pointer,
the data pointed to will not be modified by the remote method and returned to
the caller.
<div class="p"><!----></div>
The output parameter MUST be passed by reference using <i>&amp;</i> or by using a
pointer. Arrays are passed by reference by default and do not require the use
of the reference operator <i>&amp;</i>.
<div class="p"><!----></div>
The input and output parameter types have certain limitations, see
Section&nbsp;<a href="#sec:limitations">8.10</a>
<div class="p"><!----></div>
If the output parameter is a <i><b>struct</b></i> or <i><b>class</b></i> type, it is
considered a SOAP remote method response element instead of a simple output
parameter value. That is, the name of the <i><b>struct</b></i> or <i><b>class</b></i> is the
name of the response element and the <i><b>struct</b></i> or <i><b>class</b></i> fields are
the output parameters of the remote method, see also&nbsp;<a href="#sec:response">7.1.7</a>. Hence,
if the output parameter has to be a <i><b>struct</b></i> or <i><b>class</b></i>, a response
<i><b>struct</b></i> or <i><b>class</b></i> MUST be declared as well. In addition, if a
remote method returns multiple output parameters, a response <i><b>struct</b></i> or
<i><b>class</b></i> MUST be declared. By convention, the response element is the
remote method name ending with "<tt>Response</tt>".
<div class="p"><!----></div>
The general form of a response element declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>response_element_name <br />
{ <br />
&nbsp;&nbsp;&nbsp;outparam1; <br />
&nbsp;&nbsp;&nbsp;outparam2; <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
where
<dl compact="compact">
<dt><b><span class="roman"><i>namespace_prefix__</i></b></dt>
<dd> is the optional namespace prefix of the response element (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>)</span></dd>
<dt><b><span class="roman"><i>response_element_name</i></b></dt>
<dd> it the name of the response element (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>)</span></dd>
<dt><b><span class="roman"><i>outparam</i></b></dt>
<dd> is the declaration of an output parameter of the remote method</span></dd>
</dl>
The general form of a remote method specification with a response element declaration for (multiple) output parameters is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<font size="+1"><span class="roman">[</span></font><b>int</b><font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>method_name(<font size="+1"><span class="roman">[</span></font>inparam1, inparam2, ...,<font size="+1"><span class="roman">]</span></font> <b>struct</b>&nbsp;<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>response_element_name {outparam1<font size="+1"><span class="roman">[</span></font>, outparam2, ...<font size="+1"><span class="roman">]</span></font>} &amp;anyparam);
</td></tr></table><br></i>
The choice of name for <i>anyparam</i> has no effect on the SOAP encoding and decoding and is only used as a place holder for the
response.
<div class="p"><!----></div>
The method request is encoded in SOAP as an independent element and the
namespace prefix, method name, and input parameters are encoded using the
format:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-name xsi:type="<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-name&#62; <br />
&lt;inparam-name1 xsi:type="..."&#62;...&lt;/inparam-name1&#62; <br />
&lt;inparam-name2 xsi:type="..."&#62;...&lt;/inparam-name2&#62; <br />
... <br />
&lt;/<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>method-name&#62;
</td></tr></table><br></tt>
where the <tt>inparam-name</tt> accessors are the element-name representations of
the <i>inparam</i> parameter name declarations, see Section&nbsp;<a href="#sec:idtrans">9.3</a>.
(The optional parts resulting from the specification are shown enclosed in
<font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">]</span></font>.)
<div class="p"><!----></div>
The method response is expected to be of the form:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>response-element-name xsi:type="<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>response-element-name&#62; <br />
&lt;outparam-name1 xsi:type="..."&#62;...&lt;/outparam-name1&#62; <br />
&lt;outparam-name2 xsi:type="..."&#62;...&lt;/outparam-name2&#62; <br />
... <br />
&lt;/<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>response-element-name&#62;
</td></tr></table><br></tt>
where the <tt>outparam-name</tt> accessors are the element-name representations of
the <i>outparam</i> parameter name declarations, see Section&nbsp;<a href="#sec:idtrans">9.3</a>.
(The optional parts resulting from the specification are shown enclosed in
<font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">]</span></font>.)
<div class="p"><!----></div>
The input and/or output parameters can be made anonymous, which allows the
deserialization of requests/responses with different parameter names as is
endorsed by the SOAP 1.1 specification, see Section&nbsp;<a href="#sec:anonymous">7.1.13</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc9.2">
9.2</a>&nbsp;&nbsp;<font color="#0000FF">Error Codes</font></h3><a name="sec:errcodes">
</a>
<div class="p"><!----></div>
The error codes returned by the stub and skeleton routines are listed below.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td align="right"><font color="#FF0000"><b>Code</b></font> </td><td><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td align="right"><i>SOAP_OK</i> </td><td>No error </td></tr>
<tr><td align="right"><i>SOAP_CLI_FAULT</i>* </td><td>The service returned a client fault (SOAP 1.2 Sender fault)</td></tr>
<tr><td align="right"><i>SOAP_SVR_FAULT</i>* </td><td>The service returned a server fault (SOAP 1.2 Receiver fault)</td></tr>
<tr><td align="right"><i>SOAP_TAG_MISMATCH</i> </td><td>An XML element didn't correspond to anything expected </td></tr>
<tr><td align="right"><i>SOAP_TYPE</i> </td><td>An XML Schema type mismatch </td></tr>
<tr><td align="right"><i>SOAP_SYNTAX_ERROR</i> </td><td>An XML syntax error occurred on the input </td></tr>
<tr><td align="right"><i>SOAP_NO_TAG</i> </td><td>Begin of an element expected, but not found </td></tr>
<tr><td align="right"><i>SOAP_IOB</i> </td><td>Array index out of bounds </td></tr>
<tr><td align="right"><i>SOAP_MUSTUNDERSTAND</i>* </td><td>An element needs to be ignored that need to be understood </td></tr>
<tr><td align="right"><i>SOAP_NAMESPACE</i> </td><td>Namespace name mismatch (validation error) </td></tr>
<tr><td align="right"><i>SOAP_OBJ_MISMATCH</i> </td><td>Mismatch in the size and/or shape of an object </td></tr>
<tr><td align="right"><i>SOAP_FATAL_ERROR</i> </td><td>Internal error </td></tr>
<tr><td align="right"><i>SOAP_FAULT</i> </td><td>An exception raised by the service </td></tr>
<tr><td align="right"><i>SOAP_NO_METHOD</i> </td><td>Skeleton error: the skeleton cannot serve the method </td></tr>
<tr><td align="right"><i>SOAP_GET_METHOD</i> </td><td>Unsupported HTTP GET </td></tr>
<tr><td align="right"><i>SOAP_EOM</i> </td><td>Out of memory </td></tr>
<tr><td align="right"><i>SOAP_NULL</i> </td><td>An element was null, while it is not supposed to be null </td></tr>
<tr><td align="right"><i>SOAP_MULTI_ID</i> </td><td>Multiple occurrences of the same element ID on the input </td></tr>
<tr><td align="right"><i>SOAP_MISSING_ID</i> </td><td>Element ID missing for an HREF on the input </td></tr>
<tr><td align="right"><i>SOAP_HREF</i> </td><td>Reference to object is incompatible with the object refered to </td></tr>
<tr><td align="right"><i>SOAP_UDP_ERROR</i> </td><td>Message too large to store in UDP packet </td></tr>
<tr><td align="right"><i>SOAP_TCP_ERROR</i> </td><td>A connection error occured </td></tr>
<tr><td align="right"><i>SOAP_HTTP_ERROR</i> </td><td>An HTTP error occured </td></tr>
<tr><td align="right"><i>SOAP_SSL_ERROR</i> </td><td>An SSL error occured </td></tr>
<tr><td align="right"><i>SOAP_ZLIB_ERROR</i> </td><td>A Zlib error occured </td></tr>
<tr><td align="right"><i>SOAP_PLUGIN_ERROR</i> </td><td>Failed to register plugin </td></tr>
<tr><td align="right"><i>SOAP_MIME_ERROR</i> </td><td>MIME parsing error </td></tr>
<tr><td align="right"><i>SOAP_DIME_ERROR</i> </td><td>DIME parsing error </td></tr>
<tr><td align="right"><i>SOAP_DIME_END</i> </td><td>End of DIME error </td></tr>
<tr><td align="right"><i>SOAP_DIME_HREF</i> </td><td>DIME attachment has no href from SOAP body </td></tr>
<tr><td align="right"></td><td>(and no DIME callbacks were defined to save the attachment) </td></tr>
<tr><td align="right"><i>SOAP_DIME_MISMATCH</i> </td><td>DIME version/transmission error </td></tr>
<tr><td align="right"><i>SOAP_VERSIONMISMATCH</i>* </td><td>SOAP version mismatch or no SOAP message </td></tr>
<tr><td align="right"><i>SOAP_DATAENCODINGUNKNOWN</i> </td><td>SOAP 1.2 DataEncodingUnknown fault </td></tr>
<tr><td align="right"><i>SOAP_REQUIRED</i> </td><td>Attributed required validation error </td></tr>
<tr><td align="right"><i>SOAP_PROHIBITED</i> </td><td>Attributed prohibited validation error </td></tr>
<tr><td align="right"><i>SOAP_OCCURS</i> </td><td>Element minOccurs/maxOccurs validation error </td></tr>
<tr><td align="right"><i>SOAP_LENGTH</i> </td><td>Element length validation error </td></tr>
<tr><td align="right"><i>SOAP_EOF</i> </td><td>Unexpected end of file, no input, or timeout while receiving data </td></tr></table>
</td></tr></table><br></span>
The error codes that are returned by a stub routine (proxy) upon receiving a
SOAP Fault from the server are marked (*). The remaining error codes are
generated by the proxy itself as a result of problems with a SOAP payload. The
error code is <i>SOAP_OK</i> when the remote method call was successful (the
<i>SOAP_OK</i> predefined constant is guaranteed to be <i>0</i>). The error
code is also stored in <i>soap.error</i>, where <i>soap</i> is a variable that
contains the current runtime environment. The function
<i>soap_print_fault(<b>struct</b>&nbsp;soap *soap, FILE *fd)</i> can be called to
display an error message on <i>fd</i> where current value of the
<i>soap.error</i> variable is used by the function to display the error. The
function <i>soap_print_fault_location(<b>struct</b>&nbsp;soap *soap, FILE *fd)</i>
prints the location of the error if the error is a result from parsing XML.
<div class="p"><!----></div>
A remote method implemented in a SOAP service MUST return an error code as the
function's return value. <i>SOAP_OK</i> denotes success and <i>SOAP_FAULT</i>
denotes an exception. The exception details can be assigned with the
<i>soap_receiver_fault(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring,
<b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i> which sets the strings
<i>soap.fault</i><tt>-&gt;</tt><i>faultstring</i> and
<i>soap.fault</i><tt>-&gt;</tt><i>detail</i> for SOAP 1.1, and
<i>soap.fault</i><tt>-&gt;</tt><i>SOAP_ENV__Reason</i> and
<i>soap.fault</i><tt>-&gt;</tt><i>SOAP_ENV__Detail</i> for SOAP 1.2, where
<i>soap</i> is a variable that contains the current runtime environment, see
Section&nbsp;<a href="#sec:fault">11</a>.
A receiver error indicates that the service can't handle the request, but can possibly recover from the error.
To return an unrecoverable error, use <i>soap_receiver_fault(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*faultstring,
<b>const</b>&nbsp;<b>char</b>&nbsp;*detail)</i>.
<div class="p"><!----></div>
To return a HTTP error code a service method can simply return the HTTP error code number.
For example, <i><b>return</b>&nbsp;404;</i> returns a "404 Not Found" HTTP error back to the client. The <i>soap.error</i>
is set to the HTTP error code at the client side.
The HTTP 1.1 error codes are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td align="right"><font color="#FF0000"><b>#</b></font> </td><td><font color="#FF0000"><b>Error</b></font> </td></tr>
<tr><td align="right">201 </td><td>Created </td></tr>
<tr><td align="right">202 </td><td>Accepted </td></tr>
<tr><td align="right">203 </td><td>Non-Authoritative Information </td></tr>
<tr><td align="right">204 </td><td>No Content </td></tr>
<tr><td align="right">205 </td><td>Reset Content </td></tr>
<tr><td align="right">206 </td><td>Partial Content </td></tr>
<tr><td align="right">300 </td><td>Multiple Choices </td></tr>
<tr><td align="right">301 </td><td>Moved Permanently </td></tr>
<tr><td align="right">302 </td><td>Found </td></tr>
<tr><td align="right">303 </td><td>See Other </td></tr>
<tr><td align="right">304 </td><td>Not Modified </td></tr>
<tr><td align="right">305 </td><td>Use Proxy </td></tr>
<tr><td align="right">307 </td><td>Temporary Redirect </td></tr>
<tr><td align="right">400 </td><td>Bad Request </td></tr>
<tr><td align="right">401 </td><td>Unauthorized </td></tr>
<tr><td align="right">402 </td><td>Payment Required </td></tr>
<tr><td align="right">403 </td><td>Forbidden </td></tr>
<tr><td align="right">404 </td><td>Not Found </td></tr>
<tr><td align="right">405 </td><td>Method Not Allowed </td></tr>
<tr><td align="right">406 </td><td>Not Acceptable </td></tr>
<tr><td align="right">407 </td><td>Proxy Authentication Required </td></tr>
<tr><td align="right">408 </td><td>Request Time-out </td></tr>
<tr><td align="right">409 </td><td>Conflict </td></tr>
<tr><td align="right">410 </td><td>Gone </td></tr>
<tr><td align="right">411 </td><td>Length Required </td></tr>
<tr><td align="right">412 </td><td>Precondition Failed </td></tr>
<tr><td align="right">413 </td><td>Request Entity Too Large </td></tr>
<tr><td align="right">414 </td><td>Request-URI Too Large </td></tr>
<tr><td align="right">415 </td><td>Unsupported Media Type </td></tr>
<tr><td align="right">416 </td><td>Requested range not satisfiable </td></tr>
<tr><td align="right">417 </td><td>Expectation Failed </td></tr>
<tr><td align="right">500 </td><td>Internal Server Error </td></tr>
<tr><td align="right">501 </td><td>Not Implemented </td></tr>
<tr><td align="right">502 </td><td>Bad Gateway </td></tr>
<tr><td align="right">503 </td><td>Service Unavailable </td></tr>
<tr><td align="right">504 </td><td>Gateway Time-out </td></tr>
<tr><td align="right">505 </td><td>HTTP Version not supported </td></tr></table>
</td></tr></table><br></span>
The error codes are given for informational purposes only. The HTTP protocol requires the proper actions after an error is issued. gSOAP's HTTP 1.0/1.1 handling is automatic.
<div class="p"><!----></div>
<h3><a name="tth_sEc9.3">
9.3</a>&nbsp;&nbsp;<font color="#0000FF">C/C++ Identifier Name to XML Name Translations</font></h3><a name="sec:idtrans">
</a>
<div class="p"><!----></div>
One of the "secrets" behind the power and flexibility of gSOAP's encoding and
decoding of remote method names, class names, type identifiers, and struct or
class fields is the ability to specify namespace prefixes with these names that
are used to denote their encoding style. More specifically, a C/C++ identifier
name of the form
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>element_name
</td></tr></table><br></i>
will be encoded in XML as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>element-name ...&#62;
</td></tr></table><br></tt>
The <b>underscore pair</b> (<i>__</i>) separates the namespace prefix from the
element name. Each namespace prefix has a namespace URI specified by a
namespace mapping table&nbsp;<a href="#sec:nstable">9.4</a>, see also
Section&nbsp;<a href="#sec:namespace">7.1.2</a>. The namespace URI is a unique identification that
can be associated with the remote methods and data types. The namespace URI
disambiguates potentially identical remote method names and data type names
used by disparate organizations.
<div class="p"><!----></div>
XML element names are NCNames (restricted strings) that MAY contain <b>
hyphens</b>, <b>dots</b>, and <b>underscores</b>. The special characters in the XML
element names of remote methods, structs, classes, typedefs, and fields can be
controlled using the following conventions: A <b>single underscore</b> in a
namespace prefix or identifier name is replaced by a hyphen (<tt>-</tt>) in the
XML element name. For example, the identifier name <i>SOAP_ENC__ur_type</i>
is represented in XML as <tt>SOAP-ENC:ur-type</tt>. The sequence <i>_DOT</i> is
replaced by a dot (<tt>.</tt>), and the sequence <i>_USCORE</i> is replaced by
an underscore (<tt>_</tt>) in the corresponding XML element name. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;n_s__biz_DOTcom <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*n_s__biz_USCOREname; <br />
};
</td></tr></table><br></i>
is encoded in XML as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;n-s:biz.com xsi:type="n-s:biz.com"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;n-s:biz_name xsi:type="string"&#62;Bizybiz&lt;/n-s:biz_name&#62; <br />
&lt;/n-s:biz.com&#62;
</td></tr></table><br></tt>
Trailing underscores of an identifier name are not translated into the XML
representation. This is useful when an identifier name clashes with a C++
keyword. For example, <tt>return</tt> is often used as an accessor name in a SOAP
response element. The <tt>return</tt> element can be specified as <i>return_</i>
in the C++ source code. Note that XML should be treated as case sensitive, so
the use of e.g. <i>Return</i> may not always work to avoid a name clash with the
<i><b>return</b></i> keyword. The use of trailing underscores also allows for
defining <i><b>struct</b></i>s and <i><b>class</b></i>es with essentially the same XML Schema
type name, but that have to be distinguished as seperate C/C++ types.
<div class="p"><!----></div>
For decoding, the underscores in identifier names act as wildcards. An XML
element is parsed and matches the name of an identifier if the name is
identical to the element name (case insensitive) and the underscores in the
identifier name are allowed to match any character in the element name. For
example, the identifier name <i>I_want__soap_fun_the_bea___DOTcom</i>
matches the element name <tt>I-want:SOAP4fun@the-beach.com</tt>.
<div class="p"><!----></div>
<h3><a name="tth_sEc9.4">
9.4</a>&nbsp;&nbsp;<font color="#0000FF">Namespace Mapping Table</font></h3><a name="sec:nstable">
</a>
<div class="p"><!----></div>
A namespace mapping table MUST be defined by clients and service applications.
The mapping table is used by the serializers and deserializers of the stub and
skeleton routines to produce a valid SOAP payload and to validate an incoming
SOAP payload. A typical mapping table is shown below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name"} <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, // MUST be first <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, // MUST be second <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, // MUST be third <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, // Required for XML Schema types <br />
&nbsp;&nbsp;&nbsp;{"ns1", "urn:my-service-URI"}, // The namespace URI of the remote methods <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} // end of table <br />
}; <br />
</td></tr></table><br></i>
Each namespace prefix used by a identifier name in the header file
specification (see Section&nbsp;<a href="#sec:idtrans">9.3</a>) MUST have a binding to a
namespace URI in the mapping table. The end of the namespace mapping table MUST
be indicated by the <i>NULL</i> pair. The namespace URI matching is case
insensitive. A namespace prefix is distinguished by the occurrence of a pair
of underscores (<i>__</i>) in an identifier.
<div class="p"><!----></div>
An optional namespace pattern MAY be provided with each namespace mapping table
entry. The patterns provide an alternative namespace matching for the
validation of decoded SOAP messages. In this pattern, dashes (<i>-</i>) are
single-character wildcards and asterisks (<i>*</i>) are multi-character
wildcards. For example, to decode different versions of XML Schema type with
different authoring dates, four dashes can be used in place of the specific
dates in the namespace mapping table pattern:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name", "ns-name validation pattern"} <br />
... <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/<tt>----</tt>/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/<tt>----</tt>/XMLSchema"}, <br />
...
</td></tr></table><br></i>
Or alternatively, asterisks can be used as wildcards for multiple characters:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name", "ns-name validation pattern"} <br />
... <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema"}, <br />
...
</td></tr></table><br></i>
A namespace mapping table is automatically generated together with a WSDL file
for each namespace prefix that is used for a remote method in the header file.
This namespace mapping table has entries for all namespace prefixes. The
namespace URIs need to be filled in. These appear as <i>http://tempuri.org</i>
in the table. See Section&nbsp;<a href="#sec:directives">18.2</a> on how to specify the namespace
URIs in the header file.
<div class="p"><!----></div>
For decoding elements with namespace prefixes, the namespace URI associated with the namespace prefix (through the <tt>xmlns</tt>
attribute of an XML element) is searched from the
beginning to the end in a namespace mapping table,
and for every row the following tests are performed as part of the validation process:
<ol type="1">
<li> the string in the second column matches the namespace URI (case insensitive)
<div class="p"><!----></div>
</li>
<li> the string in the optional third column matches the namespace URI (case insensitive), where <i>-</i> is a one-character wildcard and <i>*</i> is a
multi-character wildcard
<div class="p"><!----></div>
</li>
</ol>
When a match is found, the namespace prefix in the first column of the table is considered semantically identical to the namespace prefix used
by the XML element to be decoded, though the prefix names may differ.
A service will respond with the namespace that it received from a client in case it matches a pattern in the third column.
<div class="p"><!----></div>
For example, let's say we have the following structs:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;a__elt { ... }; <br />
<b>struct</b>&nbsp;b__elt { ... }; <br />
<b>struct</b>&nbsp;k__elt { ... }; <br />
</td></tr></table><br></i>
and a namespace mapping table in the program:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{&nbsp;&nbsp;&nbsp;// {"ns-prefix", "ns-name", "ns-name validation pattern"} <br />
... <br />
&nbsp;&nbsp;&nbsp;{"a", "some uri"}, <br />
&nbsp;&nbsp;&nbsp;{"b", "other uri"}, <br />
&nbsp;&nbsp;&nbsp;{"c", "his uri", "* uri"}, <br />
...
</td></tr></table><br></i>
Then, the following XML elements will match the structs:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;n:elt xmlns:n="some URI"&#62; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matches the struct name <i>a__elt</i> <br />
... <br />
&lt;m:elt xmlns:m="other URI"&#62; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matches the struct name <i>b__elt</i> <br />
... <br />
&lt;k:elt xmlns:k="my URI"&#62; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matches the struct name <i>c__elt</i> <br />
... <br />
</td></tr></table><br></tt>
The response of a service to a client request that uses the namespaces listed above,
will include <tt>my URI</tt> for the name space of element <tt>k</tt>.
<div class="p"><!----></div>
It is possible to use a number of different namespace tables and select the one that is appropriate.
For example, an application might contact many different Web services all using different namespace URIs.
If all the URIs are stored in one table, each remote method invocation will dump the whole namespace
table in the SOAP payload. There is no technical problem with that, but it can be ugly when the table is large.
To use different namespace tables, declare a pointer to a table and set the pointer to a particular table before remote method
invocation. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Namespace namespacesTable1[] = { ... }; <br />
<b>struct</b>&nbsp;Namespace namespacesTable2[] = { ... }; <br />
<b>struct</b>&nbsp;Namespace namespacesTable3[] = { ... }; <br />
<b>struct</b>&nbsp;Namespace *namespaces; <br />
... <br />
<b>struct</b>&nbsp;soap soap; <br />
... <br />
soap_init(&amp;soap); <br />
soap_set_namespaces(&amp;soap, namespaceTable1); <br />
soap_call_remote_method(&amp;soap, URL, Action, ...); <br />
...
</td></tr></table><br></i>
<div class="p"><!----></div>
<h2><a name="tth_sEc10">
10</a>&nbsp;&nbsp;<font color="#0000FF">gSOAP Serialization and Deserialization Rules</font></h2>
<div class="p"><!----></div>
This section describes the serialization and deserialization of C and C++ data types for SOAP 1.1 and 1.2 compliant encoding and decoding.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.1">
10.1</a>&nbsp;&nbsp;<font color="#0000FF">Primitive Type Encoding</font></h3>
<div class="p"><!----></div>
The default encoding rules for the primitive C and C++ data types are given in the table below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Type</b></font> </td><td><font color="#FF0000"><b>XSD Type</b></font> </td></tr>
<tr><td><i><b>bool</b></i> </td><td><tt>boolean</tt> </td></tr>
<tr><td><i><b>char</b>*</i> (C string) </td><td><tt>string</tt> </td></tr>
<tr><td><i><b>char</b></i> </td><td><tt>byte</tt> </td></tr>
<tr><td><i><b>double</b></i> </td><td><tt>double</tt> </td></tr>
<tr><td><i><b>float</b></i> </td><td><tt>float</tt> </td></tr>
<tr><td><i><b>int</b></i> </td><td><tt>int</tt> </td></tr>
<tr><td><i><b>long</b></i> </td><td><tt>long</tt> </td></tr>
<tr><td><i>LONG64</i> </td><td><tt>long</tt> </td></tr>
<tr><td><i><b>long</b>&nbsp;<b>long</b></i> </td><td><tt>long</tt> </td></tr>
<tr><td><i><b>short</b></i> </td><td><tt>short</tt> </td></tr>
<tr><td><i>time_t</i> </td><td><tt>dateTime</tt> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>char</b></i> </td><td><tt>unsignedByte</tt> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>int</b></i> </td><td><tt>unsignedInt</tt> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b></i> </td><td><tt>unsignedLong</tt> </td></tr>
<tr><td><i>ULONG64</i> </td><td><tt>unsignedLong</tt> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b></i> </td><td><tt>unsignedLong</tt> </td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>short</b></i> </td><td><tt>unsignedShort</tt> </td></tr>
<tr><td><i>wchar_t*</i> </td><td><tt>string</tt> </td></tr></table>
</td></tr></table><br></span>
Objects of type <i><b>void</b></i> and <i><b>void</b>*</i> cannot be encoded.
Enumerations and bit masks are supported as well, see&nbsp;<a href="#sec:enum">10.3</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.2">
10.2</a>&nbsp;&nbsp;<font color="#0000FF">How to Encode and Decode Primitive Types as XSD Types</font></h3><a name="sec:primitive">
</a>
<div class="p"><!----></div>
By default, encoding of the primitive types will take place as per SOAP
encoding style. The encoding can be changed to any XML Schema type (XSD type) with an
optional namespace prefix by using a <i><b>typedef</b></i> in the header file input to
the gSOAP stub and skeleton compiler. The declaration enables the
implementation of built-in XML Schema types (also known as XSD types) such as
<tt>positiveInteger</tt>, <tt>xsd:anyURI</tt>, and <tt>xsd:date</tt> for which no
built-in data structures in C and C++ exist but which can be represented using
standard data structures such as strings, integers, and floats.
<div class="p"><!----></div>
The <i><b>typedef</b></i> declaration is frequently used for convenience in C. A
<i><b>typedef</b></i> declares a type name for a (complex) type expression. The type
name can then be used in other declarations in place of the more complex type
expression, which often improves the readability of the program code.
<div class="p"><!----></div>
The gSOAP compiler interprets <i><b>typedef</b></i> declarations the same way as a
regular C compiler interprets them, i.e.&nbsp;as types in declarations. In addition
however, the gSOAP compiler will also use the type name in the encoding of the
data in SOAP. The <i><b>typedef</b></i> name will appear as the XML element name of
an independent element and as the value of the <tt>xsi:type</tt> attribute in the
SOAP payload.
<div class="p"><!----></div>
Many built-in primitive and derived XSD types such as <tt>xsd:anyURI</tt>,
<tt>positiveInteger</tt>, and <tt>decimal</tt> can be stored by standard primitive
data structures in C++ as well such as strings, integers, floats, and doubles.
To serialize strings, integers, floats, and doubles as built-in primitive and
derived XSD types. To this end, a <i><b>typedef</b></i> declaration can be used
to declare an XSD type.
<div class="p"><!----></div>
For example, the declaration
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>int</b>&nbsp;xsd__positiveInteger;
</td></tr></table><br></i>
creates a named type <i>positiveInteger</i> which is represented by <i><b>unsigned</b>&nbsp;<b>int</b></i> in C++. For example, the encoding of a
<i>positiveInteger</i> value <i>3</i> is
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;positiveInteger xsi:type="xsd:positiveInteger"&#62;3&lt;/positiveInteger&#62;
</td></tr></table><br></tt>
The built-in XML Schema datatype hierarchy from the XML Schema Part 2 documentation <a href="http://www.w3.org/TR/xmlschema-2"><tt>http://www.w3.org/TR/xmlschema-2</tt></a> is depicted below.
<div class="p"><!----></div>
<a name="tth_fIg1">
</a>
<center><img src="http://www.w3.org/TR/xmlschema-2/type-hierarchy.gif"/>
</center>
<center>Figure 1: Built-in Datatype Hierarchy</center>
<div class="p"><!----></div>
The built-in primitive and derived numerical XML Schema types are listed below together with their recommended <i><b>typedef</b></i>
declarations. Note that the SOAP encoding schemas for primitive types are derived from the built-in XML Schema types, so
<i>SOAP_ENC__</i> can be used as a namespace prefix instead of <i>xsd__</i>.
<dl compact="compact">
<dt><b><tt>xsd:anyURI</tt></b></dt>
<dd>
Represents a Uniform Resource Identifier Reference (URI).
Each URI scheme imposes specialized syntax rules for URIs in that scheme, including restrictions
on the syntax of allowed fragment identifiers.
It is recommended to use strings to store <tt>xsd:anyURI</tt> XML Schema types. The recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__anyURI;
</td></tr></table><br></i></dd>
<dt><b><tt>xsd:base64Binary</tt></b></dt>
<dd>
Represents Base64-encoded arbitrary binary data.
For using the <tt>xsd:base64Binary</tt> XSD Schema type, the use of the base64Binary representation of a dynamic array is <b>strongly</b> recommended,
see Section&nbsp;<a href="#sec:base64binary">10.11</a>. However, the
type can also be declared as a string and the encoding will be string-based:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__base64Binary;
</td></tr></table><br></i>
With this approach, it is solely the responsibility of the application to make sure the string content is according to the Base64 Content-Transfer-Encoding defined in Section 6.8 of RFC 2045.</dd>
<dt><b><tt>xsd:boolean</tt></b></dt>
<dd>
For declaring an <tt>xsd:boolean</tt> XSD Schema type, the use of a bool is <b>strongly</b> recommended.
If a pure C compiler is used that does not support the <i>bool</i> type, see Section&nbsp;<a href="#sec:boolean">10.3.5</a>.
The corresponding type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>bool</b>&nbsp;xsd__boolean;
</td></tr></table><br></i>
Type <i>xsd__boolean</i> declares a Boolean (0 or 1), which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:boolean xsi:type="xsd:boolean"&#62;...&lt;/xsd:boolean&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:byte</tt></b></dt>
<dd>
Represents a byte (-128...127). The corresponding type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;xsd__byte;
</td></tr></table><br></i>
Type <i>xsd__byte</i> declares a byte which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:byte xsi:type="xsd:byte"&#62;...&lt;/xsd:byte&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:dateTime</tt></b></dt>
<dd>
Represents a date and time. The lexical representation is according to the ISO 8601 extended format CCYY-MM-DDThh:mm:ss where "CC"
represents the century, "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-" sign to indicate a
negative number. If the sign is omitted, "+" is assumed. The letter "T" is the date/time separator and "hh", "mm", "ss" represent
hour, minute and second respectively.
It is recommended to use the <i>time_t</i> type to store <tt>xsd:dateTime</tt> XSD Schema types and the type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;time_t xsd__dateTime;
</td></tr></table><br></i>
However, note that calendar times before the year 1902 or after
the year 2037 cannot be represented. Upon receiving a date outside this range,
the <i>time_t</i> value will be set to -1.
<div class="p"><!----></div>
Strings (<i><b>char</b>*</i>) can be used to store <tt>xsd:dateTime</tt> XSD Schema types. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__dateTime;
</td></tr></table><br></i>
In this case, it is up to the application to read and set the dateTime representation.</dd>
<dt><b><tt>xsd:date</tt></b></dt>
<dd>
Represents a date.
The lexical representation for date is the reduced (right truncated) lexical representation for dateTime: CCYY-MM-DD.
It is recommended to use strings (<i><b>char</b>*</i>) to store <tt>xsd:date</tt> XSD Schema types. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__date;
</td></tr></table><br></i></dd>
<dt><b><tt>xsd:decimal</tt></b></dt>
<dd>
Represents arbitrary precision decimal numbers.
It is recommended to use the <b>double</b> type to store <tt>xsd:decimal</tt> XSD Schema types and the type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__decimal;
</td></tr></table><br></i>
Type <i>xsd__decimal</i> declares a double floating point number which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:double xsi:type="xsd:decimal"&#62;...&lt;/xsd:double&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:double</tt></b></dt>
<dd>
Corresponds to the IEEE double-precision 64-bit floating point type. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__double;
</td></tr></table><br></i>
Type <i>xsd__double</i> declares a double floating point number which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:double xsi:type="xsd:double"&#62;...&lt;/xsd:double&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:duration</tt></b></dt>
<dd>
Represents a duration of time.
The lexical representation for duration is the ISO 8601 extended format PnYn MnDTnH nMnS, where nY represents
the number of years, nM the number of months, nD the number of days, T is the date/time separator, nH the number of
hours, nM the number of minutes and nS the number of seconds. The number of seconds can include decimal digits to
arbitrary precision.
It is recommended to use strings (<i><b>char</b>*</i>) to store <tt>xsd:duration</tt> XSD Schema types. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__duration;
</td></tr></table><br></i></dd>
<dt><b><tt>xsd:float</tt></b></dt>
<dd>
Corresponds to the IEEE single-precision 32-bit floating point type. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float;
</td></tr></table><br></i>
Type <i>xsd__float</i> declares a floating point number which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:float xsi:type="xsd:float"&#62;...&lt;/xsd:float&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:hexBinary</tt></b></dt>
<dd>
Represents arbitrary hex-encoded binary data. It has a lexical representation where each binary octet is encoded as a character
tuple, consisting of two hexadecimal digits ([0-9a-fA-F]) representing the octet code. For example, "0FB7" is a hex encoding for
the 16-bit integer 4023 (whose binary representation is 111110110111.
For using the <tt>xsd:hexBinary</tt> XSD Schema type, the use of the hexBinary representation of a dynamic array is <b>strongly</b> recommended,
see Section&nbsp;<a href="#sec:hexbinary">10.12</a>. However, the
type can also be declared as a string and the encoding will be string-based:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__hexBinary;
</td></tr></table><br></i>
With this approach, it is solely the responsibility of the application to make sure the string content consists of a sequence of octets.</dd>
<dt><b><tt>xsd:int</tt></b></dt>
<dd>
Corresponds to a 32-bit integer in the range -2147483648 to 2147483647.
If the C++ compiler supports 32-bit <i><b>int</b></i> types, the type declaration can use the <i><b>int</b></i> type:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>int</b>&nbsp;xsd__int;
</td></tr></table><br></i>
Otherwise, the C++ compiler supports 16-bit <i><b>int</b></i> types and the type declaration should use the <i><b>long</b></i> type:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;xsd__int;
</td></tr></table><br></i>
Type <i>xsd__int</i> declares a 32-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:int xsi:type="xsd:int"&#62;...&lt;/xsd:int&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:integer</tt></b></dt>
<dd>
Corresponds to an unbounded integer.
Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__integer;
</td></tr></table><br></i>
Type <i>xsd__integer</i> declares a 64-bit integer which is encoded as an unbounded <tt>xsd:integer</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:integer xsi:type="xsd:integer"&#62;...&lt;/xsd:integer&#62;
</td></tr></table><br></tt>
Another possibility is to use strings to represent unbounded integers and do the translation in code.</dd>
<dt><b><tt>xsd:long</tt></b></dt>
<dd>
Corresponds to a 64-bit integer in the range -9223372036854775808 to 9223372036854775807.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__long;
</td></tr></table><br></i>
Or in Visual C++:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;LONG64 xsd__long;
</td></tr></table><br></i>
Type <i>xsd__long</i> declares a 64-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:long xsi:type="xsd:long"&#62;...&lt;/xsd:long&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:negativeInteger</tt></b></dt>
<dd>
Corresponds to a negative unbounded integer ( &lt; 0).
Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__negativeInteger;
</td></tr></table><br></i>
Type <i>xsd__negativeInteger</i> declares a 64-bit integer which is encoded as a <tt>xsd:negativeInteger</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:negativeInteger xsi:type="xsd:negativeInteger"&#62;...&lt;/xsd:negativeInteger&#62;
</td></tr></table><br></tt>
Another possibility is to use strings to represent unbounded integers and do the translation in code.</dd>
<dt><b><tt>xsd:nonNegativeInteger</tt></b></dt>
<dd>
Corresponds to a non-negative unbounded integer ( &gt; 0).
Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__nonNegativeInteger;
</td></tr></table><br></i>
Type <i>xsd__nonNegativeInteger</i> declares a 64-bit unsigned integer which is encoded as a non-negative unbounded <tt>xsd:nonNegativeInteger</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:nonNegativeInteger xsi:type="xsd:nonNegativeInteger"&#62;...&lt;/xsd:nonNegativeInteger&#62;
</td></tr></table><br></tt>
Another possibility is to use strings to represent unbounded integers and do the translation in code.</dd>
<dt><b><tt>xsd:nonPositiveInteger</tt></b></dt>
<dd>
Corresponds to a non-positive unbounded integer ( <font face="symbol">£</font
> 0).
Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__nonPositiveInteger;
</td></tr></table><br></i>
Type <i>xsd__nonPositiveInteger</i> declares a 64-bit integer which is encoded as a <tt>xsd:nonPositiveInteger</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:nonPositiveInteger xsi:type="xsd:nonPositiveInteger"&#62;...&lt;/xsd:nonPositiveInteger&#62;
</td></tr></table><br></tt>
Another possibility is to use strings to represent unbounded integers and do the translation in code.</dd>
<dt><b><tt>xsd:normalizedString</tt></b></dt>
<dd>
Represents normalized character strings.
Normalized character strings do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters.
It is recommended to use strings to store <tt>xsd:normalizeString</tt> XSD Schema types.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__normalizedString;
</td></tr></table><br></i>
Type <i>xsd__normalizedString</i> declares a string type which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:normalizedString xsi:type="xsd:normalizedString"&#62;...&lt;/xsd:normalizedString&#62;
</td></tr></table><br></tt>
It is solely the responsibility of the application to make sure the strings do not contain carriage return (#xD), line feed (#xA)
and tab (#x9) characters.</dd>
<dt><b><tt>xsd:positiveInteger</tt></b></dt>
<dd>
Corresponds to a positive unbounded integer ( <font face="symbol">³</font
> 0).
Since C++ does not support unbounded integers as a standard feature, the recommended type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__positiveInteger;
</td></tr></table><br></i>
Type <i>xsd__positiveInteger</i> declares a 64-bit unsigned integer which is encoded as a <tt>xsd:positiveInteger</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:positiveInteger xsi:type="xsd:positiveInteger"&#62;...&lt;/xsd:positiveInteger&#62;
</td></tr></table><br></tt>
Another possibility is to use strings to represent unbounded integers and do the translation in code.</dd>
<dt><b><tt>xsd:short</tt></b></dt>
<dd>
Corresponds to a 16-bit integer in the range -32768 to 32767.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>short</b>&nbsp;xsd__short;
</td></tr></table><br></i>
Type <i>xsd__short</i> declares a short 16-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:short xsi:type="xsd:short"&#62;...&lt;/xsd:short&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:string</tt></b></dt>
<dd>
Represents character strings. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string;
</td></tr></table><br></i>
Type <i>xsd__string</i> declares a string type which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:string xsi:type="xsd:string"&#62;...&lt;/xsd:string&#62;
</td></tr></table><br></tt>
The type declaration for wide character strings is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;wchar_t *xsd__string;
</td></tr></table><br></i>
Both type of strings can be used at the same time, but requires one typedef name to be changed by appending an underscore which is
invisible in XML. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;wchar_t *xsd__string_;
</td></tr></table><br></i></dd>
<dt><b><tt>xsd:time</tt></b></dt>
<dd>
Represents a time. The lexical representation for time is the left truncated lexical representation for dateTime: hh:mm:ss.sss
with optional following time zone indicator.
It is recommended to use strings (<i><b>char</b>*</i>) to store <tt>xsd:time</tt> XSD Schema types. The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__time;
</td></tr></table><br></i></dd>
<dt><b><tt>xsd:token</tt></b></dt>
<dd>
Represents tokenized strings.
Tokens are strings that do not contain the
line feed (#xA) nor tab (#x9) characters, that have no leading or trailing spaces (#x20) and that have no internal
sequences of two or more spaces.
It is recommended to use strings to store <tt>xsd:token</tt> XSD Schema types.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__token;
</td></tr></table><br></i>
Type <i>xsd__token</i> declares a string type which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:token xsi:type="xsd:token"&#62;...&lt;/xsd:token&#62;
</td></tr></table><br></tt>
It is solely the responsibility of the application to make sure the strings do not contain the line feed (#xA) nor tab (#x9)
characters, that have no leading or trailing spaces (#x20) and that have no internal sequences of two or more spaces.</dd>
<dt><b><tt>xsd:unsignedByte</tt></b></dt>
<dd>
Corresponds to an 8-bit unsigned integer in the range 0 to 255.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;xsd__unsignedByte;
</td></tr></table><br></i>
Type <i>xsd__unsignedByte</i> declares a unsigned 8-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:unsignedByte xsi:type="xsd:unsignedByte"&#62;...&lt;/xsd:unsignedByte&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:unsignedInt</tt></b></dt>
<dd>
Corresponds to a 32-bit unsigned integer in the range 0 to 4294967295.
If the C++ compiler supports 32-bit <i><b>int</b></i> types, the type declaration can use the <i><b>int</b></i> type:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>int</b>&nbsp;xsd__unsignedInt;
</td></tr></table><br></i>
Otherwise, the C++ compiler supports 16-bit <i><b>int</b></i> types and the type declaration should use the <i><b>long</b></i> type:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;xsd__unsignedInt;
</td></tr></table><br></i>
Type <i>xsd__unsignedInt</i> declares an unsigned 32-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:unsignedInt xsi:type="xsd:unsignedInt"&#62;...&lt;/xsd:unsignedInt&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:unsignedLong</tt></b></dt>
<dd>
Corresponds to a 64-bit unsigned integer in the range 0 to 18446744073709551615.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__unsignedLong;
</td></tr></table><br></i>
Or in Visual C++:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;ULONG64 xsd__unsignedLong;
</td></tr></table><br></i>
Type <i>xsd__unsignedLong</i> declares an unsigned 64-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:unsignedLong xsi:type="xsd:unsignedLong"&#62;...&lt;/xsd:unsignedLong&#62;
</td></tr></table><br></tt></dd>
<dt><b><tt>xsd:unsignedShort</tt></b></dt>
<dd>
Corresponds to a 16-bit unsigned integer in the range 0 to 65535.
The type declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>short</b>&nbsp;xsd__unsignedShort;
</td></tr></table><br></i>
Type <i>xsd__unsginedShort</i> declares an unsigned short 16-bit integer which is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:unsignedShort xsi:type="xsd:unsignedShort"&#62;...&lt;/xsd:unsignedShort&#62;
</td></tr></table><br></tt></dd>
</dl>
Other XSD Schema types such as <tt>gYearMonth</tt>, <tt>gYear</tt>, <tt>gMonthDay</tt>, <tt>gDay</tt>, <tt>xsd:gMonth</tt>, <tt>QName</tt>,
<tt>NOTATION</tt>, etc., can be encoded similarly using a <i><b>typedef</b></i> declaration.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.1">
10.2.1</a>&nbsp;&nbsp;<font color="#0000FF">How to Use Multiple C/C++ Types for a Single Primitive XSD Type</font></h4>
<div class="p"><!----></div>
Trailing underscores (see Section&nbsp;<a href="#sec:idtrans">9.3</a>) can be used in the type
name in a <i><b>typedef</b></i> to enable the declaration of multiple storage formats
for a single XML Schema type. For example, one part of a C/C++ application's
data structure may use plain strings while another part may use wide character
strings. To enable this simultaneous use, declare:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;wchar_t *xsd__string_;
</td></tr></table><br></i>
Now, the <i>xsd__string</i> and <i>xsd__string_</i> types will both be encoded
and decoded as XML string types and the use of trailing underscores allows
multiple declarations for a single XML Schema type.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.2">
10.2.2</a>&nbsp;&nbsp;<font color="#0000FF">How to use Wrapper Classes to Specify Polymorphic Primitive Types</font></h4><a name="sec:primclass">
</a>
<div class="p"><!----></div>
SOAP 1.1 supports polymorphic types, because XSD Schema types form a hierarchy.
The root of the hierarchy is called <tt>xsd:anyType</tt> (<tt>xsd:ur-type</tt> in the
older 1999 schema). So, for example, an array of <tt>xsd:anyType</tt> in SOAP may
actually contain any mix of element types that are the derived types of the
root type. The use of polymorphic types is indicated by the WSDL and schema
descriptions of a Web service and can therefore be predicted/expected for each
particular case.
<div class="p"><!----></div>
On the one hand, the <i><b>typedef</b></i> construct provides a convenient way to
associate C/C++ types with XML Schema types and makes it easy to incorporate
these types in a (legacy) C/C++ application. However, on the other hand the
<i><b>typedef</b></i> declarations cannot be used to support polymorphic XML Schema
types. Most SOAP clients and services do not use polymorphic types. In case
they do, the primitive polymorphic types can be declared as a hierarchy of C++
<i><b>class</b></i>es that can be used simultaneously with the <i><b>typedef</b></i>
declarations.
<div class="p"><!----></div>
The general form of a primitive type declaration that is derived from a super type is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__type_name: <font size="+1"><span class="roman">[</span></font><b>public</b>&nbsp;xsd__super_type_name<font size="+1"><span class="roman">]</span></font> <br />
{ <b>public</b>: <u><span class="roman">Type</span></u> __item; <br />
&nbsp;&nbsp;&nbsp;<font size="+1"><span class="roman">[</span></font><b>public</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>private</b><font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>protected</b>:<font size="+1"><span class="roman">]</span></font> <br />
&nbsp;&nbsp;&nbsp;method1; <br />
&nbsp;&nbsp;&nbsp;method2; <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
where <u><span class="roman">Type</span></u> is a primitive C type. The <i>__item</i> field MUST be the first
field in this wrapper class.
<div class="p"><!----></div>
For example, the XML Schema type hierarchy can be copied to C++ with the following declarations:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__anyType { }; <br />
<b>class</b>&nbsp;xsd__anySimpleType: <b>public</b>&nbsp;xsd__anyType { }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__anyURI; <br />
<b>class</b>&nbsp;xsd__anyURI_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__anyURI __item; }; <br />
<b>typedef</b>&nbsp;<b>bool</b>&nbsp;xsd__boolean; <br />
<b>class</b>&nbsp;xsd__boolean_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__boolean __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__date; <br />
<b>class</b>&nbsp;xsd__date_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__date __item; }; <br />
<b>typedef</b>&nbsp;time_t xsd__dateTime; <br />
<b>class</b>&nbsp;xsd__dateTime_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__dateTime __item; }; <br />
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__double; <br />
<b>class</b>&nbsp;xsd__double_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__double __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__duration; <br />
<b>class</b>&nbsp;xsd__duration_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__duration __item; }; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>class</b>&nbsp;xsd__float_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__float __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__time; <br />
<b>class</b>&nbsp;xsd__time_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__time __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__decimal; <br />
<b>class</b>&nbsp;xsd__decimal_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__decimal __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__integer; <br />
<b>class</b>&nbsp;xsd__integer_: <b>public</b>&nbsp;xsd__decimal_ { <b>public</b>: xsd__integer __item; }; <br />
<b>typedef</b>&nbsp;LONG64 xsd__long; <br />
<b>class</b>&nbsp;xsd__long_: <b>public</b>&nbsp;xsd__integer_ { <b>public</b>: xsd__long __item; }; <br />
<b>typedef</b>&nbsp;<b>long</b>&nbsp;xsd__int; <br />
<b>class</b>&nbsp;xsd__int_: <b>public</b>&nbsp;xsd__long_ { <b>public</b>: xsd__int __item; }; <br />
<b>typedef</b>&nbsp;<b>short</b>&nbsp;xsd__short; <br />
<b>class</b>&nbsp;xsd__short_: <b>public</b>&nbsp;xsd__int_ { <b>public</b>: xsd__short __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;xsd__byte; <br />
<b>class</b>&nbsp;xsd__byte_: <b>public</b>&nbsp;xsd__short_ { <b>public</b>: xsd__byte __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__nonPositiveInteger; <br />
<b>class</b>&nbsp;xsd__nonPositiveInteger_: <b>public</b>&nbsp;xsd__integer_ { <b>public</b>: xsd__nonPositiveInteger __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__negativeInteger; <br />
<b>class</b>&nbsp;xsd__negativeInteger_: <b>public</b>&nbsp;xsd__nonPositiveInteger_ { <b>public</b>: xsd__negativeInteger __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__nonNegativeInteger; <br />
<b>class</b>&nbsp;xsd__nonNegativeInteger_: <b>public</b>&nbsp;xsd__integer_ { <b>public</b>: xsd__nonNegativeInteger __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__positiveInteger; <br />
<b>class</b>&nbsp;xsd__positiveInteger_: <b>public</b>&nbsp;xsd__nonNegativeInteger_ { <b>public</b>: xsd__positiveInteger __item; }; <br />
<b>typedef</b>&nbsp;ULONG64 xsd__unsignedLong; <br />
<b>class</b>&nbsp;xsd__unsignedLong_: <b>public</b>&nbsp;xsd__nonNegativeInteger_ { <b>public</b>: xsd__unsignedLong __item; }; <br />
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;xsd__unsignedInt; <br />
<b>class</b>&nbsp;xsd__unsignedInt_: <b>public</b>&nbsp;xsd__unsginedLong_ { <b>public</b>: xsd__unsignedInt __item; }; <br />
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>short</b>&nbsp;xsd__unsignedShort; <br />
<b>class</b>&nbsp;xsd__unsignedShort_: <b>public</b>&nbsp;xsd__unsignedInt_ { <b>public</b>: xsd__unsignedShort __item; }; <br />
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;xsd__unsignedByte; <br />
<b>class</b>&nbsp;xsd__unsignedByte_: <b>public</b>&nbsp;xsd__unsignedShort_ { <b>public</b>: xsd__unsignedByte __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>class</b>&nbsp;xsd__string_: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: xsd__string __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__normalizedString; <br />
<b>class</b>&nbsp;xsd__normalizedString_: <b>public</b>&nbsp;xsd__string_ { <b>public</b>: xsd__normalizedString __item; }; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__token; <br />
<b>class</b>&nbsp;xsd__token_: <b>public</b>&nbsp;xsd__normalizedString_ { <b>public</b>: xsd__token __item; }; <br />
</td></tr></table><br></i>
Note the use of the trailing underscores for the <i><b>class</b></i> names to distinguish the <i><b>typedef</b></i> type names from the
<i><b>class</b></i> names. Only the most frequently used built-in schema types are shown.
It is also allowed to include the <i>xsd:base64Binary</i> and <i>xsd:hexBinary</i> types in the hierarchy:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__base64Binary: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: <b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <b>int</b>&nbsp;__size; }; <br />
<b>class</b>&nbsp;xsd__hexBinary: <b>public</b>&nbsp;xsd__anySimpleType { <b>public</b>: <b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <b>int</b>&nbsp;__size; };
</td></tr></table><br></i>
See Sections&nbsp;<a href="#sec:base64binary">10.11</a> and&nbsp;<a href="#sec:hexbinary">10.12</a>.
<div class="p"><!----></div>
Methods are allowed to be added to the classes above, such as constructors and getter/setter methods, see Section&nbsp;<a href="#sec:gettersetter">10.5.4</a>.
<div class="p"><!----></div>
Wrapper structs are supported as well, similar to wrapper classes. But they cannot be used
to implement polymorphism. Rather, the wrapper structs facilitate the use of XML attributes
with a primitive typed object, see&nbsp;<a href="#sec:attributes">10.5.7</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.3">
10.2.3</a>&nbsp;&nbsp;<font color="#0000FF">XSD Schema Type Decoding Rules</font></h4>
<div class="p"><!----></div>
The decoding rules for the primitive C and C++ data types is given in the table below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Type</b></font> </td><td><font color="#FF0000"><b>Allows Decoding of</b></font> </td><td><font color="#FF0000"><b>Precision Lost?</b></font> </td></tr>
<tr><td><i><b>bool</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>boolean</tt> </td><td>no </td></tr>
<tr><td><i><b>char</b>*</i> (C string) </td><td>any type, see&nbsp;<a href="#sec:smart">10.2.5</a> </td><td>no </td></tr>
<tr><td><i>wchar_t *</i> (wide string) </td><td>any type, see&nbsp;<a href="#sec:smart">10.2.5</a> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>double</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>double</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>float</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>long</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>int</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>decimal</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>integer</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>positiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>negativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonPositiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonNegativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td></tr>
<tr><td><i><b>float</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>float</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>long</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>int</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>decimal</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>integer</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>positiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>negativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonPositiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonNegativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td></tr>
<tr><td><i><b>long</b>&nbsp;<b>long</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>long</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>int</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>integer</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>positiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>negativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonPositiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonNegativeInteger</tt> </td><td>possibly </td></tr></table>
</td></tr></table><br></span>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Type</b></font> </td><td><font color="#FF0000"><b>Allows Decoding of</b></font> </td><td><font color="#FF0000"><b>Precision Lost?</b></font> </td></tr>
<tr><td><i><b>long</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>long</tt> </td><td>possibly, if <i><b>long</b></i> is 32 bit </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>int</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>int</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>int</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>short</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>short</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>char</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>byte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>possibly </td></tr>
<tr><td></td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>positiveInteger</tt> </td><td>possibly </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>nonNegativeInteger</tt> </td><td>possibly </td></tr>
<tr><td></td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>long</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedLong</tt> </td><td>possibly, if <i><b>long</b></i> is 32 bit </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>int</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedInt</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>short</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedShort</tt> </td><td>no </td></tr>
<tr><td></td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i><b>unsigned</b>&nbsp;<b>char</b></i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>unsignedByte</tt> </td><td>no </td></tr>
<tr><td></td></tr>
<tr><td><i>time_t</i> </td><td><tt><font size="+1"><span class="roman">[</span></font>xsd:<font size="+1"><span class="roman">]</span></font>dateTime</tt> </td><td>no(?) </td></tr>
<tr><td></td></tr></table>
</td></tr></table><br></span>
Due to limitations in representation of certain primitive C++ types, a possible loss of accuracy may occur with the decoding of certain XSD Schema types as is indicated in the table. The table does not indicate the possible loss of precision of floating point values due to the textual representation of floating point values in SOAP.
<div class="p"><!----></div>
All explicitly declared XSD Schema encoded primitive types adhere to the same decoding rules. For example, the following declaration:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b>&nbsp;xsd__nonNegativeInteger;
</td></tr></table><br></i>
enables the encoding and decoding of <tt>xsd:nonNegativeInteger</tt> XSD Schema types (although decoding takes place with a possible
loss of precision).
The declaration also allows decoding of <tt>xsd:positiveInteger</tt> XSD Schema types, because of the storage as a <i><b>unsigned</b>&nbsp;<b>long</b>&nbsp;<b>long</b></i> data type.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.4">
10.2.4</a>&nbsp;&nbsp;<font color="#0000FF">Multi-Reference Strings</font></h4>
<div class="p"><!----></div>
If more than one <i><b>char</b></i> pointer points to the same string, the string is encoded as a multi-reference value.
Consider for example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>char</b>&nbsp;*s = "hello", *t = s;
</td></tr></table><br></i>
The <i>s</i> and <i>t</i> variables are assigned the same string, and when serialized, <i>t</i> refers to the content of <i>s</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;string id="123" xsi:type="string"&#62;hello&lt;/string&#62; <br />
... <br />
&lt;string href="#123"/&#62;
</td></tr></table><br></tt>
The example assumed that <i>s</i> and <i>t</i> are encoded as independent elements.
<div class="p"><!----></div>
Note: the use of <i><b>typedef</b></i> to declare a string type such as <i>xsd__string</i> will not affect the multi-reference string
encoding. However, strings declared with different <i><b>typedef</b></i>s will never be considered multi-reference even when they point
to the same string. For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__anyURI; <br />
xsd__anyURI *s = "http://www.myservice.com"; <br />
xsd__string *t = s;
</td></tr></table><br></i>
The variables <i>s</i> and <i>t</i> point to the same string, but since they are considered different types their content will not
be shared in the SOAP payload through a multi-referenced string.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.5">
10.2.5</a>&nbsp;&nbsp;<font color="#0000FF">"Smart String" Mixed-Content Decoding</font></h4><a name="sec:smart">
</a>
<div class="p"><!----></div>
The implementation of string decoding in gSOAP allows for mixed content decoding. If the SOAP payload contains a complex data type in place of
a string, the complex data type is decoded in the string as plain XML text.
<div class="p"><!----></div>
For example, suppose the <i>getInfo</i> remote method returns some detailed information. The remote method is declared as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of header file "getInfo.h": <br />
getInfo(<b>char</b>&nbsp;*detail);
</td></tr></table><br></i>
The proxy of the remote method is used by a client to request a piece of information and the service responds with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
HTTP/1.1 200 OK <br />
Content-Type: text/xml <br />
Content-Length: nnn <br />
<br />
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&lt;SOAP-ENV:Body&#62; <br />
&lt;getInfoResponse&#62; <br />
&lt;detail&#62; <br />
&lt;picture&#62;Mona Lisa by &lt;i&#62;Leonardo da Vinci&lt;/i&#62;&lt;/picture&#62; <br />
&lt;/detail&#62; <br />
&lt;/getInfoResponse&#62; <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
As a result of the mixed content decoding, the <i>detail</i> string contains "<tt>&lt;picture&#62;Mona Lisa by &lt;i&#62;Leonardo da Vinci&lt;/i&#62;&lt;/picture&#62;</tt>".
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.6">
10.2.6</a>&nbsp;&nbsp;<font color="#0000FF">STL Strings</font></h4><a name="sec:strings">
</a>
<div class="p"><!----></div>
gSOAP supports STL strings <i>std::string</i> and <i>std::wstring</i>.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;std::string xsd__string; <br />
<b>class</b>&nbsp;ns__myClass <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;xsd__string s; // serialized with xsi:type="xsd:string" <br />
&nbsp;&nbsp;&nbsp;std::string t; // serialized without xsi:type <br />
... <br />
};
</td></tr></table><br></i>
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution:</b></font> Please avoid mixing <i>std::string</i> and C strings (<i><b>char</b>*</i>) in the header file when using SOAP 1.1 encoding. The problem is that multi-referenced strings in SOAP encoded messages cannot be assigned simultaneously to a <i>std::string</i> and a <i><b>char</b>*</i> string.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.7">
10.2.7</a>&nbsp;&nbsp;<font color="#0000FF">Changing the Encoding Precision of <b>float</b>&nbsp;and <b>double</b>&nbsp;Types</font></h4>
<div class="p"><!----></div>
The <i>double</i> encoding format is by default set to "<i>%.18G</i>" (see a manual on <i>printf</i> text formatting in C),
i.e.&nbsp;at most 18 digits of precision to limit a loss in accuracy.
The <i>float</i> encoding format is by default "<i>%.9G</i>", i.e.&nbsp;at most 9 digits of precision.
<div class="p"><!----></div>
The encoding format of a double type can be set by assigning a format string to <i>soap.double_format</i>, where <i>soap</i> is a
variable that contains the
current runtime environment. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); // sets double_format = "%.18G" <br />
soap.double_format = "%e"; // redefine
</td></tr></table><br></i>
which causes all doubles to be encoded in scientific notation.
Likewise, the encoding format of a float type can be set by assigning a format string to the static <i>soap_float_format</i> string variable. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); // sets float_format = "%.9G" <br />
soap.float_format = "%.4f"; // redefine
</td></tr></table><br></i>
which causes all floats to be encoded with four digits precision.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: The format strings are not automatically reset before or after SOAP communications. An error in the format string may result in the incorrect encoding of floating point values.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.2.8">
10.2.8</a>&nbsp;&nbsp;<font color="#0000FF">INF, -INF, and NaN Values of <b>float</b>&nbsp;and <b>double</b>&nbsp;Types</font></h4>
<div class="p"><!----></div>
The gSOAP runtime <i>stdsoap2.cpp</i> and header file <i>stdsoap2.h</i> support the marshalling of IEEE INF, -INF, and NaN
representations. Under certain circumstances this may break if the hardware and/or C/C++ compiler does not support these
representations.
To remove the representations, remove the inclusion of the <i> &lt; math.h &gt; </i> header file from the <i>stdsoap2.h</i> file.
You can control the representations as well, which are defined by the macros:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define FLT_NAN <br />
#define FLT_PINFTY <br />
#define FLT_NINFTY <br />
#define DBL_NAN <br />
#define DBL_PINFTY <br />
#define DBL_NINFTY
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc10.3">
10.3</a>&nbsp;&nbsp;<font color="#0000FF">Enumeration Serialization</font></h3><a name="sec:enum">
</a>
<div class="p"><!----></div>
Enumerations are generally useful for the declaration of named integer-valued constants, also called enumeration constants.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.1">
10.3.1</a>&nbsp;&nbsp;<font color="#0000FF">Serialization of Symbolic Enumeration Constants</font></h4>
<div class="p"><!----></div>
The gSOAP stub and skeleton compiler encodes the constants of enumeration-typed variables in symbolic form using the names of the constants when possible to comply to SOAP's enumeration encoding style. Consider for example the following enumeration of weekdays:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;weekday {Mon, Tue, Wed, Thu, Fri, Sat, Sun};
</td></tr></table><br></i>
The enumeration-constant <i>Mon</i>, for example, is encoded as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;weekday xsi:type="weekday"&#62;Mon&lt;/weekday&#62;
</td></tr></table><br></tt>
The value of the <tt>xsi:type</tt> attribute is the enumeration-type identifier's name. If the element is independent as in the example above, the element name is the enumeration-type identifier's name.
<div class="p"><!----></div>
The encoding of complex types such as enumerations requires a reference to an XML Schema through the use of a namespace prefix. The namespace prefix can be specified as part of the enumeration-type identifier's name, with the usual namespace prefix conventions for identifiers. This can be used to explicitly specify the encoding style. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__weekday {Mon, Tue, Wed, Thu, Fri, Sat, Sun};
</td></tr></table><br></i>
The enumeration-constant <i>Sat</i>, for example, is encoded as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns1:weekday xsi:type="ns1:weekday"&#62;Sat&lt;/ns1:weekday&#62;
</td></tr></table><br></tt>
The corresponding XML Schema for this enumeration data type would be:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:element name="weekday" type="tns:weekday"/&#62; <br />
&lt;xsd:simpleType name="weekday"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;xsd:restriction base="xsd:string"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Mon"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Tue"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Wed"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Thu"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Fri"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Sat"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsd:enumeration value="Sun"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/xsd:restriction&#62; <br />
&lt;/xsd:simpleType&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.2">
10.3.2</a>&nbsp;&nbsp;<font color="#0000FF">Encoding of Enumeration Constants</font></h4>
<div class="p"><!----></div>
If the value of an enumeration-typed variable has no corresponding named constant, the value is encoded as a signed integer literal. For example, the following declaration of a <i>workday</i> enumeration type lacks named constants for Saturday and Sunday:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__workday {Mon, Tue, Wed, Thu, Fri};
</td></tr></table><br></i>
If the constant <i>5</i> (Saturday) or <i>6</i> (Sunday) is assigned to a variable of the <i>workday</i> enumeration type, the variable will be encoded with the integer literals <tt>5</tt> and <tt>6</tt>, respectively. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns1:workday xsi:type="ns1:workday"&#62;5&lt;/ns1:workday&#62;
</td></tr></table><br></tt>
Since this is legal in C++ and SOAP allows enumeration constants to be integer literals, this method ensures that non-symbolic
enumeration constants are correctly communicated to another party if the other party accepts literal enumeration constants (as
with the gSOAP stub and skeleton compiler).
<div class="p"><!----></div>
Both symbolic and literal enumeration constants can be decoded.
<div class="p"><!----></div>
To enforce the literal enumeration constant encoding and to get the literal constants in the WSDL file, use the following trick:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__nums { _1 = 1, _2 = 2, _3 = 3 };
</td></tr></table><br></i>
The difference with an enumeration type without a list of values and the enumeration type above is that the enumeration constants
will appear in the WSDL service description.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.3">
10.3.3</a>&nbsp;&nbsp;<font color="#0000FF">Initialized Enumeration Constants</font></h4>
<div class="p"><!----></div>
The gSOAP compiler supports the initialization of enumeration constants, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__relation {LESS = -1, EQUAL = 0, GREATER = 1};
</td></tr></table><br></i>
The symbolic names <tt>LESS</tt>, <tt>EQUAL</tt>, and <tt>GREATER</tt> will appear in the SOAP payload for the encoding of the <i>ns1__relation</i> enumeration values <i>-1</i>, <i>0</i>, and <i>1</i>, respectively.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.4">
10.3.4</a>&nbsp;&nbsp;<font color="#0000FF">How to "Reuse" Symbolic Enumeration Constants</font></h4>
<div class="p"><!----></div>
A well-known deficiency of C and C++ enumeration types is the lack of support for the reuse of symbolic names by multiple enumerations. That is, the names of all the symbolic constants defined by an enumeration cannot be reused by another enumeration. To force encoding of the same symbolic name by different enumerations, the identifier of the symbolic name can end in an underscore (<i>_</i>) or any number of underscores to distinguish it from other symbolic names in C++. This guarantees that the SOAP encoding will use the same name, while the symbolic names can be distinguished in C++. Effectively, the underscores are removed from a symbolic name prior to encoding.
<div class="p"><!----></div>
Consider for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__workday {Mon, Tue, Wed, Thu, Fri}; <br />
<b>enum</b>&nbsp;ns1__weekday {Mon_, Tue_, Wed_, Thu_, Fri_, Sat_, Sun_};
</td></tr></table><br></i>
which will result in the encoding of the constants of <i>enum ns1__weekday</i> without the underscore, for example as <tt>Mon</tt>.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: The following declaration:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns1__workday {Mon, Tue, Wed, Thu, Fri}; <br />
<b>enum</b>&nbsp;ns1__weekday {Sat = 5, Sun = 6};
</td></tr></table><br></i>
will not properly encode the <i>weekday</i> enumeration, because it lacks the named constants for <i>workday</i> in its enumeration list.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.5">
10.3.5</a>&nbsp;&nbsp;<font color="#0000FF">Boolean Enumeration Serialization for C</font></h4><a name="sec:boolean">
</a>
<div class="p"><!----></div>
When developing a C Web service application, the C++ <i>bool</i> type should not be used since it is not usually supported by the C compiler.
Instead, an enumeration type should be used to serialize true/false values as <tt>xsd:boolean</tt> Schema type enumeration values.
The <tt>xsd:boolean</tt> XML Schema type is defined as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;xsd__boolean {false_, true_};
</td></tr></table><br></i>
The value <i>false_</i>, for example, is encoded as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;xsd:boolean xsi:type="xsd:boolean"&#62;false&lt;/xsd:boolean&#62; <br />
</td></tr></table><br></tt>
Peculiar of the SOAP boolean type encoding is that it only defines the values <tt>0</tt> and <tt>1</tt>, while the built-in XML Schema boolean type also defines the <tt>false</tt> and <tt>true</tt> symbolic constants as valid values. The following example declaration of an enumeration type lacks named constants altogether to force encoding of the enumeration values as literal constants:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;SOAP_ENC__boolean {};
</td></tr></table><br></i>
The value <i>0</i>, for example, is encoded with an integer literal:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;SOAP-ENC:boolean xsi:type="SOAP-ENC:boolean"&#62;0&lt;SOAP-ENC:boolean&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h4><a name="tth_sEc10.3.6">
10.3.6</a>&nbsp;&nbsp;<font color="#0000FF">Bitmask Enumeration Serialization</font></h4>
<div class="p"><!----></div>
A bitmask is an enumeration of flags such as declared with C#'s [Flags] <i><b>enum</b></i> annotation.
gSOAP supports bitmask encoding and decoding for interoperability. However, bitmask types are not standardized with SOAP RPC.
<div class="p"><!----></div>
A special syntactic convention is used in the header file input to the gSOAP compiler to indicate the use of bitmasks with an
asterisk:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;* <i>name</i> { <i>enum-constant</i>, <i>enum-constant</i>, ... };
</td></tr></table><br></i>
The gSOAP compiler will encode the enumeration constants as flags, i.e. as a series of powers of 2 starting with 1.
The enumeration constants can be or-ed to form a bitvector (bitmask) which is encoded and decoded as a list of symbolic values
in SOAP.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;* ns__machineStatus { ON, BELT, VALVE, HATCH}; <br />
<b>int</b>&nbsp;ns__getMachineStatus(<b>char</b>&nbsp;*name, <b>char</b>&nbsp;*<b>enum</b>&nbsp;ns__machineStatus result);
</td></tr></table><br></i>
Note that the use of the <i><b>enum</b></i> does not require the asterisk, only the definition.
The gSOAP compiler generates the enumeration:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>enum</b>&nbsp;ns__machineStatus { ON=1, BELT=2, VALVE=4, HATCH=8};
</td></tr></table><br></i>
A remote method implementation in a Web service can return:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__getMachineStatus(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*name, <b>enum</b>&nbsp;ns__machineStatus result) <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;*result = BELT - HATCH; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc10.4">
10.4</a>&nbsp;&nbsp;<font color="#0000FF">Struct Serialization</font></h3><a name="sec:struct">
</a>
<div class="p"><!----></div>
A <i><b>struct</b></i> data type is encoded as an XML Schema complexType (SOAP-encoded compound data type) such that the
<i><b>struct</b></i> name forms the data type's element name and schema type and the
fields of the <i><b>struct</b></i> are the data type's accessors. This encoding is
identical to the <i><b>class</b></i> instance encoding without inheritance and method
declarations, see Section&nbsp;<a href="#sec:class">10.5</a> for further details. However, the
encoding and decoding of <i><b>struct</b></i>s is more efficient compared to
<i><b>class</b></i> instances due to the lack of inheritance and the requirement by
the serialization routines to check inheritance properties at run time.
<div class="p"><!----></div>
Certain type of fields of a <i><b>struct</b></i> can be (de)serialized as XML attributes.
See&nbsp;<a href="#sec:attributes">10.5.7</a> for more details.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.5">
10.5</a>&nbsp;&nbsp;<font color="#0000FF">Class Instance Serialization</font></h3><a name="sec:class">
</a>
<div class="p"><!----></div>
A <i><b>class</b></i> instance is serialized as an XML Schema complexType (SOAP-encoded compound data type) such that the
<i><b>class</b></i> name forms the data type's element name and schema type and the
data member fields are the data type's accessors. Only the data member fields
are encoded in the SOAP payload. Class methods are not encoded.
<div class="p"><!----></div>
The general form of a <i><b>class</b></i> declaration is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;<font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>class_name1 <font size="+1"><span class="roman">[</span></font>:<font size="+1"><span class="roman">[</span></font><b>public</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>private</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>protected</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font>namespace_prefix__<font size="+1"><span class="roman">]</span></font>class_name2<font size="+1"><span class="roman">]</span></font> <br />
{ <br />
&nbsp;&nbsp;&nbsp;<font size="+1"><span class="roman">[</span></font><b>public</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>private</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>protected</b>:<font size="+1"><span class="roman">]</span></font> <br />
&nbsp;&nbsp;&nbsp;field1; <br />
&nbsp;&nbsp;&nbsp;field2; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;<font size="+1"><span class="roman">[</span></font><b>public</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>private</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>protected</b>:<font size="+1"><span class="roman">]</span></font> <br />
&nbsp;&nbsp;&nbsp;method1; <br />
&nbsp;&nbsp;&nbsp;method2; <br />
&nbsp;&nbsp;&nbsp;... <br />
}; <br />
</td></tr></table><br></i>
where
<dl compact="compact">
<dt><b><span class="roman"><i>namespace_prefix__</i></b></dt>
<dd> is the optional namespace prefix of the compound data type (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>)</span></dd>
<dt><b><span class="roman"><i>class_name1</i></b></dt>
<dd> is the element name of the compound data type (see identifier translation rules&nbsp;<a href="#sec:idtrans">9.3</a>).</span></dd>
<dt><b><span class="roman"><i>class_name2</i></b></dt>
<dd> is an optional base class.</span></dd>
<dt><b><span class="roman"><i>field</i></b></dt>
<dd> is a field declaration (data member). A field MAY be declared <i><b>static</b></i> and <i><b>const</b></i> and MAY be initialized.</span></dd>
<dt><b><span class="roman"><i>method</i></b></dt>
<dd> is a method declaration. A method MAY be declared <i><b>virtual</b></i>, but abstract methods are not allowed. The method parameter declarations are REQUIRED to have parameter identifier names.</span></dd>
<dt><b><font size="+1"><span class="roman">[</span></font><b>public</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>private</b>:<font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font><b>protected</b>:<font size="+1"><span class="roman">]</span></font></b></dt>
<dd> are OPTIONAL. Only members with <i><b>public</b></i> acces permission can be serialized.</dd>
</dl>
A class name is REQUIRED to be unique and cannot have the same name as a
<i><b>struct</b></i>, <i><b>enum</b></i>, or remote method name specified in the header file
input to the gSOAP compiler. The reason is that remote method requests are
encoded similarly to class instances in SOAP and they are in principle
undistinguishable (the method parameters are encoded just as the fields of a
<i><b>class</b></i>).
<div class="p"><!----></div>
Only single inheritance is supported by the gSOAP compiler. Multiple
inheritance is not supported, because of the limitations of the SOAP protocol.
<div class="p"><!----></div>
If a constructor method is present, there MUST also be a constructor
declaration with empty parameter list.
<div class="p"><!----></div>
Classes should be declared "volatile" if you don't want gSOAP to add serialization methods to these classes, see Section&nbsp;<a href="#sec:volatile">18.4</a> for more details.
<div class="p"><!----></div>
Class templates are not supported by the gSOAP compiler, but you can use STL containers,
see Section&nbsp;<a href="#sec:templates">10.10.8</a>. You can also define your own
containers similar to STL containers.
<div class="p"><!----></div>
Certain fields of a <i><b>class</b></i> can be (de)serialized as XML attributes.
See&nbsp;<a href="#sec:attributes">10.5.7</a> for more details.
<div class="p"><!----></div>
Arrays may be embedded within a class (and struct) using a pointer field and
size information, see Section&nbsp;<a href="#sec:list">10.10.7</a>. This defines what is sometimes
referred to in SOAP as "generics".
<div class="p"><!----></div>
Void pointers may be used in a class (or struct), but you have to add a type
field so the gSOAP runtime can determine the type of object pointed to, see
Section&nbsp;<a href="#sec:void">10.8</a>.
<div class="p"><!----></div>
A <i><b>class</b></i> instance is encoded as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>class-name xsi:type="<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>class-name"&#62; <br />
&lt;basefield-name1 xsi:type="..."&#62;...&lt;/basefield-name1&#62; <br />
&lt;basefield-name2 xsi:type="..."&#62;...&lt;/basefield-name2&#62; <br />
... <br />
&lt;field-name1 xsi:type="..."&#62;...&lt;/field-name1&#62; <br />
&lt;field-name2 xsi:type="..."&#62;...&lt;/field-name2&#62; <br />
... <br />
&lt;/<font size="+1"><span class="roman">[</span></font>namespace-prefix:<font size="+1"><span class="roman">]</span></font>class-name&#62;
</td></tr></table><br></tt>
where the <tt>field-name</tt> accessors have element-name representations of the
class fields and the <tt>basefield-name</tt> accessors have element-name
representations of the base class fields. (The optional parts resulting from
the specification are shown enclosed in <font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">]</span></font>.)
<div class="p"><!----></div>
The decoding of a class instance allows any ordering of the accessors in the
SOAP payload. However, if a base class field name is identical to a derived
class field name because the field is overloaded, the base class field name
MUST precede the derived class field name in the SOAP payload for decoding.
gSOAP guarantees this, but interoperability with other SOAP implementations is
cannot be guaranteed.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.1">
10.5.1</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4>
<div class="p"><!----></div>
The following example declares a base class <i>ns__Object</i> and a derived class <i>ns__Shape</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "shape.h": <br />
<b>class</b>&nbsp;ns__Object <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
}; <br />
<b>class</b>&nbsp;ns__Shape : <b>public</b>&nbsp;ns__Object <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;sides; <br />
&nbsp;&nbsp;&nbsp;<b>enum</b>&nbsp;ns__Color {Red, Green, Blue} color; <br />
&nbsp;&nbsp;&nbsp;ns__Shape(); <br />
&nbsp;&nbsp;&nbsp;ns__Shape(<b>int</b>&nbsp;sides, <b>enum</b>&nbsp;ns__Green color); <br />
&nbsp;&nbsp;&nbsp;~ns__Shape(); <br />
};
</td></tr></table><br></i>
The implementation of the methods of <i><b>class</b>&nbsp;ns__Shape</i> must not be part of the header file and need to be defined elsewhere.
<div class="p"><!----></div>
An instance of <i><b>class</b>&nbsp;ns__Shape</i> with name Triangle, 3 sides, and color Green is encoded as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:Shape xsi:type="ns:Shape"&#62; <br />
&lt;name xsi:type="string"&#62;Triangle&lt;/name&#62; <br />
&lt;sides xsi:type="int"&#62;3&lt;/sides&#62; <br />
&lt;color xsi:type="ns:Color"&#62;Green&lt;/color&#62; <br />
&lt;/ns:shape&#62;
</td></tr></table><br></tt>
The namespace URI of the namespace prefix <tt>ns</tt> must be defined by a namespace mapping table, see Section&nbsp;<a href="#sec:nstable">9.4</a>.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.2">
10.5.2</a>&nbsp;&nbsp;<font color="#0000FF">Initialized <b>static</b>&nbsp;<b>const</b>&nbsp;Fields</font></h4>
<div class="p"><!----></div>
A data member field of a class declared as <i><b>static</b>&nbsp;<b>const</b></i> is initialized
with a constant value at compile time. This field is encoded in the
serialization process, but is not decoded in the deserialization process. For
example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "triangle.h": <br />
<b>class</b>&nbsp;ns__Triangle : <b>public</b>&nbsp;ns__Object <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;size; <br />
&nbsp;&nbsp;&nbsp;<b>static</b>&nbsp;<b>const</b>&nbsp;<b>int</b>&nbsp;sides = 3; <br />
};
</td></tr></table><br></i>
An instance of <i><b>class</b>&nbsp;ns__Triangle</i> is encoded in SOAP as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:Triangle xsi:type="ns:Triangle"&#62; <br />
&lt;name xsi:type="string"&#62;Triangle&lt;/name&#62; <br />
&lt;size xsi:type="int"&#62;15&lt;/size&#62; <br />
&lt;sides xsi:type="int"&#62;3&#62;/sides&#62; <br />
&lt;/ns:Triangle&#62;
</td></tr></table><br></tt>
Decoding will ignore the <i>sides</i> field's value.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: The current gSOAP implementation does not support encoding
<i><b>static</b>&nbsp;<b>const</b></i> fields, due to C++ compiler compatibility differences.
This feature may be provided the future.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.3">
10.5.3</a>&nbsp;&nbsp;<font color="#0000FF">Class Methods</font></h4>
<div class="p"><!----></div>
A <i><b>class</b></i> declaration in the header file input to the gSOAP compiler MAY
include method declarations. The method implementations MUST NOT be part of
the header file but are required to be defined in another C++ source that is
externally linked with the application. This convention is also used for the
constructors and destructors of the <i><b>class</b></i>.
<div class="p"><!----></div>
Dynamic binding is supported, so a method MAY be declared <i><b>virtual</b></i>.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.4">
10.5.4</a>&nbsp;&nbsp;<font color="#0000FF">Getter and Setter Methods</font></h4><a name="sec:gettersetter">
</a>
<div class="p"><!----></div>
Setter and getter methods are invoked at run time upon serialization and
deserialization of class instances, respectively. The use of setter and getter methods adds more flexibility to the serialization and deserialization process.
<div class="p"><!----></div>
A setter method is called in the serialization phase from the virtual
<i>soap_serialization</i> method generated by the gSOAP compiler. You can use
setter methods to process a class instance just before it is serialized. A
setter method can be used to convert application data, such as translating
transient application data into serializable data, for example. You can also
use setter methods to retrieve dynamic content and use it to update a class
instance right before serialization. Remember setters
as &#223;et to serialize" operations.
<div class="p"><!----></div>
Getter methods are invoked after deserialization of the instance. You can use
them to adjust the contents of class instances after all their members have been
deserialized. Getters can be used to convert deserialized members into
transient members and even invoke methods to process the deserialized data on
the fly.
<div class="p"><!----></div>
Getter and setter methods have the following signature:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<font size="+1"><span class="roman">[</span></font><b>virtual</b><font size="+1"><span class="roman">]</span></font> <b>int</b>&nbsp;get(<b>struct</b>&nbsp;soap *soap) <font size="+1"><span class="roman">[</span></font><b>const</b><font size="+1"><span class="roman">]</span></font>; <br />
<font size="+1"><span class="roman">[</span></font><b>virtual</b><font size="+1"><span class="roman">]</span></font> <b>int</b>&nbsp;set(<b>struct</b>&nbsp;soap *soap);
</td></tr></table><br></i>
The active soap struct will be passed to the <i>get</i> and <i>set</i> methods. The methods should return <i>SOAP_OK</i> when successful. A setter method should prepare the contents of the class instance for serialization. A getter method should process the instance after deserialization.
<div class="p"><!----></div>
Here is an example of a base64 binary class:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__base64Binary <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>char *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>__size; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;get(struct soap *soap); <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;set(struct soap *soap); <br />
};
</td></tr></table><br></i>
Suppose that the type and options members of the attachment should be set when
the class is about to be serialized. This can be accomplished with the
<i>set</i> method from the information provided by the <i>__ptr</i> to the data
and the soap struct passed to the <i>set</i> method (you can pass data via the
<i><b>void</b>*soap.user</i> field).
<div class="p"><!----></div>
The <i>get</i> method is invoked after the base64 data has been processed. You
can use it for post-processing purposes.
<div class="p"><!----></div>
Here is another example. It defines a primitive <i>update</i> type. The class is a wrapper for the <i>time_t</i> type, see Section&nbsp;<a href="#sec:primclass">10.2.2</a>. Therefore, elements of this type contain <tt>xsd:dateType</tt> data.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;update <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;time_t __item; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;set(<b>struct</b>&nbsp;soap *soap); <br />
};
</td></tr></table><br></i>
The setter method assigns the current time:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;update::set(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;this<tt>-&gt;</tt>__item = time(NULL); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
Therefore, serialization results in the inclusion of a time stamp in XML.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: a <i>get</i> method is invoked only when the XML element with its data
was completely parsed. The method is not invoked when the element is an <tt>xsi:nil</tt> element or has an
<tt>href</tt> attribute.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution:</b></font> The <i>soap_serialize</i> method of a class calls the setter (when
provided). However, the <i>soap_serialize</i> method is declared <i><b>const</b></i>
while the setter should be allowed to modify the contents of the class
instance. Therefore, the gSOAP-generated code recasts the instance and the
<i><b>const</b></i> is removed when invoking the setter.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.5">
10.5.5</a>&nbsp;&nbsp;<font color="#0000FF">Streaming XML with Getter and Setter Methods</font></h4><a name="sec:streaming">
</a>
<div class="p"><!----></div>
Getter methods enable streaming XML operations. A getter method is invoked
when the object is deserialized and the rest of the SOAP/XML message has not
been processed yet. For example, you can add a getter method to the SOAP Header
class to implement header processing logic that is activated as soon as the
SOAP Header is received. An example code is shown below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;h__Authentication <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;get(<b>struct</b>&nbsp;soap *soap); <br />
}; <br />
<b>class</b>&nbsp;SOAP_ENV__Header <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;h__Authentication *h__authentication; <br />
};
</td></tr></table><br></i>
The <i>Authentication</i> SOAP Header field is instantiated and decoded. After
decoding, the getter method is invoked, which can be used to check the <i>id</i>
before the rest of the SOAP message is processed.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.6">
10.5.6</a>&nbsp;&nbsp;<font color="#0000FF">Polymorphism, Derived Classes, and Dynamic Binding</font></h4><a name="sec:polymorph">
</a>
<div class="p"><!----></div>
Interoperability between client and service applications developed with gSOAP
is established even when clients and/or services use derived classes instead of
the base classes used in the declaration of the remote method parameters. A
client application MAY use pointers to instances of derived classes for the
input parameters of a remote method. If the service was compiled with a
declaration and implementation of the derived class, the remote method base
class input parameters are demarshalled and a derived class instance is created
instead of a base class instance. If the service did not include a declaration
of the derived class, the derived class fields are ignored and a base class
instance is created. Therefore, interoperability is guaranteed even when the
client sends an instance of a derived classes and when a service returns an
instance of a derived class.
<div class="p"><!----></div>
The following example declares Base and Derived classes and a remote method
that takes a pointer to a Base class instance and returns a Base class
instance:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "derived.h" <br />
<b>class</b>&nbsp;Base <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;Base(); <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(); <br />
}; <br />
<b>class</b>&nbsp;Derived : <b>public</b>&nbsp;Base <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;num; <br />
&nbsp;&nbsp;&nbsp;Derived(); <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(); <br />
}; <br />
<b>int</b>&nbsp;method(Base *in, <b>struct</b>&nbsp;methodResponse { Base *out; } &amp;result);
</td></tr></table><br></i>
This header file specification is processed by the gSOAP compiler to produce the stub and skeleton routines which are used to implement a client and service.
The pointer of the remote method is also allowed to point to Derived class instances and these instances will be marshalled as Derived class instances and send to a service, which is in accord to the usual semantics of parameter passing in C++ with dynamic binding.
<div class="p"><!----></div>
The Base and Derived class method implementations are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Method implementations of the Base and Derived classes: <br />
#include "soapH.h" <br />
... <br />
Base::Base() <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "created a Base class instance" &lt;&lt; endl; <br />
} <br />
Derived::Derived() <br />
{<br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "created a Derived class instance" &lt;&lt; endl; <br />
} <br />
Base::print() <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "print(): Base class instance " &lt;&lt; name &lt;&lt; endl; <br />
} <br />
Derived::print() <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "print(): Derived class instance " &lt;&lt; name &lt;&lt; " " &lt;&lt; num &lt;&lt; endl; <br />
}
</td></tr></table><br></i>
Below is an example <i>CLIENT</i> application that creates a Derived class instance that is passed as the input parameter of the remote method:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// CLIENT <br />
#include "soapH.h" <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;Derived obj1; <br />
&nbsp;&nbsp;&nbsp;Base *obj2; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;methodResponse r; <br />
&nbsp;&nbsp;&nbsp;obj1.name = "X"; <br />
&nbsp;&nbsp;&nbsp;obj1.num = 3; <br />
&nbsp;&nbsp;&nbsp;soap_call_method(&amp;soap, url, action, &amp;obj1, r); <br />
&nbsp;&nbsp;&nbsp;r.obj2<tt>-&gt;</tt>print(); <br />
} <br />
...
</td></tr></table><br></i>
The following example <i>SERVER1</i> application copies a class instance (Base or Derived class) from the input to the output parameter:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// SERVER1 <br />
#include "soapH.h" <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); <br />
} <br />
<b>int</b>&nbsp;method(<b>struct</b>&nbsp;soap *soap, Base *obj1, <b>struct</b>&nbsp;methodResponse &amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;obj1<tt>-&gt;</tt>print(); <br />
&nbsp;&nbsp;&nbsp;result.obj2 = obj1; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
...
</td></tr></table><br></i>
The following messages are produced by the <i>CLIENT</i> and <i>SERVER1</i> applications:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
CLIENT: created a Derived class instance <br />
SERVER1: created a Derived class instance <br />
SERVER1: print(): Derived class instance X 3 <br />
CLIENT: created a Derived class instance <br />
CLIENT: print(): Derived class instance X 3
</td></tr></table><br></span>
Which indicates that the derived class kept its identity when it passed through <i>SERVER1</i>. Note that instances are created both by the <i>CLIENT</i> and <i>SERVER1</i> by the demarshalling process.
<div class="p"><!----></div>
Now suppose a service application is developed that only accepts Base class instances. The header file is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "base.h": <br />
<b>class</b>&nbsp;Base <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;Base(); <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(); <br />
}; <br />
<b>int</b>&nbsp;method(Base *in, Base *out);
</td></tr></table><br></i>
This header file specification is processed by the gSOAP stub and skeleton compiler to produce skeleton routine which is used to implement a service (so the client will still use the derived classes).
<div class="p"><!----></div>
The method implementation of the Base class are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Method implementations of the Base class: <br />
#include "soapH.h" <br />
... <br />
Base::Base() <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "created a Base class instance" &lt;&lt; endl; <br />
} <br />
Base::print() <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; "print(): Base class instance " &lt;&lt; name &lt;&lt; endl; <br />
} <br />
</td></tr></table><br></i>
And the <i>SERVER2</i> application is that uses the Base class is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// SERVER2 <br />
#include "soapH.h" <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_serve(soap_new()); <br />
} <br />
<b>int</b>&nbsp;method(<b>struct</b>&nbsp;soap *soap, Base *obj1, <b>struct</b>&nbsp;methodResponse &amp;result) <br />
{ <br />
&nbsp;&nbsp;&nbsp;obj1<tt>-&gt;</tt>print(); <br />
&nbsp;&nbsp;&nbsp;result.obj2 = obj1; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
...
</td></tr></table><br></i>
Here are the messages produced by the <i>CLIENT</i> and <i>SERVER2</i> applications:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
CLIENT: created a Derived class instance <br />
SERVER2: created a Base class instance <br />
SERVER2: print(): Base class instance X <br />
CLIENT: created a Base class instance <br />
CLIENT: print(): Base class instance X
</td></tr></table><br></span>
In this example, the object was passed as a Derived class instance to <i>SERVER2</i>. Since <i>SERVER2</i> only implements the Base class, this object is converted to a Base class instance and send back to <i>CLIENT</i>.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.7">
10.5.7</a>&nbsp;&nbsp;<font color="#0000FF">XML Attributes</font></h4><a name="sec:attributes">
</a>
<div class="p"><!----></div>
The SOAP RPC/LIT and SOAP DOC/LIT encoding styles support XML attributes in
SOAP messages while SOAP RPC with "Section 5" encoding does not support XML
attributes other than the SOAP and XSD specific attributes. SOAP RPC "Section
5" encoding has advantages for cross-language interoperability and data
encodings such as graph serialization. However, RPC/LIT and DOC/LIT enables
direct exchange of XML documents, which may include encoded application data
structures. Language interoperability is compromised, because no mapping
between XML and the typical language data types is defined. The meaning of the
RPC/LIT and DOC/LIT XML content is Schema driven rather than
application/language driven.
<div class="p"><!----></div>
gSOAP supports XML attribute (de)serialization of members in structs and classes.
Attributes are primitive XSD types, such as strings, enumerations, boolean, and
numeric types. To declare an XML attribute in a struct/class, the qualifier
<i>@</i> is used with the type of the attribute. The type must be
primitive type (including enumerations and strings), which can be declared with or without
a <i><b>typedef</b></i> to associate a XSD type with the C/C+ type. For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>bool</b>&nbsp;*xsd__boolean; <br />
<b>enum</b>&nbsp;ns__state { _0, _1, _2 }; <br />
<b>struct</b>&nbsp;ns__myStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;@xsd__string ns__type; // encode as XML attribute 'ns:type' of type 'xsd:string' <br />
&nbsp;&nbsp;&nbsp;@xsd__boolean ns__flag = false; // encode as XML attribute 'ns:flag' of type 'xsd:boolean' <br />
&nbsp;&nbsp;&nbsp;@<b>enum</b>&nbsp;ns__state ns__state = _2; // encode as XML attribute 'ns:state' of type 'ns:state' <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__myStruct *next; <br />
};
</td></tr></table><br></i>
The <i>@</i> qualifier indicates XML attribute encoding for the
<i>ns__type</i>, <i>ns__flag</i>, and <i>ns__state</i> fields. Note that the
namespace prefix <i>ns</i> is used to distinguish these attributes from any
other attributes such as <tt>xsi:type</tt> (<tt>ns:type</tt> is not to be confused
with <tt>xsi:type</tt>).
<div class="p"><!----></div>
Default values can be associated with any field that has
a primitive type in a struct/class, as is illustrated in this example. The
default values are used when the receiving message does not contain the
corresponding values.
<div class="p"><!----></div>
String attributes are optional. Other type of attributes should be declared as pointers to make them optional:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__myStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;@<b>int</b>&nbsp;*a; // omitted when NULL
};
</td></tr></table><br></i>
Because a remote method request and response is essentially a struct, XML
attributes can also be associated with method requests and responses. For
example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__myMethod(@<b>char</b>&nbsp;*ns__name, ...);
</td></tr></table><br></i>
Attributes can also be attached to the dynamic arrays, binary types, and wrapper classes/structs of primitive
types. Wrapper classes are described in Section&nbsp;<a href="#sec:primclass">10.2.2</a>. For
example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__string <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*__item; <br />
&nbsp;&nbsp;&nbsp;@xsd__boolean flag; <br />
};
</td></tr></table><br></i>
and
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;@xsd__boolean flag; <br />
};
</td></tr></table><br></i>
The attribute declarations MUST follow the <i>__item</i>, <i>__ptr</i>, and <i>__size</i> fields
which define the characteristics of wrapper structs/classes and dynamic arrays.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: Do not use XML attributes with SOAP RPC encoding. You can only use attributes with RPC literal encoding.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.5.8">
10.5.8</a>&nbsp;&nbsp;<font color="#0000FF">QName Attributes and Elements</font></h4>
<div class="p"><!----></div>
gSOAP ensures the proper decoding of XSD QNames.
An element or attribute with type QName (Qualified Name) contains a namespace prefix and a local name.
You can declare a QName type as a <i><b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__QName</i>. Values of type QName
are internally handled as regular strings.
gSOAP takes care of the proper namespace prefix mappings when deserializing QName values.
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__QName; <br />
<b>struct</b>&nbsp;ns__myStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__QName elt = "ns:xyz"; // QName element with default value "ns:xyz" <br />
&nbsp;&nbsp;&nbsp;@xsd__QName att = "ns:abc"; // QName attribute with default value "ns:abc" <br />
};
</td></tr></table><br></i>
When the <i>elt</i> and <i>att</i> fields are serialized,
their string contents are just transmitted (which means that the application is responsible to
ensure proper formatting of the QName strings prior to transmission). When the
fields are deserialized however, gSOAP takes care mapping the qualifiers to the
appropriate namespace prefixes. Suppose that the inbound value
for the <i>elt</i> is <tt>x:def</tt>, where the namespace name associated with the
prefix <tt>x</tt> matches the namespace name of the prefix <tt>ns</tt> (as defined in
the namespace mapping table). Then, the value is automatically converted into <tt>ns:def</tt>.
If the namespace name is not in the table, then
<tt>x:def</tt> is converted to <i>&#220;RI":def</i> where <tt>&#220;RI"</tt> is the namespace
URI bound to <tt>x</tt> in the message received. This enables an application to
retrieve the namespace information, whether it is in the namespace mapping
table or not.
<div class="p"><!----></div>
Note: <i>QName</i> is a pre-defined typedef type and used by gSOAP to
(de)serialize SOAP Fault codes which are QName elements.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.6">
10.6</a>&nbsp;&nbsp;<font color="#0000FF">Union Serialization</font></h3><a name="sec:union">
</a>
<div class="p"><!----></div>
A <i><b>union</b></i> is only serialized if the <i><b>union</b></i> is used within a
<i><b>struct</b></i> or <i><b>class</b></i> declaration that includes a <i><b>int</b>&nbsp;__union</i>
field that acts as a <em>discriminant</em> or <em>selector</em> for the <i><b>union</b></i>
fields. The selector stores run-time usage information about the <i><b>union</b></i>
fields. That is, the selector is used to enumerate the <i><b>union</b></i> fields such
that the gSOAP engine is able to select the correct <i><b>union</b></i> field to
serialize.
<div class="p"><!----></div>
A <i><b>union</b></i> within a <i><b>struct</b></i> or <i><b>class</b></i> with a selector field
represents <tt>xs:choice</tt> within a Schema complexType component. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__PO <br />
{ ... }; <br />
<b>struct</b>&nbsp;ns__Invoice <br />
{ ... }; <br />
<b>union</b>&nbsp;ns__PO_or_Invoice <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__PO po; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__Invoice invoice; <br />
};
<b>struct</b>&nbsp;ns__composite <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__union; <br />
&nbsp;&nbsp;&nbsp;<b>union</b>&nbsp;ns__PO_or_Invoice value; <br />
};
</td></tr></table><br></i>
The <i><b>union</b>&nbsp;ns__PO_or_Invoice</i> is expanded as a <tt>xs:choice</tt>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;complexType name="composite&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;sequence&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="name" type="xsd:string"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;choice&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="po" type="ns:PO"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="invoice" type="ns:Invoice"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/choice&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/sequence&#62; <br />
&lt;/complexType&#62;
</td></tr></table><br></tt>
Therefore, the name of the <i><b>union</b></i> and field can be freely chosen.
However, the <i><b>union</b></i> name should be qualified (as shown in the example) to
ensure instances of XML Schemas with <tt>elementFormDefault="qualified"</tt> are
correctly serialized (<i>po</i> and <i>invoice</i> are <tt>ns:</tt> qualified).
<div class="p"><!----></div>
The <i><b>int</b>&nbsp;__union</i> field selector's values are determined by the
<i>soapcpp2</i> compiler. Each <i><b>union</b></i> field name has a selector value
formed by:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
SOAP_UNION_<i>union-name</i>_<i>field-name</i>
</td></tr></table><br></i>
These selector values enumerate the <i><b>union</b></i> fields starting with 1. The
value 0 can be assigned to omit the serialization of the <i><b>union</b></i>, but only
if explicitly allowed by validation rules, which requires <tt>minOccurs="0"</tt>
for the <tt>xs:choice</tt> as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__composite <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__union 0; // <tt>&lt;choice minOccurs="0&#187;</tt> <br />
&nbsp;&nbsp;&nbsp;<b>union</b>&nbsp;ns__PO_or_Invoice value; <br />
};
</td></tr></table><br></i>
This way we can treat the <i><b>union</b></i> as an optional data item by setting <i>__union=0</i>.
<div class="p"><!----></div>
The following example shows how the <i><b>struct</b>&nbsp;ns__composite</i> instance is
initialized for serialization:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__composite data; <br />
data.name = "..."; <br />
data.__union = SOAP_UNION_ns__PO_or_Invoice_po; // select PO <br />
data.value.po.number = ...; // populate the PO
</td></tr></table><br></i>
Note that failing to set the selector to a valid <i><b>union</b></i> field can lead to
a crash of the gSOAP serializer because it will attempt to serialize an invalid
<i><b>union</b></i> field.
<div class="p"><!----></div>
For deserialization of <i><b>union</b></i> types, the <i>__union</i> selector will be
ser to 0 (when permitted) by the gSOAP deserializer or set to one of the
<i><b>union</b></i> field selector values as determined by the XML payload.
<div class="p"><!----></div>
When more than one <i><b>union</b></i> is used in a <i><b>struct</b></i> or <i><b>class</b></i>, the
<i>__union</i> selectors must be renamed to avoid name clashes by using
suffixes as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__composite <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__union_value; // added suffix "_value" <br />
&nbsp;&nbsp;&nbsp;<b>union</b>&nbsp;ns__PO_or_Invoice value; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__union_data; // added suffix "_data" <br />
&nbsp;&nbsp;&nbsp;<b>union</b>&nbsp;ns__Email_or_Fax data; <br />
};
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc10.7">
10.7</a>&nbsp;&nbsp;<font color="#0000FF">Serializing Pointer Types</font></h3><a name="sec:pointer">
</a>
<div class="p"><!----></div>
The serialization of a pointer to a data type amounts to the serialization of
the data type in SOAP and the SOAP encoded representation of a pointer to the
data type is indistinguishable from the encoded representation of the data
type pointed to.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.7.1">
10.7.1</a>&nbsp;&nbsp;<font color="#0000FF">Multi-Referenced Data</font></h4>
<div class="p"><!----></div>
A data structure pointed to by more than one pointer is serialized as SOAP
multi-reference data. This means that the data will be serialized only once and
identified with a unique <tt>id</tt> attribute. The encoding of the pointers to
the shared data is done through the use of <tt>href</tt> attributes to refer to
the multi-reference data (also see Section&nbsp;<a href="#sec:flags">8.12</a> on options to
control the serialization of multi-reference data). Cyclic C/C++ data
structures are encoded with multi-reference SOAP encoding. Consider for
example the following a linked list data structure:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>struct</b>&nbsp;ns__list<br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__string value; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__list *next; <br />
};
</td></tr></table><br></i>
Suppose a cyclic linked list is created. The first node contains the value "<tt>abc</tt>" and points to a node with value
"<tt>def</tt>" which in turn points to the first node. This is encoded as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:list id="1" xsi:type="ns:list"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;value xsi:type="xsd:string"&#62;abc&lt;/value&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;next xsi:type="ns:list"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value xsi:type="xsd:string"&#62;def&lt;/value&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;next href="#1"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/next&#62; <br />
&lt;/ns:list&#62;
</td></tr></table><br></tt>
In case multi-referenced data is received that "does not fit in a pointer-based structure", the data is copied.
For example, the following two <i><b>struct</b></i>s are similar, except that the first uses pointer-based fields while the other uses
non-pointer-based fields:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>long</b>&nbsp;xsd__int; <br />
<b>struct</b>&nbsp;ns__record <br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__int *a; <br />
&nbsp;&nbsp;&nbsp;xsd__int *b; <br />
} P; <br />
<b>struct</b>&nbsp;ns__record<br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__int a; <br />
&nbsp;&nbsp;&nbsp;xsd__int b; <br />
} R; <br />
... <br />
&nbsp;&nbsp;&nbsp;P.a = &amp;n; <br />
&nbsp;&nbsp;&nbsp;P.b = &amp;n; <br />
...
</td></tr></table><br></i>
Since both <i>a</i> and <i>b</i> fields of <i>P</i> point to the same integer, the encoding of <i>P</i> is multi-reference:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:record xsi:type="ns:record"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;a href="#1"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;b href="#1"/&#62; <br />
&lt;/ns:record&#62; <br />
&lt;id id="1" xsi:type="xsd:int"&#62;123&lt;/id&#62;
</td></tr></table><br></tt>
Now, the decoding of the content in the <i>R</i> data structure that does not use pointers to integers results in a copy of each
multi-reference integer. Note that the two <i><b>struct</b></i>s resemble the same XML data type because the trailing underscore will be
ignored in XML encoding and decoding.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.7.2">
10.7.2</a>&nbsp;&nbsp;<font color="#0000FF">NULL Pointers and Nil Elements</font></h4>
<div class="p"><!----></div>
A <i>NULL</i> pointer is <b>not</b> serialized, unless the pointer itself is pointed to by another pointer (but see
Section&nbsp;<a href="#sec:flags">8.12</a> to control the serialization of NULLs).
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;X <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;*p; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;**q; <br />
}
</td></tr></table><br></i>
Suppose pointer <i>q</i> points to pointer <i>p</i> and suppose <i>p=NULL</i>.
In that case the <i>p</i> pointer is serialized as
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;... id="123" xsi:nil="true"/&#62;
</td></tr></table><br></tt>
and the serialization of <i>q</i> refers to <tt>href="#123"</tt>.
Note that SOAP 1.1 does not support
pointer to pointer types (!), so this encoding is specific to gSOAP. The pointer to pointer encoding is rarely used in codes
anyway. More common is a pointer to a data type such as a <i><b>struct</b></i> with pointer fields.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: When the deserializer encounters an XML element that has a <tt>xsi:nil="true"</tt> attribute but the corresponding C++ data is not a pointer or reference,
the deserializer will terminate with a <i>SOAP_NULL</i> fault when the <i>SOAP_XML_STRICT</i> flag is set.
The types section of a WSDL description contains information on the "nilability" of data.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.8">
10.8</a>&nbsp;&nbsp;<font color="#0000FF">Void Pointers</font></h3><a name="sec:void">
</a>
<div class="p"><!----></div>
In general, void pointers (<i><b>void</b>*</i>) cannot be (de)serialized because the
type of data referred to is untyped. To enable the (de)serialization of the
void pointers that are members of structs or classes, you can insert a
<i><b>int</b>&nbsp;__type</i> field right before the void pointer field. The <i><b>int</b>&nbsp;__
type</i> field contains run time information on the type of the data pointed to by
<i><b>void</b>*</i> member in a struct/class to enable the (de)serialization of this
data. The <i><b>int</b>&nbsp;__type</i> field is set to a <i>SOAP_TYPE_X</i> value, where <i>X</i> is the name of a type. gSOAP generates the <i>SOAP_TYPE_X</i> definitions in <i>soapH.h</i> and uses them internally to uniquely identify the type of each object.
The type naming conventions outlined in
Section&nbsp;<a href="#sec:serialize">7.5.1</a> are used to determine the type name for <i>X</i>.
<div class="p"><!----></div>
Here is an example to illustrate the (de)serialization of a <i><b>void</b>*</i> field in a struct:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;myStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__type; // the SOAP_TYPE pointed to by p <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;*p; <br />
};
</td></tr></table><br></i>
The <i>__type</i> integer can be set to 0 at run time to omit the serialization
of the void pointer field.
<div class="p"><!----></div>
The following example illustrates the initialization of <i>myStruct</i> with a
void pointer to an int:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;myStruct S; <br />
<b>int</b>&nbsp;n; <br />
S.p = &amp;n; <br />
S.__type = SOAP_TYPE_int; <br />
</td></tr></table><br></i>
The serialized output of <i>S</i> contains the integer.
<div class="p"><!----></div>
The deserializer for <i>myStruct</i> will automatically set the <i>__type</i>
field and void pointer to the deserialized data, provided that the XML content
for <i>p</i> carries the <tt>xsi:type</tt> attribute from which gSOAP can determine
the type.
<div class="p"><!----></div>
<font color="#FF0000"><b>Important</b></font>: when (de)serializing strings via a <i><b>void</b>*</i> field, the <i><b>void</b>*</i> pointer MUST directly point to the string value rather than indirectly as with all other types. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;myStruct S; <br />
S.p = (<b>void</b>*)"Hello"; <br />
S.__type = SOAP_TYPE_string; <br />
</td></tr></table><br></i>
This is the case for all string-based types, including types defined with <i><b>typedef</b>&nbsp;<b>char</b>*</i>.
<div class="p"><!----></div>
You may use an arbitrary suffix with the <i>__type</i> fields to handle
multiple void pointers in structs/classes. For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;myStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__typeOfp; // the SOAP_TYPE pointed to by p <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;*p; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__typeOfq; // the SOAP_TYPE pointed to by q <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;*q; <br />
};
</td></tr></table><br></i>
Because service method parameters are stored within structs, you can use
<i>__type</i> and <i><b>void</b>*</i> parameters to pass polymorphic arguments without
having to define a C++ class hierarchy (Section&nbsp;<a href="#sec:polymorph">10.5.6</a>). For
example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string; <br />
<b>typedef</b>&nbsp;<b>int</b>&nbsp;xsd__int; <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>enum</b>&nbsp;ns__status { on, off }; <br />
<b>struct</b>&nbsp;ns__widget { xsd__string name; xsd__int part; };
<b>int</b>&nbsp;ns__myMethod(<b>int</b>&nbsp;__type, <b>void</b>&nbsp;*data, <b>struct</b>&nbsp;ns__myMethodResponse { <b>int</b>&nbsp;__type; <b>void</b>&nbsp;*return_; } *out);
</td></tr></table><br></i>
This method has a polymorphic input parameter <i>data</i> and a polymorphic
output parameter <i>return_</i>. The <i>__type</i> parameters can be one of
<i>SOAP_TYPE_xsd__string</i>, <i>SOAP_TYPE_xsd__int</i>,
<i>SOAP_TYPE_xsd__float</i>, <i>SOAP_TYPE_ns__status</i>, or
<i>SOAP_TYPE_ns__widget</i>. The WSDL produced by the gSOAP compiler
declares the polymorphic parameters of type <tt>xsd:anyType</tt> which is "too
loose" and doesn't allow the gSOAP importer to handle the WSDL accurately.
Future gSOAP releases might replace <tt>xsd:anyType</tt> with a <tt>choice</tt>
schema type that limits the choice of types to the types declared in the
header file.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.9">
10.9</a>&nbsp;&nbsp;<font color="#0000FF">Fixed-Size Arrays</font></h3>
<div class="p"><!----></div>
Fixed size arrays are encoded as per SOAP 1.1 one-dimensional array types.
Multi-dimensional fixed size arrays are encoded by gSOAP as nested
one-dimensional arrays in SOAP. Encoding of fixed size arrays supports
partially transmitted and sparse array SOAP formats.
<div class="p"><!----></div>
The decoding of (multi-dimensional) fixed-size arrays supports the SOAP multi-dimensional array format as well as partially transmitted and sparse array formats.
<div class="p"><!----></div>
An example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of header file "fixed.h": <br />
<b>struct</b>&nbsp;Example <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;a[2][3]; <br />
};
</td></tr></table><br></i>
This specifies a fixed-size array part of the <i><b>struct</b>&nbsp;Example</i>. The encoding of array <i>a</i> is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;a xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="float[][2]"&#62; <br />
&lt;SOAP-ENC:Array xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="float[3]" <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;/SOAP-ENC:Array&#62; <br />
&lt;SOAP-ENC:Array xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="float[3]" <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;float xsi:type="float"&#62;...&lt;/float&#62; <br />
&lt;/SOAP-ENC:Array&#62; <br />
&lt;/a&#62;
</td></tr></table><br></tt>
<font color="#FF0000"><b>Caution</b></font>: Any decoded parts of a (multi-dimensional) array that do not "fit" in the fixed size array are ignored by the deserializer.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.10">
10.10</a>&nbsp;&nbsp;<font color="#0000FF">Dynamic Arrays</font></h3><a name="sec:dynarray">
</a>
<div class="p"><!----></div>
As the name suggests, dynamic arrays are much more flexible than fixed-size
arrays and dynamic arrays are better adaptable to the SOAP encoding and decoding
rules for arrays. In addition, a typical C application allocates a dynamic
array using <i>malloc</i>, assigns the location to a pointer variable, and
deallocates the array later with <i>free</i>. A typical C++ application
allocates a dynamic array using <i>new</i>, assigns the location to a pointer
variable, and deallocates the array later with <i>delete</i>. Such dynamic
allocations are flexible, but pose a problem for the serialization of data: how
does the array serializer know the length of the array to be serialized given
only a pointer to the sequence of elements? The application stores the size
information somewhere. This information is crucial for the array serializer and
has to be made explicitly known to the array serializer by packaging the
pointer and array size information within a <i><b>struct</b></i> or <i><b>class</b></i>.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.1">
10.10.1</a>&nbsp;&nbsp;<font color="#0000FF">SOAP Array Bounds Limits</font></h4>
<div class="p"><!----></div>
SOAP encoded arrays use the <tt>SOAP-ENC:Array</tt> type and the <tt>SOAP-ENC:arrayType</tt> attribute to define the array dimensionality and size. As a security measure to avoid denial of service attacks based on sending a huge array size value requiring the allocation of large chunks of memory, the total number of array elements set by the <tt>SOAP-ENC:arrayType</tt> attribute cannot exceed <i>SOAP_MAXARRAYSIZE</i>, which is set to 100,000 by default. This constant is defined in <i>stdsoap2.h</i>. This constant <b>only</b> affects multi-dimensional arrays and the dimensionality of the receiving array will be lost when the number of elements exceeds 100,000. One-dimensional arrays will be populated in sequential order as expected.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.2">
10.10.2</a>&nbsp;&nbsp;<font color="#0000FF">One-Dimensional Dynamic Arrays</font></h4>
<div class="p"><!----></div>
A special form of <i><b>struct</b></i> or <i><b>class</b></i> is used for one-dimensional
dynamic arrays that contains a pointer variable and a field that records the
number of elements the pointer points to in memory.
<div class="p"><!----></div>
The general form of the <i><b>struct</b></i> declaration for one-dimensional dynamic SOAP arrays is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;some_name <br />
{ <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type</span></u> *__ptr; // pointer to array <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; // number of elements pointed to <br />
&nbsp;&nbsp;&nbsp;<font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">[</span></font><b>static</b>&nbsp;<b>const</b><font size="+1"><span class="roman">]</span></font> <b>int</b>&nbsp;__offset <font size="+1"><span class="roman">[</span></font>= ...<font size="+1"><span class="roman">]</span></font>;<font size="+1"><span class="roman">]</span></font> // optional SOAP 1.1 array offset <br />
&nbsp;&nbsp;&nbsp;... // anything that follows here will be ignored <br />
};
</td></tr></table><br></i>
where <i><u><span class="roman">Type</span></u></i> MUST be a type associated with an XML Schema or MUST be a primitive type.
If these conditions are not met, a vector-like XML (de)serialization is used (see Section&nbsp;<a href="#sec:list">10.10.7</a>).
A primitive type can be used with or without a <i><b>typedef</b></i>.
If the array elements are structs or classes, then the <i>struct</i>/<i>class</i> type names should have a namespace prefix for schema
association, or they should be other (nested) dynamic arrays.
<div class="p"><!----></div>
An alternative to a <i><b>struct</b></i> is to use a <i><b>class</b></i> with optional methods that MUST appear after the <i>__ptr</i> and
<i>__size</i> fields:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;some_name <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type</span></u> *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<font size="+1"><span class="roman">[</span></font><font size="+1"><span class="roman">[</span></font><b>static</b>&nbsp;<b>const</b><font size="+1"><span class="roman">]</span></font> <b>int</b>&nbsp;__offset <font size="+1"><span class="roman">[</span></font>= ...<font size="+1"><span class="roman">]</span></font>;<font size="+1"><span class="roman">]</span></font> <br />
&nbsp;&nbsp;&nbsp;method1; <br />
&nbsp;&nbsp;&nbsp;method2; <br />
&nbsp;&nbsp;&nbsp;... // any fields that follow will be ignored <br />
};
</td></tr></table><br></i>
To encode the data type as an array, the name of the <i><b>struct</b></i> or
<i><b>class</b></i> SHOULD NOT have a namespace prefix, otherwise the data type will
be encoded and decoded as a generic vector, see Section&nbsp;<a href="#sec:list">10.10.7</a>.
<div class="p"><!----></div>
The deserializer of a dynamic array can decode partially transmitted and/or
SOAP sparse arrays, and even multi-dimensional arrays which will be collapsed
into a one-dimensional array with row-major ordering.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: SOAP 1.2 does not support partially transmitted arrays. So the <i>__offset</i> field of a dynamic array is ignored.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.3">
10.10.3</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4>
<div class="p"><!----></div>
The following example header file specifies the XMethods Service Listing service <i>getAllSOAPServices</i> remote method and an array of <i>SOAPService</i> data structures:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "listing.h": <br />
<b>class</b>&nbsp;ns3__SOAPService <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;ID; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*owner; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*description; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*homepageURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*endpoint; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*SOAPAction; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*methodNamespaceURI; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*serviceStatus; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*methodName; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*dateCreated; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*downloadURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*wsdlURL; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*instructions; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*contactEmail; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*serverImplementation; <br />
}; <br />
<b>class</b>&nbsp;ServiceArray <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;ns3__SOAPService *__ptr; // points to array elements <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; // number of elements pointed to <br />
&nbsp;&nbsp;&nbsp;ServiceArray(); <br />
&nbsp;&nbsp;&nbsp;~ServiceArray(); <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;print(); <br />
}; <br />
<b>int</b>&nbsp;ns__getAllSOAPServices(ServiceArray &amp;return_);
</td></tr></table><br></i>
An example client application:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h"
... <br />
// ServiceArray class method implementations: <br />
ServiceArray::ServiceArray() <br />
{ <br />
&nbsp;&nbsp;&nbsp;__ptr = NULL; <br />
&nbsp;&nbsp;&nbsp;__size = 0; <br />
} <br />
ServiceArray::~ServiceArray() <br />
{ // destruction handled by gSOAP <br />
} <br />
<b>void</b>&nbsp;ServiceArray::print() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(<b>int</b>&nbsp;i = 0; i &lt; __size; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout &lt;&lt; __ptr[i].name &lt;&lt; ": " &lt;&lt; __ptr[i].homepage &lt;&lt; endl; <br />
} <br />
... <br />
// Request a service listing and display results: <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;ServiceArray result; <br />
&nbsp;&nbsp;&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint = "www.xmethods.net:80/soap/servlet/rpcrouter"; <br />
&nbsp;&nbsp;&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;*action = "urn:xmethodsServicesManager#getAllSOAPServices"; <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__getAllSOAPServices(&amp;soap, endpoint, action, result); <br />
&nbsp;&nbsp;&nbsp;result.print(); <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); // dealloc class instances <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // dealloc deserialized data <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // cleanup and detach soap struct <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.4">
10.10.4</a>&nbsp;&nbsp;<font color="#0000FF">One-Dimensional Dynamic Arrays With Non-Zero Offset</font></h4>
<div class="p"><!----></div>
The declaration of a dynamic array as described in&nbsp;<a href="#sec:dynarray">10.10</a> MAY
include an <i><b>int</b>&nbsp;__offset</i> field. When set to an integer value, the
serializer of the dynamic array will use this field as the start index of the
array and the SOAP array offset attribute will be used in the SOAP payload.
Note that array offsets is a SOAP 1.1 specific feature which is not supported
in SOAP 1.2.
<div class="p"><!----></div>
For example, the following header file declares a mathematical <i>Vector</i>
class, which is a dynamic array of floating point values with an index that
starts at 1:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "vector.h": <br />
<b>typedef</b>&nbsp;<b>float</b>&nbsp;xsd__float; <br />
<b>class</b>&nbsp;Vector <br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__float *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset; <br />
&nbsp;&nbsp;&nbsp;Vector(); <br />
&nbsp;&nbsp;&nbsp;Vector(<b>int</b>&nbsp;n); <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&amp; <b>operator</b>[](<b>int</b>&nbsp;i); <br />
}
</td></tr></table><br></i>
The implementations of the <i>Vector</i> methods are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
Vector::Vector() <br />
{ <br />
&nbsp;&nbsp;&nbsp;__ptr = NULL; <br />
&nbsp;&nbsp;&nbsp;__size = 0; <br />
&nbsp;&nbsp;&nbsp;__offset = 1; <br />
} <br />
Vector::Vector(<b>int</b>&nbsp;n) <br />
{ <br />
&nbsp;&nbsp;&nbsp;__ptr = (<b>float</b>*)malloc(n*<b>sizeof</b>(<b>float</b>)); <br />
&nbsp;&nbsp;&nbsp;__size = n; <br />
&nbsp;&nbsp;&nbsp;__offset = 1; <br />
} <br />
Vector::~Vector() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(__ptr) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(__ptr); <br />
} <br />
<b>float</b>&amp; Vector::<b>operator</b>[](<b>int</b>&nbsp;i) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;__ptr[i-__offset]; <br />
}
</td></tr></table><br></i>
An example program fragment that serializes a vector of 3 elements:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
Vector v(3); <br />
v[1] = 1.0; <br />
v[2] = 2.0; <br />
v[3] = 3.0; <br />
soap_begin(&amp;soap); <br />
v.serialize(&amp;soap); <br />
v.put(<tt>"vec"</tt>); <br />
soap_end(&amp;soap);
</td></tr></table><br></i>
The output is a partially transmitted array:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;vec xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:float[4]" SOAP-ENC:offset="[1]"&#62; <br />
&lt;item xsi:type="xsd:float"&#62;1.0&lt;/item&#62; <br />
&lt;item xsi:type="xsd:float"&#62;2.0&lt;/item&#62; <br />
&lt;item xsi:type="xsd:float"&#62;3.0&lt;/item&#62; <br />
&lt;/vec&#62;
</td></tr></table><br></tt>
Note that the size of the encoded array is necessarily set to 4 and that the encoding omits the non-existent element at index 0.
<div class="p"><!----></div>
The decoding of a dynamic array with an <i>__offset</i> field is more efficient than decoding a dynamic array without an <i>__offset</i> field, because the <i>__offset</i> field will be assigned the value of the <tt>SOAP-ENC:offset</tt> attribute instead of padding the initial part of the array with default values.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.5">
10.10.5</a>&nbsp;&nbsp;<font color="#0000FF">Nested One-Dimensional Dynamic Arrays</font></h4><a name="sec:nested">
</a>
<div class="p"><!----></div>
One-dimensional dynamic arrays MAY be nested.
For example, using <i><b>class</b>&nbsp;Vector</i> declared in the previous section, <i><b>class</b>&nbsp;Matrix</i> is declared:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// Contents of file "matrix.h": <br />
<b>class</b>&nbsp;Matrix <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;Vector *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset; <br />
&nbsp;&nbsp;&nbsp;Matrix(); <br />
&nbsp;&nbsp;&nbsp;Matrix(<b>int</b>&nbsp;n, <b>int</b>&nbsp;m); <br />
&nbsp;&nbsp;&nbsp;~Matrix(); <br />
&nbsp;&nbsp;&nbsp;Vector&amp; <b>operator</b>[](<b>int</b>&nbsp;i); <br />
};
</td></tr></table><br></i>
The Matrix type is essentially an array of pointers to arrays which make up the rows of a matrix.
The encoding of the two-dimensional dynamic array in SOAP will be in nested form.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.6">
10.10.6</a>&nbsp;&nbsp;<font color="#0000FF">Multi-Dimensional Dynamic Arrays</font></h4>
<div class="p"><!----></div>
The general form of the <i><b>struct</b></i> declaration for K-dimensional (K &gt; 1) dynamic arrays is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;some_name <br />
{ <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type</span></u> *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size[K]; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset[K]; <br />
&nbsp;&nbsp;&nbsp;... // anything that follows here will be ignored <br />
};
</td></tr></table><br></i>
where <i><u><span class="roman">Type</span></u></i> MUST be a type associated with an XML Schema, which means that it must be a <i><b>typedef</b></i>ed type
in case of a primitive type, or a <i><b>struct</b></i>/<i><b>class</b></i> name with a namespace prefix for schema association, or another dynamic array. If these conditions are not met, a generic vector XML (de)serialization is used (see Section&nbsp;<a href="#sec:list">10.10.7</a>).
<div class="p"><!----></div>
An alternative is to use a <i><b>class</b></i> with optional methods:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;some_name <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type</span></u> *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size[K]; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset[K]; <br />
&nbsp;&nbsp;&nbsp;method1; <br />
&nbsp;&nbsp;&nbsp;method2; <br />
&nbsp;&nbsp;&nbsp;... // any fields that follow will be ignored <br />
};
</td></tr></table><br></i>
In the above, K is a constant denoting the number of dimensions of the multi-dimensional array.
<div class="p"><!----></div>
To encode the data type as an array, the name of the <i><b>struct</b></i> or <i><b>class</b></i> SHOULD NOT have a namespace prefix, otherwise
the data type will be encoded and decoded as a generic vector, see Section&nbsp;<a href="#sec:list">10.10.7</a>.
<div class="p"><!----></div>
The deserializer of a dynamic array can decode partially transmitted multi-dimensional arrays.
<div class="p"><!----></div>
For example, the following declaration specifies a matrix class:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>double</b>&nbsp;xsd__double; <br />
<b>class</b>&nbsp;Matrix <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;xsd__double *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size[2]; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset[2]; <br />
};
</td></tr></table><br></i>
In contrast to the matrix class of Section&nbsp;<a href="#sec:nested">10.10.5</a> that defined a matrix as an array of pointers to matrix rows, this
class has one pointer to a matrix stored in row-major order. The size of the matrix is determined by the <i>__size</i> field:
<i>__size[0]</i> holds the number of rows and <i>__size[1]</i> holds the number of columns of the matrix. Likewise, <i>__
offset[0]</i> is the row offset and <i>__offset[1]</i> is the columns offset.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.7">
10.10.7</a>&nbsp;&nbsp;<font color="#0000FF">Encoding XML Generics Containing Dynamic Arrays</font></h4><a name="sec:list">
</a>
<div class="p"><!----></div>
XML "generics" extend the concept of a struct by allowing repetitions of elements within the struct.
A simple generic is an array-like data structure with a repetition of one element.
To achieve this, declare a dynamic array as a <i><b>struct</b></i> or <i><b>class</b></i> with a name that is qualified with
a namespace prefix. SOAP arrays are declared without prefix.
<div class="p"><!----></div>
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__Map <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__Binding {<b>char</b>&nbsp;*key; <b>char</b>&nbsp;*val;} *__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
This declares a dynamic array, but the array will be serialized and deserialized as a generic with a list-like data structure. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;ns:Map xsi:type="ns:Map"&#62; <br />
&lt;ns:Binding xsi:type="ns:Binding"&#62; <br />
&lt;key&#62;Joe&lt;/key&#62; <br />
&lt;val&#62;555 77 1234&lt;/val&#62; <br />
&lt;/ns:Binding&#62; <br />
&lt;ns:Binding xsi:type="ns:Binding"&#62; <br />
&lt;key&#62;Susan&lt;/key&#62; <br />
&lt;val&#62;555 12 6725&lt;/val&#62; <br />
&lt;/ns:Binding&#62; <br />
&lt;ns:Binding xsi:type="ns:Binding"&#62; <br />
&lt;key&#62;Pete&lt;/key&#62; <br />
&lt;val&#62;555 99 4321&lt;/val&#62; <br />
&lt;/ns:Binding&#62; <br />
&lt;/ns:Map&#62;
</td></tr></table><br></tt>
Deserialization is less efficient compared to an array, because the size of the
list is not part of the SOAP encoding. Internal buffering is used by the
deserializer to collect the elements. When the end of the list is reached, the
buffered elements are copied to a newly allocated space on the heap for the
dynamic array.
<div class="p"><!----></div>
Multiple arrays can be used in a struct/class to support the concept of
generics. Each array results in a repetition of elements in the struct/class.
This is achieved with a <i><b>int</b>&nbsp;__size</i> field in the struct/class where the
next field (i.e.&nbsp;below the <i>__size</i> field) is a pointer type. The pointer
type is assumed to point to an array of values at run time. The <i>__size</i>
field holds the number of values at run time. Multiple arrays can be embedded
in a struct/class with <i>__size</i> fields that have a distinct names. To
make the <i>__size</i> fields distinct, you can end them with a unique name
suffix such as <i>__sizeOfstrings</i>, for example.
<div class="p"><!----></div>
The general convention for embedding arrays is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__SomeStruct <br />
{ <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size<u><span class="roman">name1</span></u>; // number of elements pointed to <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type1</span></u> *<u>field1</u>; // by this field <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size<u><span class="roman">name2</span></u>; // number of elements pointed to <br />
&nbsp;&nbsp;&nbsp;<u><span class="roman">Type2</span></u> *<u>field2</u>; // by this field <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
where <i><u><span class="roman">name1</span></u></i> and <i><u><span class="roman">name2</span></u></i> are identifiers used as a suffix to distinguish the <i>__
size</i> field. These names can be arbitrary and are not visible in XML.
<div class="p"><!----></div>
For example, the following struct has two embedded arrays:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__Contact <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*firstName; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*lastName; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__sizePhones; <br />
&nbsp;&nbsp;&nbsp;ULONG64 *phoneNumber; // array of phone numbers <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__sizeEmails; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;**emailAddress; // array of email addresses <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*socSecNumber; <br />
};
</td></tr></table><br></i>
The XML serialization of an example <i>ns__Contact</i> is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;mycontact xsi:type="ns:Contact"&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;firstName&#62;Joe&lt;/firstName&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;lastName&#62;Smith&lt;/lastName&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;phoneNumber&#62;5551112222&lt;/phoneNumber&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;phoneNumber&#62;5551234567&lt;/phoneNumber&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;phoneNumber&#62;5552348901&lt;/phoneNumber&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;emailAddress&#62;Joe.Smith@mail.com&lt;/emailAddress&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;emailAddress&#62;Joe@Smith.com&lt;/emailAddress&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;socSecNumber&#62;999999999&lt;/socSecNumber&#62; <br />
&lt;/mycontact&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.8">
10.10.8</a>&nbsp;&nbsp;<font color="#0000FF">STL Containers</font></h4><a name="sec:templates">
</a>
<div class="p"><!----></div>
gSOAP supports the STL containers <i>std::deque</i>, <i>std::list</i>,
<i>std::set</i>, and <i>std::vector</i>.
<div class="p"><!----></div>
STL containers can only be used within classes to declare members that contain
multiple values. This is somewhat similar to the embedding of arrays in
structs in C as explained in Section&nbsp;<a href="#sec:list">10.10.7</a>, but the STL container
approach is more flexible.
<div class="p"><!----></div>
You need to import <i>stldeque.h</i>, <i>stllist.h</i>, <i>stlset.h</i>, or
<i>stlvector.h</i> to enable <i>std::deque</i>, <i>std::list</i>, <i>std::set</i>,
and <i>std::vector</i> (de)serialization.
Here is an example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import "stlvector.h" <br />
<b>class</b>&nbsp;ns__myClass <br />
{ <b>public</b>: <br />
&nbsp;&nbsp;&nbsp;std::vector &lt; int &gt; *number; <br />
&nbsp;&nbsp;&nbsp;std::vector &lt; xsd__string &gt; *name; <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
The use of pointer members is not required but advised. The reason is that
interoperability with other SOAP toolkits may lead to copying of <i>ns__
myClass</i> instances at run time when (de)serializing multi-referenced data.
When a copy is made, certain parts of the containers will be shared between the
copies which could lead to disaster when the classes with their containers are
deallocated. Another way to avoid this is to declare class <i>ns__myClass</i>
within other data types via a pointer. (Interoperability between gSOAP clients
and services does not lead to copying.)
<div class="p"><!----></div>
The XML Schema that corresponds to the <i>ns__myClass</i> type is
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;complexType name="myClass&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;sequence&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="number" type="xsd:int" minOccurs="1" maxOccurs="unbounded"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;element name="name" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;&lt;/sequence&#62; <br />
&lt;/complexType&#62;
</td></tr></table><br></tt>
You can specify the minOccurs and maxOccurs values as explained in Section&nbsp;<a href="#sec:directives">18.2</a>.
<div class="p"><!----></div>
You can also implement your own
containers similar to STL containers. The containers must be class templates and should define an iterator type, and <i><b>void</b>&nbsp;clear()</i>, <i>iterator begin()</i>, <i>iterator end()</i>, and <i>iterator insert(iterator pos, const_reference val)</i>.
The <i>iterator</i> should have a dereference operator to
access the container's elements. The dereference operator is used by gSOAP to
send a sequence of XML element values. The <i>insert</i> method can be used as
a setter method. gSOAP reads a sequence of XML element values and inserts them
in the container via this method.
<div class="p"><!----></div>
Here is in example user-defined container template class:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
// simpleVector.h <br />
<b>template</b>&nbsp; &lt; <b>class</b>&nbsp;T &gt; <br />
<b>class</b>&nbsp;simpleVector <br />
{ <br />
<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;T value_type; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;value_type * pointer; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;const value_type * const_pointer; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;value_type &amp; reference; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;const value_type &amp; const_reference; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;pointer iterator; <br />
&nbsp;&nbsp;&nbsp;<b>typedef</b>&nbsp;const_pointer const_iterator; <br />
<b>protected</b>: <br />
&nbsp;&nbsp;&nbsp;iterator start; <br />
&nbsp;&nbsp;&nbsp;iterator finish; <br />
&nbsp;&nbsp;&nbsp;size_t length; <br />
<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;simpleVector() { clear(); } <br />
&nbsp;&nbsp;&nbsp;~simpleVector() { <b>delete</b>[] start; } <br />
&nbsp;&nbsp;&nbsp;<b>void</b>\ clear() { start = finish = NULL; } <br />
&nbsp;&nbsp;&nbsp;iterator begin() { <b>return</b>&nbsp;start; } <br />
&nbsp;&nbsp;&nbsp;const_iterator begin() <b>const</b>\ { <b>return</b>&nbsp;start; } <br />
&nbsp;&nbsp;&nbsp;iterator end() { <b>return</b>&nbsp;finish; } <br />
&nbsp;&nbsp;&nbsp;const_iterator end() <b>const</b>\ { <b>return</b>&nbsp;finish; } <br />
&nbsp;&nbsp;&nbsp;size_t size() <b>const</b>\ { <b>return</b>&nbsp;finish-start; } <br />
&nbsp;&nbsp;&nbsp;iterator insert(iterator pos, const_reference val) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!start) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start = finish = <b>new</b>&nbsp;value_type[length = 4]; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<b>if</b>&nbsp;(finish &gt; = start + length) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterator i = start; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterator j = <b>new</b>&nbsp;value_type[2 * length]; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start = j; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finish = start + length; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;length *= 2; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(pos) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pos = j + (pos - i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>while</b>&nbsp;(i != finish) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*j++ = *i++; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(pos &amp;&amp; pos != finish) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ iterator i = finish; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterator j = i - 1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>while</b>&nbsp;(j != pos) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*i- = *j-; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*finish++ = val; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;pos; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
};
</td></tr></table><br></i>
To enable the container, we add the following two lines to our gSOAP header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "simpleVector.h" <br />
<b>template</b>&nbsp; &lt; class T &gt; <b>class</b>&nbsp;simpleVector;
</td></tr></table><br></i>
The container class
should not be defined in the gSOAP header file. It must be defined in
a separate header file (e.g.&nbsp;"simpleVector.h"). The <i><b>template</b>&nbsp; &lt; class T &gt; <b>class</b>&nbsp;simpleVector</i> declaration ensures that gSOAP will recognize <i>simpleVector</i> as a container class.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: when parsing XML content the container elements may not be stored in the same order given in
the XML content. When gSOAP parses XML it uses the <i>insert</i> container methods to
store elements one by one. However, element content that is "forwarded" with
<tt>href</tt> attributes will be appended to the container. Forwarding can take
place with multi-referenced data that is referred to from the main part of the
SOAP 1.1 XML message to the independent elements that carry <tt>id</tt>s.
Therefore, your application should not rely on the preservation of the order of
elements in a container.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.9">
10.10.9</a>&nbsp;&nbsp;<font color="#0000FF">Polymorphic Dynamic Arrays and Lists</font></h4>
<div class="p"><!----></div>
Polymorphic arrays (arrays of polymorphic element types) can be encoded when
declared as an array of pointers to class instances. and lists. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;ns__Object <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;... <br />
}; <br />
<b>class</b>&nbsp;ns__Data: <b>public</b>&nbsp;ns__Object <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;... <br />
}; <br />
<b>class</b>&nbsp;ArrayOfObject <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;ns__Object **__ptr; // pointer to array of pointers to Objects <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; // number of Objects pointed to <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__offset; // optional SOAP 1.1 array offset <br />
};
</td></tr></table><br></i>
The pointers in the array can point to the <i>ns__Object</i> base class or
<i>ns__Data</i> derived class instances which will be serialized and
deserialized accordingly in SOAP. That is, the array elements are polymorphic.
<div class="p"><!----></div>
<h4><a name="tth_sEc10.10.10">
10.10.10</a>&nbsp;&nbsp;<font color="#0000FF">How to Change the Tag Names of the Elements of a SOAP Array or List</font></h4>
<div class="p"><!----></div>
The <i>__ptr</i> field in a <i><b>struct</b></i> or <i><b>class</b></i> declaration of a dynamic array may have an optional suffix part that
describes the name of the tags of the SOAP array XML elements.
The suffix is part of the field name:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<u><span class="roman">Type</span></u> *__ptr<u><span class="roman">array_elt_name</span></u>
</td></tr></table><br></i>
The suffix describes the tag name to be used for all array elements. The usual identifier to XML translations apply, see
Section&nbsp;<a href="#sec:idtrans">9.3</a>.
The default XML element tag name for array elements is <tt>item</tt> (which corresponds to the use of field name <i>__ptritem</i>).
<div class="p"><!----></div>
Consider for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ArrayOfstring <br />
{ <br />
&nbsp;&nbsp;&nbsp;xsd__string *__ptrstring;
&nbsp;&nbsp;&nbsp;int __size;
};
</td></tr></table><br></i>
The array is serialized as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;array xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:string[2]&#187; <br />
&lt;string xsi:type="xsd:string&#187;Hello&lt;/string&#62; <br />
&lt;string xsi:type="xsd:string&#187;World&lt;/string&#62; <br />
&lt;/array&#62;
</td></tr></table><br></tt>
SOAP 1.1 and 1.2 do not require the use of a specific tag name for array elements. gSOAP will deserialize a SOAP array while
ignoring the tag names. Certain XML Schemas used in doc/literal encoding may require the declaration of array element tag names.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.11">
10.11</a>&nbsp;&nbsp;<font color="#0000FF">Base64Binary XML Schema Type Encoding</font></h3><a name="sec:base64binary">
</a>
<div class="p"><!----></div>
The <tt>base64Binary</tt> XML Schema type is a special form of dynamic array declared with a pointer (<i>__ptr</i>) to an
<i><b>unsigned</b>&nbsp;<b>char</b></i> array.
<div class="p"><!----></div>
For example using a <i><b>struct</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
Or with a <i><b>class</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
When compiled by the gSOAP stub and skeleton compiler, this header file specification will generate <tt>base64Binary</tt> serializers and deserializers.
<div class="p"><!----></div>
The <tt>SOAP_ENC:base64</tt> encoding is another type for base 64 binary encoding
specified by the SOAP data type schema and some SOAP applications may use this form
(as indicated by their WSDL descriptions). It is declared by:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENC__base64 <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
Or with a <i><b>class</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;SOAP_ENC__base64 <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
When compiled by the gSOAP stub and skeleton compiler, this header file specification will generate <tt>SOAP-ENC:base64</tt> serializers and deserializers.
<div class="p"><!----></div>
The advantage of using a <i><b>class</b></i> is that methods can be used to initialize and manipulate the <i>__ptr</i> and <i>__size</i> fields. The user can add methods to this class to do this. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;xsd__base64Binary(); // Constructor <br />
&nbsp;&nbsp;&nbsp;xsd__base64Binary(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;n); // Constructor <br />
&nbsp;&nbsp;&nbsp;~xsd__base64Binary(); // Destructor <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*location(); // returns the memory location <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;size(); // returns the number of bytes <br />
};
</td></tr></table><br></i>
Here are example method implementations:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
xsd__base64Binary::xsd__base64Binary() <br />
{ <br />
&nbsp;&nbsp;&nbsp;__ptr = NULL; <br />
&nbsp;&nbsp;&nbsp;__size = 0; <br />
} <br />
xsd__base64Binary::xsd__base64Binary(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;n) <br />
{ <br />
&nbsp;&nbsp;&nbsp;__ptr = (<b>unsigned</b>&nbsp;<b>char</b>*)soap_malloc(soap, n); <br />
&nbsp;&nbsp;&nbsp;__size = n; <br />
} <br />
xsd__base64Binary::~xsd__base64Binary() <br />
{ } <br />
<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*xsd__base64Binary::location() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;__ptr; <br />
} <br />
<b>int</b>&nbsp;xsd__base64Binary::size() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;__size; <br />
}
</td></tr></table><br></i>
The following example in C/C++ reads from a raw image file and encodes the image in SOAP using the <tt>base64Binary</tt> type:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
... <br />
FILE *fd = fopen(<tt>"image.jpg"</tt>, <tt>"rb"</tt>); <br />
xsd__base64Binary image(&amp;soap, filesize(fd)); <br />
fread(image.location(), image.size(), 1, fd); <br />
fclose(fd); <br />
soap_begin(&amp;soap); <br />
image.soap_serialize(&amp;soap); <br />
image.soap_put(&amp;soap, <tt>"jpegimage"</tt>, NULL); <br />
soap_end(&amp;soap); <br />
...
</td></tr></table><br></i>
where <i>filesize</i> is a function that returns the size of a file given a file descriptor.
<div class="p"><!----></div>
Reading the <tt>xsd:base64Binary</tt> encoded image.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
... <br />
xsd__base64Binary image; <br />
soap_begin(&amp;soap); <br />
image.get(&amp;soap, <tt>"jpegimage"</tt>); <br />
soap_end(&amp;soap); <br />
...
</td></tr></table><br></i>
The <i><b>struct</b></i> or <i><b>class</b></i> name <i>soap_enc__base64</i> should be used for <tt>SOAP-ENC:base64</tt> schema type instead of
<i>xsd__base64Binary</i>.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.12">
10.12</a>&nbsp;&nbsp;<font color="#0000FF">hexBinary XML Schema Type Encoding</font></h3><a name="sec:hexbinary">
</a>
<div class="p"><!----></div>
The <tt>hexBinary</tt> XML Schema type is a special form of dynamic array declared with the name <i>xsd__hexBinary</i> and a pointer (<i>__ptr</i>) to an <i><b>unsigned</b>&nbsp;<b>char</b></i> array.
<div class="p"><!----></div>
For example, using a <i><b>struct</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__hexBinary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
Or using a <i><b>class</b></i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__hexBinary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>public</b>: <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
};
</td></tr></table><br></i>
When compiled by the gSOAP stub and skeleton compiler, this header file specification will generate <tt>base64Binary</tt> serializers and deserializers.
<div class="p"><!----></div>
<h3><a name="tth_sEc10.13">
10.13</a>&nbsp;&nbsp;<font color="#0000FF">Literal XML Encoding Style</font></h3><a name="sec:literal">
</a>
<div class="p"><!----></div>
gSOAP supports document/literal encoding by default.
Just as with SOAP RPC encoding, literal encoding requires the XML Schema of the message data to be provided
e.g.&nbsp;in WSDL in order for the
gSOAP compiler to generate the (de)serialization routines. Alternatively, the
optional DOM parser (<i>dom.c</i> and <i>dom++.cpp</i>) can be used to handle generic XML or
arbitrary XML documents can be (de)serialized into regular C strings or wide
character strings (<i>wchar_t*</i>) by gSOAP (see Section&nbsp;<a href="#sec:literal2">10.13.1</a>).
<div class="p"><!----></div>
The <i>//gsoap service encoding</i>, <i>//gsoap service method-encoding</i>, and <i>//gsoap service method-response-encoding</i> directives explicitly enable SOAP encoded or literal encoded messages. For example, to enable RPC encoding style for the entire service, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service encoding: encoded
</td></tr></table><br></i>
To enable encoding for particular service methods, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-encoding: myMethod encoded <br />
<b>int</b>&nbsp;ns__myMethod(...)
</td></tr></table><br></i>
To enable encoding for particular service methods responses when the method request is literal, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-response-encoding: myMethod encoded <br />
<b>int</b>&nbsp;ns__myMethod(...)
</td></tr></table><br></i>
Instead of the <i>encoded</i> value, you can use <i>literal</i>, or a specific encoding style value.
<div class="p"><!----></div>
Consider the following example that uses the directive to make the literal encoding explicit.
The <i>LocalTimeByZipCode</i> remote service method of the LocalTime service provides
the local time given a zip code and uses literal encoding (with MS
.NET). The following header file declares the method: <br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>int
LocalTimeByZipCode(<b>char</b>&nbsp;*ZipCode, <b>char</b>&nbsp;**LocalTimeByZipCodeResult);
</td></tr></table><br></i> Note that none of the data types need to be namespace qualified using
namespace prefixes.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service name: localtime <br />
//gsoap ns service encoding: literal <br />
//gsoap ns service namespace: http://alethea.net/webservices/ <br />
<b>int</b>&nbsp;ns__LocalTimeByZipCode(<b>char</b>&nbsp;*ZipCode, <b>char</b>&nbsp;**LocalTimeByZipCodeResult);
</td></tr></table><br></i>
In this case, the method name requires to be associated with a schema through a namespace prefix, e.g. <i>ns</i> is used in this example.
See Section&nbsp;<a href="#sec:directives">18.2</a> for more details on gSOAP directives.
With these directives, the gSOAP compiler generates client and server sources with the specified settings.
<div class="p"><!----></div>
The example client program is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include "localtime.nsmap" // include generated map file <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*t; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns__LocalTimeByZipCode(&amp;soap, "http://alethea.net/webservices/LocalTime.asmx", "http://alethea.net/webservices/LocalTimeByZipCode", "32306", &amp;t)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("Time = %s<tt>\n</tt>", t); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
</td></tr></table><br></i>
<div class="p"><!----></div>
To illustrate the manual doc/literal setting, the following client program sets
the required properties before the call:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
#include "localtime.nsmap" // include generated map file <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*t; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap.encodingStyle = NULL; // don't use SOAP encoding <br />
&nbsp;&nbsp;&nbsp;soap_set_omode(&amp;soap, SOAP_XML_TREE);" // don't produce multi-ref data (but can accept) <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns__LocalTimeByZipCode(&amp;soap, "http://alethea.net/webservices/LocalTime.asmx", "http://alethea.net/webservices/LocalTimeByZipCode", "32306", &amp;t)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("Time = %s<tt>\n</tt>", t); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
The SOAP request is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
POST /webservices/LocalTime.asmx HTTP/1.0 <br />
Host: alethea.net <br />
Content-Type: text/xml; charset=utf-8 <br />
Content-Length: 479 <br />
SOAPAction: "http://alethea.net/webservices/LocalTimeByZipCode" <br />
<br />
&lt;?xml version="1.0" encoding=&#220;TF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;&lt;SOAP-ENV:Body&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;LocalTimeByZipCode xmlns="http://alethea.net/webservices/"&#62; <br />
&lt;ZipCode&#62;32306&lt;/ZipCode&#62;&lt;/LocalTimeByZipCode&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h4><a name="tth_sEc10.13.1">
10.13.1</a>&nbsp;&nbsp;<font color="#0000FF">Serializing and Deserializing Mixed Content XML With Strings</font></h4><a name="sec:literal2">
</a>
<div class="p"><!----></div>
To declare a literal XML "type" to hold XML documents in regular strings, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*XML;
</td></tr></table><br></i>
To declare a literal XML "type" to hold XML documents in wide character strings, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;wchar_t *XML;
</td></tr></table><br></i>
Note: only one of the two storage formats can be used.
The differences between the use of regular strings versus wide character strings for XML documents are:
<ul>
<li> Regular strings for XML documents MUST hold UTF-8 encoded XML documents. That is, the string MUST contain the proper UTF-8
encoding to exchange the XML document in SOAP messages.
<div class="p"><!----></div>
</li>
<li> Wide character strings for XML documents SHOULD NOT hold UTF-8 encoded XML documents. Instead, the UTF-8 translation is done automatically by
the gSOAP runtime marshalling routines.
<div class="p"><!----></div>
</li>
</ul>
Here is an example of a remote method specification in which the parameters of the remote method uses literal XML encoding to pass
an XML document to a service and back:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*XML; <br />
ns__GetDocument(XML m__XMLDoc, XML &amp;m__XMLDoc_);
</td></tr></table><br></i>
The <i>ns__Document</i> is essentially a <i><b>struct</b></i> that forms the root of the XML document.
The use of the underscore in the <i>ns__Document</i> response part of the message avoids the name clash between the
<i><b>struct</b></i>s.
Assuming that the namespace mapping table contains the binding of <i>ns</i> to <tt>http://my.org/</tt>
and the binding of <i>m</i> to <tt>http://my.org/mydoc.xsd</tt>, the XML message is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;?xml version="1.0" encoding="UTF-8"?&#62; <br />
&lt;SOAP-ENV:Envelope <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <br />
&nbsp;&nbsp;&nbsp;xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&nbsp;&nbsp;&nbsp;xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />
&nbsp;&nbsp;&nbsp;xmlns:ns="http://my.org/" <br />
&nbsp;&nbsp;&nbsp;xmlns:m="http://my.org/mydoc.xsd" <br />
&nbsp;&nbsp;&nbsp;SOAP-ENV:encodingStyle=""&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;SOAP-ENV:Body&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ns:GetDocument&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;XMLDoc xmlns="http://my.org/mydoc.xsd"&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/XMLDoc&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ns:Document&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
When using literal encoding of method parameters and response as shown in the example above, the literal XML encoding style MUST be specified by setting <i>soap.encodingStyle</i>.
For example, to specify no constraints on the encoding style (which is typical) use NULL:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.encodingStyle = NULL;
</td></tr></table><br></i>
As a result, the <tt>SOAP-ENV:encodingStyle</tt> attribute will not appear in the SOAP payload.
<div class="p"><!----></div>
For interoperability with Apache SOAP, use
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.encodingStyle = "http://xml.apache.org/xml-soap/literalxml";
</td></tr></table><br></i>
When the response parameter is an XML type, it will store the entire XML response content but without the enveloping response element.
<div class="p"><!----></div>
The XML type can be used as part of any data structure to enable the rendering and parsing of custom XML documents. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*XML; <br />
<b>struct</b>&nbsp;ns__Data /* data in namespace 'ns' */ <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;number; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;XML m__document; /* XML document in default namespace 'm' */ <br />
}; <br />
ns__Example(<b>struct</b>&nbsp;ns__Data data, <b>struct</b>&nbsp;ns__ExampleResponse { <b>struct</b>&nbsp;ns__Data data; } *out);
</td></tr></table><br></i>
<div class="p"><!----></div>
<h2><a name="tth_sEc11">
11</a>&nbsp;&nbsp;<font color="#0000FF">SOAP Fault Processing</font></h2><a name="sec:fault">
</a>
<div class="p"><!----></div>
A predeclared standard SOAP Fault data structure is generated by the gSOAP stub and skeleton compiler for exchanging exception messages.
The built-in <i><b>struct</b>&nbsp;SOAP_ENV__Fault</i> data structure is defined as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Fault <br />
{ <br />
&nbsp;&nbsp;&nbsp;_QName faultcode; // _QName is builtin <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*faultstring; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*faultactor; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;SOAP_ENC__Detail *detail; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;SOAP_ENV__Code *SOAP_ENV__Code; // MUST be a SOAP_ENV__Code struct defined below <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*SOAP_ENV__Reason; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*SOAP_ENV__Node; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*SOAP_ENV__Role; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;SOAP_ENV__Detail SOAP_ENV__Detail; // SOAP 1.2 detail field <br />
};
<b>struct</b>&nbsp;SOAP_ENV__Code <br />
{ <br />
&nbsp;&nbsp;&nbsp;_QName SOAP_ENV__Value; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;SOAP_ENV__Code *SOAP_ENV__Subcode;
}; <br />
<b>struct</b>&nbsp;SOAP_ENV__Detail <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__type; // The SOAP_TYPE_ of the object serialized as Fault detail <br />
&nbsp;&nbsp;&nbsp;<b>void</b>&nbsp;*fault; // pointer to the fault object, or NULL <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*__any; // any other detail element content (stored in XML format) <br />
};
</td></tr></table><br></i>
The first four fields in <i>SOAP_ENV__Fault</i> are SOAP 1.1 specific. The last five fields are SOAP 1.2 specific.
You can redefine these structures in the header file. For example, you can use a <i>class</i> for the <i>SOAP_ENV__Fault</i> and add methods for convenience.
<div class="p"><!----></div>
The data structure content can be changed to the need of an application, but this is generally not necessary because the application-specific SOAP Fault details can be serialized via the <i>__type</i> and <i>fault</i> fields in the <i>SOAP_ENV__Detail</i> field, see Section&nbsp;<a href="#sec:void">10.8</a> on the serialization of data refered to by <i>__type</i> and <i>fault</i>.
<div class="p"><!----></div>
The <i>__type</i> field allows application data to be serialized as part of the SOAP Fault. The application data SHOULD be defined as XML elements, which requires you to declare the type names with a leading underscore to ensure that the types are compatible with XML elements and not just simpleTypes and complexTypes.
<div class="p"><!----></div>
When the skeleton of a remote method returns an error (see Section&nbsp;<a href="#sec:errcodes">9.2</a>), then <i>soap.fault</i> contains the SOAP
Fault data at the receiving side (client).
<div class="p"><!----></div>
Server-side faults are raised with <i>soap_sender_fault</i> or <i>soap_receiver_fault</i>. The <i>soap_sender_fault</i> call should be used to inform that the sender is at fault and the sender (client) should not resend the request. The <i>soap_receiver_fault</i> call should be used to indicate a temporary server-side problem, so a sender (client) can resend the request later. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns1__myMethod(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_receiver_fault(soap, "Resource temporarily unavailable", NULL); // return fault to sender <br />
}
</td></tr></table><br></i>
In the example, the SOAP Fault details were empty (NULL). You may pass an XML fragment, which will be literally included in the SOAP Fault message. For WS-I Basic Profile compliance, you must pass an XML string with one or more namespace qualified elements, such as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>return</b>&nbsp;soap_receiver_fault(soap, "Resource temporarily unavailable", " &lt; errorcode xmlns='http://tempuri.org' &gt; 123 &lt; /errorcode &gt; &lt; errorinfo xmlns='http://tempuri.org' &gt; abc &lt; /errorinfo &gt; ");
</td></tr></table><br></i>
<div class="p"><!----></div>
When a remote method must raise an exception with application SOAP Fault details, it does so by assigning the <i>soap.fault</i> field of the current reference to the
runtime environment with
appropriate data associated with the exception and by returning the error <i>SOAP_FAULT</i>.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
&nbsp;&nbsp;&nbsp;soap_receiver_fault(soap, "Stack dump", NULL); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>version == 2) // SOAP 1.2 is used <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>SOAP_ENV__Detail = (<b>struct</b>&nbsp;SOAP_ENV__Detail*)soap_malloc(soap, sizeof(<b>struct</b>&nbsp;SOAP_ENV__Detail); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>SOAP_ENV__Detail<tt>-&gt;</tt>__type = SOAP_TYPE_ns1__myStackDataType; // stack type <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>SOAP_ENV__Detail<tt>-&gt;</tt>fault = sp; // point to stack <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>SOAP_ENV__Detail<tt>-&gt;</tt>__any = NULL; // no other XML data <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>detail = (<b>struct</b>&nbsp;SOAP_ENV__Detail*)soap_malloc(soap, sizeof(<b>struct</b>&nbsp;SOAP_ENV__Detail); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>detail<tt>-&gt;</tt>__type = SOAP_TYPE_ns1__myStackDataType; // stack type <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>detail<tt>-&gt;</tt>fault = sp; // point to stack <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fault<tt>-&gt;</tt>detail<tt>-&gt;</tt>__any = NULL; // no other XML data <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_FAULT; // return from remote method call
</td></tr></table><br></i>
When <i>soap_receiver_fault</i> allocates a fault struct, this data is removed with the <i>soap_end</i> call (or <i>soap_dealloc</i>).
Note that the <i>soap_receiver_fault</i> function is called to allocate the fault struct and set the fault string and detail
fields, i.e. <i>soap_receiver_fault(soap, "Stack dump", NULL)</i>. The advantage is that this is independent of SOAP 1.1 and
SOAP 1.2. However, setting the custom detail fields requires inspecting the SOAP version used, using the <i>soap</i><tt>-&gt;</tt><i>version</i>
attribute which is 1 for SOAP 1.1 and 2 for SOAP 1.2.
<div class="p"><!----></div>
Each remote method implementation in a service application can return a SOAP Fault upon an exception by returning an error code,
see Section&nbsp;<a href="#sec:example7">7.2.1</a> for details and an example.
In addition, a SOAP Fault can be returned by a service application through calling the <i>soap_send_fault</i> function.
This is useful in case the initialization of the application fails, as illustrated in the example below:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;some initialization code <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(initialization failed) <br />
&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.error = soap_receiver_fault(&amp;soap, <tt>"Init&nbsp;failed"</tt>, NULL); // set the error condition (SOAP_FAULT) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_send_fault(&amp;soap); // Send SOAP Fault to client <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; // Terminate <br />
&nbsp;&nbsp;&nbsp;} <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h2><a name="tth_sEc12">
12</a>&nbsp;&nbsp;<font color="#0000FF">SOAP Header Processing</font></h2><a name="sec:header">
</a>
<div class="p"><!----></div>
A predeclared standard SOAP Header data structure is generated by the gSOAP stub and skeleton compiler for exchanging SOAP
messages with SOAP Headers.
This predeclared data structure is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <b>void</b>&nbsp;*dummy; <br />
};
</td></tr></table><br></i>
which declares and empty header (some C and C++ compilers don't accept empty structs so a transient dummy field is provided).
<div class="p"><!----></div>
To adapt the data structure to a specific need for SOAP Header processing, a
new <i><b>struct</b>&nbsp;SOAP_ENV__Header</i> can be added to the header file input to the gSOAP
compiler. A <i><b>class</b></i> for the SOAP Header data structure can be used instead of a <i><b>struct</b></i>.
<div class="p"><!----></div>
For example, the following header can be used for transaction control:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <b>char</b>&nbsp;*t__transaction; <br />
};
</td></tr></table><br></i>
with client-side code:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
... <br />
soap.header = NULL; // do not use a SOAP Header for the request (as set with soap_init) <br />
soap.actor = NULL; // do not use an actor (receiver is actor) <br />
soap_call_method(&amp;soap, ...); <br />
<b>if</b>&nbsp;(soap.header) // a SOAP Header was received <br />
&nbsp;&nbsp;&nbsp;cout &lt;&lt; soap.header<tt>-&gt;</tt>t__transaction; <br />
// Can reset, modify, or set soap.header here before next call <br />
soap_call_method(&amp;soap, ...); // reuse the SOAP Header of the service response for the request <br />
...
</td></tr></table><br></i>
The SOAP Web service response can include a SOAP Header with a transaction number that the client is supposed to use for the next remote method invocation to the service. Therefore, the next request includes a transaction number:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
... <br />
&lt;SOAP-ENV:Envelope ...&#62; <br />
&lt;SOAP-ENV:Header&#62; <br />
&lt;transaction xmlns="..." xsi:type="int"&#62;12345&lt;/transaction&#62; <br />
&lt;/SOAP-ENV:Header&#62; <br />
&lt;SOAP-ENV:Body&#62; <br />
... <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
This is just an example and the transaction control is not a feature of SOAP but can be added on by the application layer
to implement stateful transactions between clients and services.
At the client side, the <i>soap.actor</i> attribute can be set to
indicate the recipient of the header (the SOAP <tt>SOAP-ENV:actor</tt> attribute).
<div class="p"><!----></div>
A Web service can read and set the SOAP Header as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap.actor = NULL; // use this to accept all headers (default) <br />
&nbsp;&nbsp;&nbsp;soap.actor = "http://some/actor"; // accept headers destined for "http://some/actor" only <br />
&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap);<br />
} <br />
... <br />
<b>int</b>&nbsp;method(<b>struct</b>&nbsp;soap *soap, ...) <br />
{<br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>header) // a Header was received <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... = soap<tt>-&gt;</tt>header<tt>-&gt;</tt>t__transaction; <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header = soap_malloc(<b>sizeof</b>(<b>struct</b>&nbsp;SOAP_ENV__Header)); // alloc new header <br />
...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>t__transaction = ...; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
See Section&nbsp;<a href="#sec:directives">18.2</a> on how to generate WSDL with the proper method-to-header-part bindings.
<div class="p"><!----></div>
The <tt>SOAP-ENV:mustUnderstand</tt> attribute indicates the requirement that the recipient of the SOAP Header (who must
correspond to the <tt>SOAP-ENV:actor</tt> attribute when present or when the attribute has the value
<tt>SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next"</tt>) MUST handle the Header part that carries the attribute.
gSOAP handles this automatically on the background. However, an application still needs to inspect the header part's value
and handle it appropriately. If a remote method in a Web service is not able to do this, it should return
<i>SOAP_MUSTUNDERSTAND</i> to indicate this failure.
<div class="p"><!----></div>
The syntax for the header file input to the gSOAP compiler is extended with a special storage qualifier <i>mustUnderstand</i>.
This qualifier can be used in the SOAP Header declaration to indicate which parts should carry a <i>SOAP-ENV:mustUnderstand="1"</i>
attribute. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*t__transaction; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand <b>char</b>&nbsp;*t__authentication; <br />
};
</td></tr></table><br></i>
When both fields are set and <i>soap.actor="http://some/actor"</i> then the message contains:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;SOAP-ENV:Envelope ...&#62; <br />
&lt;SOAP-ENV:Header&#62; <br />
&lt;transaction xmlns="...&#187;5&lt;/transaction&#62; <br />
&lt;authentication xmlns="..." SOAP-ENV:actor="http://some/actor" SOAP-ENV:mustUnderstand="1"&#62;XX <br />
&lt;/authentication&#62; <br />
&lt;/SOAP-ENV:Header&#62; <br />
&lt;SOAP-ENV:Body&#62; <br />
... <br />
&lt;/SOAP-ENV:Body&#62; <br />
&lt;/SOAP-ENV:Envelope&#62;
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h2><a name="tth_sEc13">
13</a>&nbsp;&nbsp;<font color="#0000FF">MIME Attachments</font></h2><a name="sec:MIME">
</a>
<div class="p"><!----></div>
The gSOAP toolkit supports MIME attachments as per SOAP with Attachments (SwA)
specification (http://www.w3.org/TR/SOAP-attachments). MIME attachment data must be memory resident for sending
operations and MIME attachments received will be stored in memory. DIME
attachments on the other hand can be streamed and therefore DIME attachment
data does not need to be stored in memory, see
Section&nbsp;<a href="#sec:DIME">14</a>.
<div class="p"><!----></div>
Transmitting multipart/related MIME attachments with a SOAP/XML message is
accomplished with two functions, <i>soap_set_mime</i> and
<i>soap_set_mime_attachment</i>. The first function is for initialization
purposes and the latter function is used to specify meta data and content data
for each attachment.
<div class="p"><!----></div>
<h3><a name="tth_sEc13.1">
13.1</a>&nbsp;&nbsp;<font color="#0000FF">Sending a Collection of MIME Attachments</font></h3>
<div class="p"><!----></div>
The following functions should be used to set up a collection of
multipart/related MIME attachments for transmission with a SOAP/XML message.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Function</b></font> </td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_set_mime(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*boundary, <b>const</b>&nbsp;<b>char</b>&nbsp;*start)</i> </td></tr>
<tr><td width="602">This function must be called first to initialize MIME attachment send operations (receives are automatic). The function specifies a MIME boundary and start content ID used for the SOAP message body. When <i>boundary</i> is NULL, an appropriate MIME boundary will be choosen (important: boundaries cannot occur in the SOAP/XML message and cannot occur in any of the MIME attachments content). When a specific boundary value is provided, gSOAP will NOT verify that the boundary is valid. When <i>start</i> is NULL, the start ID of the SOAP message is <tt>&lt;</tt><tt>SOAP-ENV:Envelope</tt><tt>&gt;</tt>.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_set_mime_attachment(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*ptr, size_t size, <b>enum</b>&nbsp;soap_mime_encoding encoding, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>const</b>&nbsp;<b>char</b>&nbsp;*location, <b>const</b>&nbsp;<b>char</b>&nbsp;*description)</i> </td></tr>
<tr><td width="602">This function adds a new attachment to the list of attachments, where <i>ptr</i> and <i>size</i> refer to the block of memory that holds the attachment data. The <i>encoding</i> parameter specifies the content encoding of this block, where the value of <i>encoding</i> is one of <i>SOAP_MIME_7BIT</i>, <i>SOAP_MIME_8BIT</i>, <i>SOAP_MIME_BINARY</i>, <i>SOAP_MIME_QUOTED_PRINTABLE</i>, <i>SOAP_MIME_BASE64</i>, <i>SOAP_MIME_IETF_TOKEN</i>, or <i>SOAP_MIME_X_TOKEN</i>. These constants reflect the content encoding defined in RFC2045 and you MUST adhere to the content encoding rules defined by RFC2045. When in doubt, use <i>SOAP_MIME_BINARY</i>, since this encoding type covers any content. The mandatory <i>type</i> string parameter is the MIME type of the data. The <i>id</i> string parameter is the content ID of the MIME attachment. The optional <i>location</i> string parameter is the content location of the attachment. The optional <i>description</i> string parameter holds a textual description of the attachment (it may not contain any control characters). All parameter values are copied, except <i>ptr</i> which must point to a valid location of the attachment data during the transfer.
The value <i>SOAP_OK</i> is returned when the attachment was added. Otherwise a gSOAP error code is returned.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_clr_mime(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Disables MIME attachments, e.g.&nbsp;to avoid MIME attachments to be part of a SOAP Fault response message. </td></tr></table>
</td></tr></table><br></span>
When providing a MIME boundary with <i>soap_set_mime</i>, you have to make
sure the boundary cannot match any SOAP/XML message content. Therefore, it is
recommended to include an invalid XML sequence such as <tt>&lt;&gt;</tt>. Or you can
simply pass NULL and let gSOAP select a safe boundary for you.
<div class="p"><!----></div>
The internal list of attachments is destroyed with <i>soap_end</i>, you should
call this function sometime after the message exchange was completed (the
content of the block of memory referred to by the <i>ptr</i> parameter is
unaffected).
<div class="p"><!----></div>
The following example shows how a multipart/related HTTP message with three
MIME attachments is set up and transmitted to a server. The first attachment
contains the SOAP message. The second and third attachments contain image data.
In this example we let the SOAP message body refer to the attachments using
<tt>href</tt> attributes. The <i><b>struct</b>&nbsp;claim__form</i> data type includes a
definition of a <i>href</i> attribute for this purpose.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;claim__form form1, form2; <br />
form1.href = <tt>"cid:claim061400a.tiff@claiming-it.com"</tt>; <br />
form2.href = <tt>"cid:claim061400a.jpeg@claiming-it.com"</tt>; <br />
/* initialize and enable MIME */ <br />
soap_set_mime(soap, <tt>"MIME_boundary"</tt>, <tt>"&lt;claim061400a.xml@claiming-it.com&gt;"</tt>); <br />
/* add a base64 encoded tiff image (tiffImage points to base64 data) */ <br />
soap_set_mime_attachment(soap, tiffImage, tiffLen, SOAP_MIME_BASE64, <tt>"image/tiff"</tt>, <tt>"&lt;claim061400a.tiff@claiming-it.com&gt;"</tt>, NULL, NULL); <br />
/* add a raw binary jpeg image (jpegImage points to raw data) */ <br />
soap_set_mime_attachment(soap, jpegImage, jpegLen, SOAP_MIME_BINARY, <tt>"image/jpeg"</tt>, <tt>"&lt;claim061400a.jpeg@claiming-it.com&gt;"</tt>, NULL, NULL); <br />
/* send the forms as MIME attachments with this invocation */ <br />
<b>if</b>&nbsp;(soap_call_claim__insurance_claim_auto(soap, form1, form2, ...)) <br />
&nbsp;&nbsp;&nbsp;// an error occurred <br />
<b>else</b><br />
&nbsp;&nbsp;&nbsp;// process response
</td></tr></table><br></i>
Note: the above example assumes that the boundary <tt>MIME_boundary</tt> does not occur in the SOAP/XML message.
<div class="p"><!----></div>
The <i>claim__form</i> struct is declared in the gSOAP header file as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;claim__form <br />
{ @<b>char</b>&nbsp;*href; <br />
};
</td></tr></table><br></i>
This data type defines the parameter data of the operation. The claim forms in
the SOAP/XML message consist of <tt>href</tt>s to the claim forms attached. The
produced message is similar to the last example shown in the SOAP with
Attachments specification (http://www.w3.org/TR/SOAP-attachments). Note that
the use of <tt>href</tt> or other attributes for referring to the MIME attachments
is optional according to the SwA standard.
<div class="p"><!----></div>
To associate MIME attachments with the request and response of a service operation in the generated WSDL, please see Section&nbsp;<a href="#sec:MIMEWSDL">15.1</a>.
<div class="p"><!----></div>
The server-side code to transmit MIME attachments back to a client is similar:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;claim__insurance_claim_auto(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_set_mime(soap, NULL, NULL); // enable MIME<br />
&nbsp;&nbsp;&nbsp;// add a HTML document (htmlDoc points to data, where the HTML doc is stored in compliance with 7bit encoding RFC2045) <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_set_mime_attachment(soap, htmlDoc, strlen(htmlDoc), SOAP_MIME_7BIT, <tt>"text/html"</tt>, <tt>"&lt;claim061400a.html@claiming-it.com&gt;"</tt>, NULL, NULL)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_clr_mime(soap); // don't want fault with attachments <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap<tt>-&gt;</tt>error; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
It is also possible to attach data to a SOAP fault message.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution:</b></font> DIME in MIME is supported. However, gSOAP will not verify whether
the MIME boundary is present in the DIME attachments and therefore will not
select a boundary that is guaranteed to be unique. Therefore, you must provide
a MIME boundary with <i>soap_set_mime</i> that is unique when using DIME in
MIME.
<div class="p"><!----></div>
<h3><a name="tth_sEc13.2">
13.2</a>&nbsp;&nbsp;<font color="#0000FF">Retrieving a Collection of MIME Attachments</font></h3>
<div class="p"><!----></div>
MIME attachments are automatically parsed and stored in memory.
After receiving a set of MIME attachments, either at the client-side or
the server-side, the list of MIME attachments can be traversed to extract
meta data and the attachment content. The first attachment in the collection of
MIME attachments always contains meta data about the SOAP message
itself (because the SOAP message was processed the attachment does not contain
any useful data).
<div class="p"><!----></div>
To traverse the list of MIME attachments in C, you use a loop similar to:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap_multipart *attachment; <br />
<b>for</b>&nbsp;(attachment = soap.mime.list; attachment; attachment = attachment<tt>-&gt;</tt>next) <br />
{ <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"MIME&nbsp;attachment:\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Memory=%p\n"</tt>, (*attachment).ptr); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Size=%ul\n"</tt>, (*attachment).size); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Encoding=%d\n"</tt>, (<b>int</b>)(*attachment).encoding); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Type=%s\n"</tt>, (*attachment).type?(*attachment).type:"null"); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"ID=%s\n"</tt>, (*attachment).id?(*attachment).id:"null"); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Location=%s\n"</tt>, (*attachment).location?(*attachment).location:"null"); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Description=%s\n"</tt>, (*attachment).description?(*attachment).description:"null"); <br />
}
</td></tr></table><br></i>
C++ programmers can use an iterator instead, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>for</b>&nbsp;(soap_multipart::iterator attachment = soap.mime.begin(); attachment != soap.mime.end(); ++attachment) <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "MIME attachment:" <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Memory=" <tt>&lt;&lt;</tt> (<b>void</b>*)(*attachment).ptr <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Size=" <tt>&lt;&lt;</tt> (*attachment).size <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> &#203;ncoding=" <tt>&lt;&lt;</tt> (*attachment).encoding <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Type=" <tt>&lt;&lt;</tt> ((*attachment).type?(*attachment).type:"null") <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "ID=" <tt>&lt;&lt;</tt> ((*attachment).id?(*attachment).id:"null") <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Location=" <tt>&lt;&lt;</tt> ((*attachment).location?(*attachment).location:"null") <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Description=" <tt>&lt;&lt;</tt> ((*attachment).description?(*attachment).description:"null") <tt>&lt;&lt;</tt> endl; <br />
}
</td></tr></table><br></i>
Note: keep in mind that the first attachment is associated with the SOAP
message and you may want to ignore it.
<div class="p"><!----></div>
A call to <i>soap_end</i> removes all of the received MIME data. To preserve an
attachment in memory, use <i>soap_unlink</i> on the <i>ptr</i> field of the
<i>soap_multipart</i> struct. Recall that the <i>soap_unlink</i> function is
commonly used to prevent deallocation of deserialized data.
<div class="p"><!----></div>
<h2><a name="tth_sEc14">
14</a>&nbsp;&nbsp;<font color="#0000FF">DIME Attachments</font></h2><a name="sec:DIME">
</a>
<div class="p"><!----></div>
The gSOAP toolkit supports DIME attachments as per DIME
specification, see for example (http://msdn.microsoft.com/library/en-us/dnglobspec/html/draft-nielsen-dime-02.txt)
<div class="p"><!----></div>
Applications developed with gSOAP can transmit binary DIME
attachments with or without streaming. Without streaming, all data is stored and retrieved in memory, which can be prohibitive when transmitting large files on small devices. In contrast with DIME
streaming, data handlers are used to pass the data to and from a resource, such as a file or device.
With DIME output streaming, raw binary data is send from a data source in
chunks on the fly without buffering the entire content to save memory. With DIME input streaming,
raw binary data will be passed to data handlers (callbacks).
<div class="p"><!----></div>
<h3><a name="tth_sEc14.1">
14.1</a>&nbsp;&nbsp;<font color="#0000FF">Sending a Collection of DIME Attachments</font></h3>
<div class="p"><!----></div>
The following functions should be used to set up a collection of
multipart/related MIME attachments for transmission with a SOAP/XML message.
The attachments can be streamed, as described in Section&nbsp;<a href="#sec:DIMEstreaming">14.4</a>.
Without streaming, each attachment must refer to a block of data in memory.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Function</b></font> </td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_set_dime(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">This function must be called first to initialize DIME attachment send operations (receives are automatic).
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_set_dime_attachment(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*ptr, size_t size, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>unsigned</b>&nbsp;<b>short</b>&nbsp;optype, <b>const</b>&nbsp;<b>char</b>&nbsp;*option)</i> </td></tr>
<tr><td width="602">This function adds a new attachment to the list of attachments, where <i>ptr</i> and <i>size</i> refer to the block of memory that holds the attachment data (except when DIME streaming callback handlers are used as described in Section&nbsp;<a href="#sec:DIMEstreaming">14.4</a>. The <i>type</i> string parameter is the MIME type of the data. The <i>id</i> string parameter is the content ID of the DIME attachment. The <i>option</i> string parameter holds optional text (gSOAP supports DIME options, but it can send only one) and <i>optype</i> is a user-defined option type (as per DIME option specification format). All parameter values are copied, except <i>ptr</i>.
The value <i>SOAP_OK</i> is returned when the attachment was added. Otherwise a gSOAP error code is returned.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_clr_mime(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Disables DIME attachments, unless the serialized SOAP message contains attachments for transmission.
</td></tr></table>
</td></tr></table><br></span>
<div class="p"><!----></div>
<h3><a name="tth_sEc14.2">
14.2</a>&nbsp;&nbsp;<font color="#0000FF">Retrieving a Collection of DIME Attachments</font></h3>
<div class="p"><!----></div>
DIME attachments are automatically parsed and stored in memory (or passed to the streaming handlers).
After receiving a set of DIME attachments, either at the client-side or
the server-side, the list of DIME attachments can be traversed to extract
meta data and the attachment content.
<div class="p"><!----></div>
To traverse the list of DIME attachments in C, you use a loop similar to:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap_multipart *attachment; <br />
<b>for</b>&nbsp;(attachment = soap.dime.list; attachment; attachment = attachment<tt>-&gt;</tt>next) <br />
{ <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"DIME&nbsp;attachment:\n"</tt>); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Memory=%p\n"</tt>, (*attachment).ptr); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Size=%ul\n"</tt>, (*attachment).size); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"Type=%s\n"</tt>, (*attachment).type?(*attachment).type:"null"); <br />
&nbsp;&nbsp;&nbsp;printf(<tt>"ID=%s\n"</tt>, (*attachment).id?(*attachment).id:"null"); <br />
}
</td></tr></table><br></i>
C++ programmers can use an iterator instead, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>for</b>&nbsp;(soap_multipart::iterator attachment = soap.dime.begin(); attachment != soap.dime.end(); ++attachment) <br />
{ <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "DIME attachment:" <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Memory=" <tt>&lt;&lt;</tt> (<b>void</b>*)(*attachment).ptr <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Size=" <tt>&lt;&lt;</tt> (*attachment).size <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "Type=" <tt>&lt;&lt;</tt> ((*attachment).type?(*attachment).type:"null") <tt>&lt;&lt;</tt> endl; <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "ID=" <tt>&lt;&lt;</tt> ((*attachment).id?(*attachment).id:"null") <tt>&lt;&lt;</tt> endl; <br />
}
</td></tr></table><br></i>
The <i>options</i> field is available as well. The <i>options</i> content is
formatted according to the DIME specification: the first two bytes are reserved
for the option type, the next two bytes store the size of the option data,
followed by the (binary) option data.
<div class="p"><!----></div>
A call to <i>soap_end</i> removes all of the received DIME data. To preserve an
attachment in memory, use <i>soap_unlink</i> on the <i>ptr</i> field of the
<i>soap_multipart</i> struct. Recall that the <i>soap_unlink</i> function is
commonly used to prevent deallocation of deserialized data.
<div class="p"><!----></div>
<h3><a name="tth_sEc14.3">
14.3</a>&nbsp;&nbsp;<font color="#0000FF">Serializing Binary Data in DIME</font></h3>
<div class="p"><!----></div>
Binary data stored in extended <tt>xsd:base64Binary</tt> and <tt>xsd:hexBinary</tt>
types can be serialized and deserialized as DIME attachments. These attachments
will be transmitted prior to the sequence of secondary DIME attachments defined
by the user with <i>soap_set_dime_attachment</i> as explained in the
previous section. The serialization process is automated and DIME attachments
will be send even when <i>soap_set_dime</i> or
<i>soap_set_dime_attachment</i> are not used.
<div class="p"><!----></div>
The <tt>xsd:base64Binary</tt> XSD type is defined in gSOAP as a struct or class by
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; // pointer to raw binary data <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; // size of the block of data <br />
};
</td></tr></table><br></i>
To enable serialization of the data in DIME, we extend this type with three
additional fields:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*type; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*options; <br />
};
</td></tr></table><br></i>
The three additional fields consist of an <i>id</i> field for attachment
referencing (typically a content id (CID) or UUID), a <i>type</i> field to
specify the MIME type of the binary data, and an <i>options</i> field to
piggy-back additional information with a DIME attachment. The order of the
declaration of the fields is significant. In addition, no other fields or
methods may be declared before any of these fields in the struct/class, but
additional fields and methods may appear after the field declarations. An
extended <i>xsd__hexBinary</i> declaration is similar.
<div class="p"><!----></div>
The <i>id</i> and <i>type</i> fields contain text. The set the DIME-specific
options field, you can use the <i>soap_dime_option</i> function: <br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>char</b>&nbsp;*soap_dime_option(<b>struct</b>&nbsp;soap *soap, <b>unsigned</b>&nbsp;<b>short</b>&nbsp;type, <b>const</b>&nbsp;<b>char</b>&nbsp;*option)
</td></tr></table><br></i>
returns a string with this encoding. For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;xsd__base64Binary image; <br />
image.__ptr = ...; <br />
image.__size = ...; <br />
image.id = <tt>"uuid:09233523-345b-4351-b623-5dsf35sgs5d6"</tt>; <br />
image.type = <tt>"image/jpeg"</tt>; <br />
image.options = soap_dime_option(soap, 0, <tt>"My&nbsp;wedding&nbsp;picture"</tt>);
</td></tr></table><br></i>
When either the <i>id</i> or <i>type</i> field values are non-NULL at run time,
the data will be serialized as a DIME attachment. The SOAP/XML message refers
to the attachments using <tt>href</tt> attributes. This generally works will with
SOAP RPC, because <tt>href</tt> attributes are permitted. However, with document/literal style the referencing mechanism must be explicitly defined
in the schema of the binary type. The gSOAP
declaration of an extended binary type is
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__myBinaryDataType <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*type; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*options; <br />
};
</td></tr></table><br></i>
C++ programmers can use inheritance instead of textual extension required in C, as in
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>class</b>&nbsp;xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
}; <br />
<b>class</b>&nbsp;ns__myBinaryDataType : xsd__base64Binary <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*type; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*options; <br />
};
</td></tr></table><br></i>
This defines an extension of <tt>xsd:base64Binary</tt>, such that the data can be
serialized as DIME attachments using <tt>href</tt> attributes for referencing.
When a different attribute name is in fact used, it must be explicitly defined:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap WSref schema import: http://schemas.xmlsoap.org/ws/2002/04/reference/ <br />
<b>struct</b>&nbsp;ns__myBinaryDataType <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*type; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*options; <br />
&nbsp;&nbsp;&nbsp;@<b>char</b>&nbsp;*WSref__location; <br />
};
</td></tr></table><br></i>
The example above uses the <tt>location</tt> attribute defined in the content reference schema, as defined in one of the vendor's specific WSDL extensions for DIME (http://www.gotdotnet.com/team/xml_wsspecs/dime/WSDL-Extension-for-DIME.htm).
<div class="p"><!----></div>
When receiving DIME attachments, the DIME meta data and binary data content is
stored in binary data types only when the XML parts of the message uses
<tt>href</tt> attributes to refer to these attachments. The gSOAP toolkit may
support automatic (de)serialization with other user-defined (or WSDL-defined)
attributes in future releases.
<div class="p"><!----></div>
Messages may contain binary data that references external resources not
provided as attachments. In that case, the <i>__ptr</i> field is NULL and the
<i>id</i> field refers to the external data source.
<div class="p"><!----></div>
The <i>dime_id_format</i> attribute of the current gSOAP run-time environment
can be set to the default format of DIME id fields. The format string MUST
contain a <i>%d</i> format specifier (or any other <i><b>int</b></i>-based format
specifier). The value of this specifier is a non-negative integer, with zero
being the value of the DIME attachment id for the SOAP message. For example,
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap;<br />
soap_init(&amp;soap); <br />
soap.dime_id_format = <tt>"uuid:09233523-345b-4351-b623-5dsf35sgs5d6-%x"</tt>; <br />
</td></tr></table><br></i>
As a result, all attachments with a NULL <i>id</i> field will use a
gSOAP-generated id value based on the format string.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution:</b></font> Care must be taken not to introduce duplicate content id values,
when assigning content id values to the id fields of DIME extended binary data
types. Content ids must be unique.
<div class="p"><!----></div>
<h3><a name="tth_sEc14.4">
14.4</a>&nbsp;&nbsp;<font color="#0000FF">Streaming DIME</font></h3><a name="sec:DIMEstreaming">
</a>
<div class="p"><!----></div>
Streaming DIME is achieved with callback functions to fetch and store data
during transmission. Three function callbacks for streaming DIME output and
three callbacks for streaming DIME input are available.
<div class="p"><!----></div>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Callback (function pointer)</b></font> </td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;*(*soap.fdimereadopen)(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*options)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment sender to start reading from a
(binary) data source for outbound transmission. The content will be read from the
application's data source in chunks using the <i>fdimeread</i> callback and
streamed into the SOAP/XML/DIME output stream. The <i>handle</i> contains the
value of the <i>__ptr</i> field of an attachment struct/class, which could be a
pointer to specific information such as a file descriptor or a pointer to a
string to be passed to this callback. Both <i>__ptr</i> and <i>__size</i>
fields should have been set by the application prior to the serialization of
the content. The <i>id</i>, <i>type</i>, and <i>options</i> arguments are the DIME
id, type, and options, respectively. The callback should return <i>handle</i>,
or another pointer value which will be passed as a handle to <i>fdimeread</i>
and <i>fdimereadclose</i>. The callback should return NULL and set
<i>soap</i><tt>-&gt;</tt><i>error</i> when an error occurred. The callback should return
NULL (and not set <i>soap</i><tt>-&gt;</tt><i>error</i>) when this particular DIME
attachment is not to be streamed.
</td></tr>
<tr><td width="602"><i>size_t (*soap.fdimeread)(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>char</b>&nbsp;*buf, size_t len)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment sender to read more data from a
(binary) data source for streaming into the output stream. The <i>handle</i>
contains the value returned by the <i>fdimereadopen</i> callback. The <i>buf</i>
argument is the buffer of length <i>len</i> into which a chunk of data should be
stored. The actual amount of data stored in the buffer may be less than
<i>len</i> and this amount should be returned by the application. A return value
of 0 indicates an error (the callback may set <i>soap</i><tt>-&gt;</tt><i>errnum</i> to errno).
The <i>__size</i> field of the attachment
struct/class should have been set by the application prior to the serialization
of the content. The value of <i>__size</i> indicates the total size of the
content to be transmitted. When the <i>__size</i> is zero then DIME chunked
transfers can be used under certain circumstances to stream content without
prior determination of attachment size, see Section&nbsp;<a href="#sec:dimechunking">14.5</a> below.
</td></tr>
<tr><td width="602"><i><b>void</b>(*soap.fdimereadclose)(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment sender at the end of the
streaming process to close the data source. The <i>handle</i> contains the
value returned by the <i>fdimereadopen</i> callback. The <i>fdimewriteclose</i>
callback is called after successfully transmitting the data or when an error
occurred.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;*(*soap.fdimewriteopen)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*options)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment receiver to start writing an
inbound DIME attachment to an application's data store. The content is streamed
into an application data store through multiple <i>fdimewrite</i> calls from the
gSOAP attachment receiver. The <i>id</i>, <i>type</i>, and <i>options</i>
arguments are the DIME id, type, and options respectively. The callback should
return a handle which is passed to the <i>fdimewrite</i> and
<i>fdimewriteclose</i> callbacks. The <i>__ptr</i> field of the attachment
struct/class is set to the value of this handle. The <i>__size</i> field is set
to the total size of the attachment after receiving the entire content. The size
is unknown in advance because DIME attachments may be chunked.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fdimewrite)(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>const</b>&nbsp;<b>char</b>&nbsp;*buf, size_t len)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment receiver to write part of
an inbound DIME attachment to an application's data store.
The <i>handle</i>
contains the value returned by the <i>fdimewriteopen</i> callback. The <i>buf</i>
argument contains the data of length <i>len</i>.
The callback should return a gSOAP error code (e.g.&nbsp;<i>SOAP_OK</i> when no error occurred).
</td></tr>
<tr><td width="602"><i><b>void</b>(*soap.fdimewriteclose)(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle)</i> </td></tr>
<tr><td width="602">Called by the gSOAP run-time DIME attachment receiver at the end of the
streaming process to close the data store. The <i>fdimewriteclose</i> callback
is called after successfully receiving the data or when an error occurred. The
<i>handle</i> contains the value returned by the <i>fdimewriteopen</i> callback.
</td></tr></table>
</td></tr></table><br></span>
In addition, a <i><b>void</b>*user</i> field in the <i><b>struct</b>&nbsp;soap</i> data structure
is available to pass user-defined data to the callbacks. This way, you can set
<i>soap.user</i> to point to application data that the callbacks need such as a
file name for example.
<div class="p"><!----></div>
The following example illustrates the client-side initialization of an image
attachment struct to stream a file into a DIME attachment:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;xsd__base64Binary image; <br />
&nbsp;&nbsp;&nbsp;FILE *fd; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;stat sb; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!fstat(fileno(fd), &amp;sb) &amp;&amp; sb.st_size &gt; 0) <br />
&nbsp;&nbsp;&nbsp;{ // because we can get the length of the file, we can stream it <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.fdimereadopen = dime_read_open; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.fdimereadclose = dime_read_close; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.fdimeread = dime_read; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.__ptr = (<b>unsigned</b>&nbsp;<b>char</b>*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.__size = sb.st_size; // must set size <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ // don't know the size, so buffer it <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t i; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;c; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.__ptr = (<b>unsigned</b>&nbsp;<b>char</b>*)soap_malloc(&amp;soap, MAX_FILE_SIZE); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; MAX_FILE_SIZE; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;((c = fgetc(fd)) == EOF) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.__ptr[i] = c; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(fd); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.__size = i; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;image.type = "image/jpeg"; <br />
&nbsp;&nbsp;&nbsp;image.options = soap_dime_option(&amp;soap, 0, "My picture"); <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method(&amp;soap, ...); <br />
&nbsp;&nbsp;&nbsp;... <br />
} <br />
<b>void</b>&nbsp;*dime_read_open(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*options) <br />
{ <b>return</b>&nbsp;handle; <br />
} <br />
<b>void</b>&nbsp;dime_read_close(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle) <br />
{ fclose((FILE*)handle); <br />
} <br />
size_t dime_read(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>char</b>&nbsp;*buf, size_t len) <br />
{ <b>return</b>&nbsp;fread(buf, 1, len, (FILE*)handle); <br />
}
</td></tr></table><br></i>
The following example illustrates the streaming of a DIME attachment into a file by a client:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap.fdimewriteopen = dime_write_open; <br />
&nbsp;&nbsp;&nbsp;soap.fdimewriteclose = dime_write_close; <br />
&nbsp;&nbsp;&nbsp;soap.fdimewrite = dime_write; <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__method(&amp;soap, ...); <br />
&nbsp;&nbsp;&nbsp;... <br />
} <br />
<b>void</b>&nbsp;*dime_write_open(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*id, <b>const</b>&nbsp;<b>char</b>&nbsp;*type, <b>const</b>&nbsp;<b>char</b>&nbsp;*options) <br />
{ <br />
&nbsp;&nbsp;&nbsp;FILE *handle = fopen("somefile", "wb"); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!handle) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>error = SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>errnum = errno; // get reason <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;(<b>void</b>*)handle; <br />
} <br />
<b>void</b>&nbsp;dime_write_close(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle) <br />
{ fclose((FILE*)handle); <br />
} <br />
<b>int</b>&nbsp;dime_write(<b>struct</b>&nbsp;soap *soap, <b>void</b>&nbsp;*handle, <b>const</b>&nbsp;<b>char</b>&nbsp;*buf, size_t len) <br />
{ <br />
&nbsp;&nbsp;&nbsp;size_t nwritten; <br />
&nbsp;&nbsp;&nbsp;<b>while</b>&nbsp;(len) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nwritten = fwrite(buf, 1, len, (FILE*)handle); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!nwritten) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>errnum = errno; // get reason <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;len -= nwritten; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf += nwritten; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
Note that compression can be used with DIME to compress the entire message.
However, compression requires buffering to determine the HTTP content length
header, which cancels the benefits of streaming DIME. To avoid this, you should
use chunked HTTP (with the output-mode <i>SOAP_IO_CHUNK</i> flag) with
compression and streaming DIME. At the server side, when you set
<i>SOAP_IO_CHUNK</i> before calling <i>soap_serve</i>, gSOAP will
automatically revert to buffering (<i>SOAP_IO_STORE</i> flag is set). You can
check this flag with <i>(soap-&#62;omode &amp; SOAP_IO) == SOAP_IO_CHUNK</i> to see
if the client accepts chunking. More information about streaming chunked DIME
can be found in Section&nbsp;<a href="#sec:dimechunking">14.5</a>.
<div class="p"><!----></div>
<font color="#FF0000"><b>C</b></font>aution: The <i>options</i> field is a DIME-specific data structure,
consisting of a 4 byte header containing the option type info (hi byte, lo
byte), option string length (hi byte, lo byte), followed by a non-<tt>'\0'</tt>
terminated string. The gSOAP DIME handler recognizes one option at most.
<div class="p"><!----></div>
<h3><a name="tth_sEc14.5">
14.5</a>&nbsp;&nbsp;<font color="#0000FF">Streaming Chunked DIME</font></h3><a name="sec:dimechunking">
</a>
<div class="p"><!----></div>
gSOAP automatically handles inbound chunked DIME attachments (streaming or
non-streaming). To transmit outbound DIME attachments, the attachment sizes
MUST be determined in advance to calculate HTTP message length required to
stream DIME over HTTP. However, gSOAP also supports the transmission of
outbound chunked DIME attachments without prior determination of DIME
attachment sizes when certain conditions are met. These conditions require
either non-HTTP transport (use the output-mode <i>SOAP_ENC_XML</i> flag), or
chunked HTTP transport (use the output-mode <i>SOAP_IO_CHUNK</i> flag). You
can also use the <i>SOAP_IO_STORE</i> flag (which is also used automatically
with compression to determine the HTTP content length header) but that cancels
the benefits of streaming DIME.
<div class="p"><!----></div>
To stream chunked DIME, set the <i>__size</i> field of an attachment to zero
and enable HTTP chunking. The DIME <i>fdimeread</i> callback then fetches data
in chunks and it is important to fill the entire buffer unless the end of the
data has been reached and the last chunk is to be send. That is,
<i>fdimeread</i> should return the value of the last <i>len</i> parameter and
fill the entire buffer <i>buf</i> for all chunks except the last.
<div class="p"><!----></div>
<h3><a name="tth_sEc14.6">
14.6</a>&nbsp;&nbsp;<font color="#0000FF">WSDL Bindings for DIME Attachments</font></h3>
<div class="p"><!----></div>
The <i>wsdl2h</i> WSDL parser recognizes DIME attachments and produces an annotated header file. Both open and closed layouts are supported for transmitting DIME attachments. For closed formats, all DIME attachments must be referenced from the SOAP message, e.g.&nbsp;using hrefs with SOAP encoding and using the application-specific reference attribute included in the <i>base64Binary</i> struct/class for doc/lit.
<div class="p"><!----></div>
As of this writing, the gSOAP compiler <i>soapcpp2</i> does not yet produce a WSDL with DIME extensions.
<div class="p"><!----></div>
<h2><a name="tth_sEc15">
15</a>&nbsp;&nbsp;<font color="#0000FF">MTOM Attachments</font></h2><a name="sec:MTOM">
</a>
<div class="p"><!----></div>
MTOM (Message Transmission Optimization Mechanism) is a relatively new format
for transmitting attachments with SOAP messages (see
<a href="http://www.w3.org/TR/soap12-mtom"><tt>http://www.w3.org/TR/soap12-mtom</tt></a>). MTOM is a W3C working draft as of this
writing. MTOM attachments are essentially MIME attachments with standardized
mechanisms for cross referencing attachments from the SOAP body, which is
absent in (plain) MIME attachments and optional with DIME attachments.
<div class="p"><!----></div>
Unlike the name suggests, the speed by which attached data is transmitted is
not increased compared to MIME, DIME, or even XML encoded base64 data (at least
the performance differences in gSOAP will be small). The advantage of the
format is the standardized attachment reference mechanism, which should improve
interoperability.
<div class="p"><!----></div>
The MTOM specification mandates SOAP 1.2 and the use of the XOP namespace. The
XOP Include element <tt>xop:Include</tt> is used to reference attachment(s) from the SOAP message body.
<div class="p"><!----></div>
Because references from within the SOAP message body to attachments are
mandatory with MTOM, the implementation of the serialization and deserialization of MTOM
MIME attachments in gSOAP uses the extended binary type comparable to DIME support in gSOAP. This binary type is predefined in the <i>import/xop.h</i> file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap xop schema import: http://www.w3.org/2004/08/xop/include <br />
<b>struct</b>&nbsp;_xop__Include <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>char</b>&nbsp;*__ptr; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*id; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*type; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*options; <br />
}; <br />
<b>typedef</b>&nbsp;<b>struct</b>&nbsp;_xop__Include _xop__Include;
</td></tr></table><br></i>
The additional <i>id</i>, <i>type</i>, and <i>option</i> fields
enable MTOM attachments for the data pointed to by <i>__ptr</i> of size <i>__size</i>. The process for sending and receiving MTOM XOP
attachments is fully automated. Streaming techniques however, such as for DIME
are not (yet) available.
The <i>id</i> field references the attachment (typically a content id CID or UUID). When set to NULL, gSOAP assigns a unique CID. The <i>type</i>
field specifies the required MIME type of the binary data, and the optional
<i>options</i> field can be used to piggy-back descriptive text with an attachment. The order of the
declaration of the fields is significant.
<div class="p"><!----></div>
You can explicitly import the <i>xop.h</i> in your header file to use the MTOM attachments in your service, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import &#239;mport/soap12.h" <br />
/* alternatively, without the import above, use: <br />
//gsoap SOAP-ENV schema namespace: http://www.w3.org/2003/05/soap-envelope <br />
//gsoap SOAP-ENC schema namespace: http://www.w3.org/2003/05/soap-encoding <br />
*/ <br />
#import &#239;mport/xop.h" <br />
#import &#239;mport/xmlmime.h" <br />
<br />
//gsoap x schema namespace: http://my.first.mtom.net <br />
<b>struct</b>&nbsp;x__myData <br />
{ <br />
&nbsp;&nbsp;&nbsp;_xop__Include xop__Include; // attachment <br />
&nbsp;&nbsp;&nbsp;@<b>char</b>&nbsp;*xmlmime__contentType; // and its contentType <br />
}; <br />
<b>int</b>&nbsp;x__myMTOMtest(<b>struct</b>&nbsp;x__myData *in, <b>struct</b>&nbsp;x__myData *out);
</td></tr></table><br></i>
As you can see, there is really no difference between the specification of MTOM
and DIME attachments in a gSOAP header file. Except that you MUST use SOAP 1.2
and the <i>xop__Include</i> element.
<div class="p"><!----></div>
When an instance of <i>x__myDataType</i> is serialized and either or both the
<i>id</i> and <i>type</i> fields are non-NULL, the data is transmitted as MTOM
MIME attachment if the <i>SOAP_ENC_MTOM</i> flag is set in the gSOAP's soap
struct context:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap *soap = soap_new1(SOAP_ENC_MTOM);
</td></tr></table><br></i>
Without this flag, the attachments will be transmitted in DIME format
(Section&nbsp;<a href="#sec:DIME">14</a>). If your current clients and services are based on
non-streaming DIME attachments using the SOAP body reference mechanism (thus,
without using the <i>soap_set_dime_attachment</i> function) or plain base64
binary XML data elements, it is very easy to adopt MTOM by renaming the binary types to <i>xop__Include</i> and using the
<i>SOAP_ENC_MTOM</i> flag with the SOAP 1.2 namespace.
<div class="p"><!----></div>
<h3><a name="tth_sEc15.1">
15.1</a>&nbsp;&nbsp;<font color="#0000FF">Generating MultipartRelated MIME Attachment Bindings in WSDL</font></h3><a name="sec:MIMEWSDL">
</a>
<div class="p"><!----></div>
To generate multipartRelated bindings in the WSDL file, use the <i>//gsoap
... service method-mime-type</i> directive (see also Section&nbsp;<a href="#sec:directives">18.2</a>. The
directive can be repeated for each attachment you want to associate with a
method's request and response messages.
<div class="p"><!----></div>
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import &#239;mport/soap12.h" <br />
#import &#239;mport/xop.h" <br />
#import &#239;mport/xmlmime.h" <br />
<br />
//gsoap x schema namespace: http://my.first.mtom.net <br />
<b>struct</b>&nbsp;x__myData <br />
{ <br />
&nbsp;&nbsp;&nbsp;_xop__Include xop__Include; // attachment <br />
&nbsp;&nbsp;&nbsp;@<b>char</b>&nbsp;*xmlmime__contentType; // and its contentType <br />
}; <br />
//gsoap x service method-mime-type: myMTOMtest text/xml <br />
<b>int</b>&nbsp;x__myMTOMtest(<b>struct</b>&nbsp;x__myData *in, <b>struct</b>&nbsp;x__myData *out);
</td></tr></table><br></i>
The <i>//gsoap x service method-mime-type</i> directive indicates that this
operation accepts <tt>text/xml</tt> MIME attachments. See the SOAP-with-Attachment
specification for the MIME types to use (for example, <tt>*/*</tt> is a wildcard).
If the operation has more than one attachment, just repeat this directive for
each attachment you want to bind to the operation.
<div class="p"><!----></div>
To bind attachments only to the request message of an operation, use
<i>//gsoap x service method-input-mime-type</i>. Similarly, to bind attachments
only to the response message of an operation, use <i>//gsoap x service
method-ouput-mime-type</i>.
<div class="p"><!----></div>
The <i>wsdl2h</i> WSDL parser recognizes MIME attachments and produces an
annotated header file. However, the ordering of MIME parts in the
multipartRelated elements is not reflected in the header file. Application
developers should adhere the standards and ensure that multipart/related
attachments are transmitted in compliance with the WSDL operation declarations.
<div class="p"><!----></div>
<h3><a name="tth_sEc15.2">
15.2</a>&nbsp;&nbsp;<font color="#0000FF">Sending and Receiving MTOM Attachments</font></h3>
<div class="p"><!----></div>
A receiver must be told to recognize MTOM attachments by setting
the <i>SOAP_ENC_MTOM</i> flag of the gSOAP context. Otherwise, the regular MIME
attachment mechanism will be used to store attachments and in this process the references from the SOAP message body to the attachments are lost.
<div class="p"><!----></div>
When using <i>wsdl2h</i> to build clients and/or services, you should use the <i>typemap.dat</i> file included in the distribution package. The <i>typemap.dat</i> file defines the XOP namespace and XML MIME namespaces as imported namespaces:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
xop = &lt; http://www.w3.org/2004/08/xop/include &gt; <br />
xmime = &lt; http://www.w3.org/2004/06/xmlmime &gt; <br />
xmlmime = &lt; http://www.w3.org/2004/11/xmlmime &gt;
</td></tr></table><br></i>
The <i>wsdl2h</i> tool uses the <i>typemap.dat</i> file (see also option -t) to
convert WSDL into a gSOAP header file. In this case we don't want the
<i>wsdl2h</i> tool to read the XOP schema and translate it, since we have a
special <i>_xop__Include</i> element already defined in <i>xop.h</i>.
Therefore, the above bindings will not translate the XOP and XML MIME schemas,
but instead generates <i>#import</i> statements:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import "xop.h" <br />
#import "xmlmime.h"
</td></tr></table><br></i>
The <i>#import</i> statements are only added for those namespaces that are
actually used by the service.
<div class="p"><!----></div>
Let's take a look at an example.
The <i>wsdl2h</i> importer generates a header file with <i>#import "xop.h"</i> from a WSDL that references XOP, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import "xop.h" <br />
#import "xmlmime.h" <br />
<b>struct</b>&nbsp;ns__Data <br />
{ <br />
&nbsp;&nbsp;&nbsp;_xop__Include xop__Include; <br />
&nbsp;&nbsp;&nbsp;@<b>char</b>&nbsp;*xmlmime__contentType; <br />
};
</td></tr></table><br></i>
Suppose the WSDL defines an operation:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__echoData(<b>struct</b>&nbsp;ns__Data *in, <b>struct</b>&nbsp;ns__Data *out);
</td></tr></table><br></i>
After generating the stubs/proxies with the <i>soapcpp2</i> compiler, we can invoke the stub at the client side with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap *soap = soap_new1(SOAP_ENC_MTOM); <br />
<b>struct</b>&nbsp;ns__Data data; <br />
data.xop__Include.__ptr = (<b>unsigned</b>&nbsp;<b>char</b>*)"<tt>&lt;b&gt;Hello&nbsp;world!&lt;/b&gt;</tt>"; <br />
data.xop__Include.__size = 20; <br />
data.xop__Include.id = NULL; // CID automatically generated by gSOAP engine <br />
data.xop__Include.type = "text/html"; // MIME type <br />
data.xop__Include.options = NULL; // no descriptive info added <br />
data.xmlmime__contentType = "text/html"; // MIME type <br />
<b>if</b>&nbsp;(soap_call_ns__echoData(soap, endpoint, action, &amp;data, &amp;data))
&nbsp;&nbsp;&nbsp;soap_print_fault(soap, stderr);
<b>else</b><br />
&nbsp;&nbsp;&nbsp;printf("<tt>Got&nbsp;data\n</tt>"); <br />
soap_destroy(soap); // remove deserialized class instances (C++ only) <br />
soap_end(soap); // remove temporary and deserialized data <br />
soap_done(soap); // detach <br />
free(soap);
</td></tr></table><br></i>
Note that the <i>xop__Include.type</i> field must be set to transmit MTOM attachments, otherwise plain base64 XML will be used.
<div class="p"><!----></div>
At the server side, we can implement an operation handler that just copies the input data to output to implement the echo operation as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__echoData(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;ns__Data *in, <b>struct</b>&nbsp;ns__data *out) <br />
{ <br />
&nbsp;&nbsp;&nbsp;*out = *in; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
The server must use the <i>SOAP_ENC_MTOM</i> flag to initialize the soap struct to receive and send MTOM attachments.
<div class="p"><!----></div>
<h2><a name="tth_sEc16">
16</a>&nbsp;&nbsp;<font color="#0000FF">XML Validation</font></h2><a name="sec:validation">
</a>
<div class="p"><!----></div>
The gSOAP XML parser applies basic rules to validate content. However,
occurrence constraints are not automatically verified unless explicitly
indicated. This helps to avoid interoperability problems with toolkits that do
not strictly enforce validation rules. In addition, we cannot always use strict
validation for SOAP RPC encoded messages, since SOAP RPC encoding adopts a very
loose serialization format.
<div class="p"><!----></div>
Validation constraints are checked by gSOAP with the <i>SOAP_XML_STRICT</i> input mode
flag set, e.g.&nbsp;with <i>soap_set_imode(soap, SOAP_XML_STRICT)</i> or
<i>soap_new(SOAP_XML_STRICT)</i>, see Section&nbsp;<a href="#sec:flags">8.12</a> for a complete list
of flags.
<div class="p"><!----></div>
<h3><a name="tth_sEc16.1">
16.1</a>&nbsp;&nbsp;<font color="#0000FF">Occurrence Constraints</font></h3>
<div class="p"><!----></div>
<h4><a name="tth_sEc16.1.1">
16.1.1</a>&nbsp;&nbsp;<font color="#0000FF">Elements with minOccurs and maxOccurs Restrictions</font></h4>
<div class="p"><!----></div>
To force the validation of minOccurs and maxOccurs contraints the <i>SOAP_XML_STRICT</i> input mode flag must be set.
The minOccurs and maxOccurs constraints are specified for fields of a struct and members of a class in a header file using the following syntax:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<u><span class="roman">Type</span></u> <u><span class="roman">fieldname</span></u> <font size="+1"><span class="roman">[</span></font><u><span class="roman">minOccurs</span></u><font size="+1"><span class="roman">[</span></font>:<u><span class="roman">maxOccurs</span></u><font size="+1"><span class="roman">]</span></font><font size="+1"><span class="roman">]</span></font> <font size="+1"><span class="roman">[</span></font>= value<font size="+1"><span class="roman">]</span></font>
</td></tr></table><br></i>
The minOccurs and maxOccurs values must be integer literals. A default value can be provided when minOccurs is zero. Default values must be primitive types, integer, float, string, etc. By default the minOccurs constraint is zero.
<div class="p"><!----></div>
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__MyRecord <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;n = 5; // element with default value 5, minOccurs=0, maxOccurs=1<br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;m 1; // element with minOccurs=1 <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;__size 0:10; // sequence &lt;item&#62; with minOccurs=0, maxOccurs=10<br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;*item; <br />
&nbsp;&nbsp;&nbsp;std::vector<tt>&lt;</tt>double<tt>&gt;</tt> nums 2; // sequence &lt;nums&#62; with minOccurs=2, maxOccurs=unbounded <br />
}; <br />
<b>struct</b>&nbsp;arrayOfint <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;*__ptr 1:100; // minOccurs=1, maxOccurs=100 <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;size; <br />
};
</td></tr></table><br></i>
Pointer-based struct fields and class members are allowed to be nillable when minOccurs is zero.
<div class="p"><!----></div>
<h4><a name="tth_sEc16.1.2">
16.1.2</a>&nbsp;&nbsp;<font color="#0000FF">Required and Prohibited Attributes</font></h4>
<div class="p"><!----></div>
Similar to the minOccurs and maxOccurs annotations defined in the previous
section, attributes in a struct or class can be annotated with occurrence
constraints to make them optional (0), required (1), or prohibited (0:0).
Default values can be assigned to optional attributes.
<div class="p"><!----></div>
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;ns__MyRecord <br />
{ <br />
&nbsp;&nbsp;&nbsp;@<b>int</b>&nbsp;m 1; // required attribute (occurs at least once) <br />
&nbsp;&nbsp;&nbsp;@<b>int</b>&nbsp;n = 5; // optional attribute with default value 5<br />
&nbsp;&nbsp;&nbsp;@<b>int</b>&nbsp;o 0; // optional attribute (may or may not occur) <br />
&nbsp;&nbsp;&nbsp;@<b>int</b>&nbsp;p 0:0; // prohibited attribute <br />
};
</td></tr></table><br></i>
Remember to set the <i>SOAP_XML_STRICT</i> input mode flag to
enable the validation of attribute occurrence constraints.
<div class="p"><!----></div>
<h4><a name="tth_sEc16.1.3">
16.1.3</a>&nbsp;&nbsp;<font color="#0000FF">Data Length Restrictions</font></h4>
<div class="p"><!----></div>
A schema simpleType is defined with a <i><b>typedef</b></i> by taking a base primitive to defined a derived simpleType. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>int</b>&nbsp;time__seconds;
</td></tr></table><br></i>
This defines the following schema type in <i>time.xsd</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;simpleType name="seconds&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;restriction base="xsd:int"/&#62; <br />
&lt;/simpleType&#62;
</td></tr></table><br></tt>
A complexType with simpleContent is defined with a wrapper struct/class:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;time__date <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*__item; // some custom format date (restriction of string) <br />
&nbsp;&nbsp;&nbsp;@<b>enum</b>&nbsp;time__zone { EST, GMT, ... } zone; <br />
}
</td></tr></table><br></i>
This defines the following schema type in <i>time.xsd</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;complexType name="date&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;simpleContent&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;extension base="xsd:string"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/simpleContent&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;attribute name="zone" type="time:zone" use="optional"/&#62; <br />
&lt;/complexType&#62;
&lt;simpleType name="zone&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;restriction base="xsd:string&#187; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;enumeration value="EST"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;enumeration value="GMT"/&#62; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;&lt;/restriction&#62; <br />
&lt;/simpleType&#62;
</td></tr></table><br></tt>
Data value length constraints of simpleTypes and complexTypes with simpleContent are defined as follows.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*ns__string256 0:256; // simpleType restriction of string with max length 256 characters <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*ns__string10 10:10; // simpleType restriction of string with length of 10 characters <br />
<b>typedef</b>&nbsp;std::string *ns__string8 8; // simpleType restriction of string with at least 8 characters <br />
<b>struct</b>&nbsp;ns__data <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*__item :256; // simpleContent with at most 256 characters <br />
&nbsp;&nbsp;&nbsp;@<b>char</b>&nbsp;*name 1; // required name attribute <br />
};
<b>struct</b>&nbsp;time__date <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*__item :100;
&nbsp;&nbsp;&nbsp;@<b>enum</b>&nbsp;time__zone { EST, GMT, ... } zone = GMT; <br />
}
</td></tr></table><br></i>
Remember to set the <i>SOAP_XML_STRICT</i> input mode flag to
enable the validation of value length constraints.
<div class="p"><!----></div>
<h3><a name="tth_sEc16.2">
16.2</a>&nbsp;&nbsp;<font color="#0000FF">Other Constraints</font></h3>
<div class="p"><!----></div>
To associate a pattern with a simpleType, you can define a simpleType with a <i><b>typedef</b></i> and a pattern string:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>int</b>&nbsp;time__second "[1-5]?[0-9] - 60";
</td></tr></table><br></i>
This defines the following schema type in <i>time.xsd</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
&lt;simpleType name="second&#187; <br />
&nbsp;&nbsp;&nbsp;&lt;restriction base="xsd:int&#187; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pattern value="[1-5]?[0-9] - 60"/&#62; <br />
&nbsp;&nbsp;&nbsp;&lt;/restriction base="xsd:int"/&#62; <br />
&lt;/simpleType&#62;
</td></tr></table><br></tt>
The pattern string MUST contain a valid regular expression.
<div class="p"><!----></div>
Patterns are currently not checked in the validation process.
<div class="p"><!----></div>
<h2><a name="tth_sEc17">
17</a>&nbsp;&nbsp;<font color="#0000FF">SOAP-over-UDP</font></h2><a name="sec:udp">
</a>
<div class="p"><!----></div>
UDP is a simple, unreliable datagram protocol: UDP sockets are connectionless.
UDP address formats are identical to those used by TCP. In particular UDP
provides a port identifier in addition to the normal Internet address format.
The UDP port space is separate from the TCP port space (i.e. a UDP port may not
be "connected" to a TCP port). In addition broadcast packets may be sent
(assuming the underlying network supports this) by using a reserved "broadcast
address"; this address is network interface dependent.
<div class="p"><!----></div>
To enable SOAP-over-UDP with gSOAP, <i>stdsoap2.c</i> and <i>stdsoap2.cpp</i>
MUST be compiled with <i>-DWITH_UDP</i> prior to linking with your application.
<div class="p"><!----></div>
Client-side messages with SOAP-over-UDP endpoint URLs
(<i>soap.udp://...</i>) will be automatically transmitted as datagrams.
Server-side applications should set the <i>SOAP_IO_UDP</i> mode flag to
accept UDP requests, e.g. using <i>soap_init1</i> or <i>soap_set_mode</i>.
<div class="p"><!----></div>
The maximum message length for datagram packets is restricted by the buffer
size <i>SOAP_BUFLEN</i>, which is 65536 by default, unless
compiled with <i>WITH_LEAN</i> to support small-scale embedded systems.
For UDP transport <i>SOAP_BUFLEN</i> must not exceed the maximum UDP packet size
65536 (the size of datagram messages is constrained by the
UDP packet size 2<sup>16</sup>=65536 as per UDP standard). You can use gzip compression
to reduce the message size, but note that compressed SOAP-over-UDP is a
gSOAP-specific feature because it is not part of the SOAP-over-UDP
specification.
<div class="p"><!----></div>
The SOAP-over-UDP specification relies on WS-Addressing. The <i>wsa.h</i>
file in the <i>import</i> directory defines the WS-Addressing elements for
client and server applications.
<div class="p"><!----></div>
The gSOAP implementation conforms to the SOAP-over-UDP requirements:
<ul>
<li> SOAP-over-UDP server endpoint URL format: <i>soap.udp://host:port/path</i>
<div class="p"><!----></div>
</li>
<li> Support one-way message-exchange pattern (MEP) where a SOAP envelope is
carried in a user datagram.
<div class="p"><!----></div>
</li>
<li> Support request-response message-exchange pattern (MEP) where SOAP envelopes
are carried in user datagrams.
<div class="p"><!----></div>
</li>
<li> Support multicast transmission of SOAP envelopes carried in user datagrams.
<div class="p"><!----></div>
</li>
<li> Support both SOAP 1.1 and SOAP 1.2 envelopes.
<div class="p"><!----></div>
</li>
</ul>
The following additional features are also available, but are not supported by the SOAP-over-UDP specification:
<ul>
<li> Zlib/gzip message compression (compile <i>-DWITH_GZIP</i>).
<div class="p"><!----></div>
</li>
<li> SOAP with DIME attachments over UDP.
<div class="p"><!----></div>
</li>
<li> SOAP with MIME attachments (SwA) over UDP.
<div class="p"><!----></div>
</li>
<li> Support for IPv6 (compile <i>-DWITH_IPV6</i>)
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h3><a name="tth_sEc17.1">
17.1</a>&nbsp;&nbsp;<font color="#0000FF">Using WS-Addressing with SOAP-over-UDP</font></h3><a name="sec:udp.h">
</a>
<div class="p"><!----></div>
A SOAP-over-UDP application MUST use WS-Addressing to control message delivery
as per SOAP-over-UDP specification.
<div class="p"><!----></div>
The <i>wsa.h</i> file in the <i>import</i> directory defines the
WS-Addressing elements. To include the WS-Addressing elements in the SOAP
Header for messaging, a <i><b>struct</b>&nbsp;SOAP_ENV__Header</i> structure must be
defined in your header file with the appropriate WS-Addressing elements.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#import "wsa.h" <br />
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__MessageID wsa__MessageID 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__RelatesTo *wsa__RelatesTo 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__From *wsa__From 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__ReplyTo *wsa__ReplyTo 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__FaultTo *wsa__FaultTo 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__To wsa__To 0; <br />
&nbsp;&nbsp;&nbsp;mustUnderstand _wsa__Action wsa__Action 0; <br />
};
</td></tr></table><br></i>
We also included a <i>//gsoap wsa schema import</i> directive in the <i>wsa.h</i> file to enable the generation of WSDL
specifications that import (instead of includes) the WS-Addressing elements.
Note that the <i>//gsoapopt w</i> directive must not be present in your header file to enable WSDL generation.
<div class="p"><!----></div>
One-way SOAP-over-UDP messages (see Section&nbsp;<a href="#sec:oneway1">7.3</a>) should be
declared to include the <i>wsa:MessageID</i>, <i>wsa:To</i>, and <i>wsa:Action</i>
elements in the SOAP Header of the request message as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-header-part: sendString wsa__MessageID <br />
//gsoap ns service method-header-part: sendString wsa__To <br />
//gsoap ns service method-header-part: sendString wsa__Action <br />
<b>int</b>&nbsp;ns__sendString(<b>char</b>&nbsp;*str, <b>void</b>);
</td></tr></table><br></i>
Request-response SOAP-over-UDP messages should be declared to include the
<i>wsa:MessageID</i>, <i>wsa:To</i>, <i>wsa:Action</i>, and <i>wsa:ReplyTo</i>
elements in the SOAP Header of the request message, and the the
<i>wsa:MessageID</i>, <i>wsa:To</i>, <i>wsa:Action</i>, and <i>wsa:RelatesTo</i>
elements in the SOAP Header of the response message:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-header-part: echoString wsa__MessageID <br />
//gsoap ns service method-header-part: echoString wsa__To <br />
//gsoap ns service method-header-part: echoString wsa__Action <br />
//gsoap ns service method-input-header-part: sendString wsa__ReplyTo <br />
//gsoap ns service method-output-header-part: echoString wsa__RelatesTo <br />
<b>int</b>&nbsp;ns__echoString(<b>char</b>&nbsp;*str, <b>char</b>&nbsp;**res);
</td></tr></table><br></i>
For the content requirements of these elements, please consult the
SOAP-over-UDP specification and/or read the next sections explaining
SOAP-over-UDP unicast, multicast, one-way, and request-response client and
server applications.
<div class="p"><!----></div>
<h3><a name="tth_sEc17.2">
17.2</a>&nbsp;&nbsp;<font color="#0000FF">Client-side One-way Unicast</font></h3>
<div class="p"><!----></div>
This example assumes that the gSOAP header file includes the SOAP Header with
WS-Addressing elements and the <i>ns__sendString</i> function discussed in
Section&nbsp;<a href="#sec:udp.h">17.1</a>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
<b>struct</b>&nbsp;SOAP_ENV__Header header; // the SOAP Header <br />
soap_init(&amp;soap); <br />
soap.send_timeout = 1; // 1s timeout <br />
soap_default_SOAP_ENV__Header(&amp;soap, &amp;header); // init SOAP Header <br />
header.wsa__MessageID = "<i>message ID</i>"; <br />
header.wsa__To = "<i>server URL</i>"; <br />
header.wsa__Action = "<i>server action</i>"; <br />
soap.header = &amp;header; // bind the SOAP Header for transport <br />
// Send the message over UDP: <br />
<b>if</b>&nbsp;(soap_send_ns__echoString(&amp;soap, "soap.udp://...", NULL, "hello world!")) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // report error <br />
soap_end(&amp;soap); // cleanup <br />
soap_destroy(&amp;soap); // cleanup <br />
soap_done(&amp;soap); // close connection (should not use soap struct after this)
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc17.3">
17.3</a>&nbsp;&nbsp;<font color="#0000FF">Client-side One-way Multicast</font></h3>
<div class="p"><!----></div>
This example is similar to the one-way unicast example discussed above, but
uses a broadcast address and the <i>SO_BROADCAST</i> socket option:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
<b>struct</b>&nbsp;SOAP_ENV__Header header; // the SOAP Header <br />
soap_init(&amp;soap); <br />
soap.send_timeout = 1; // 1s timeout <br />
soap.connect_flags = SO_BROADCAST; // required for broadcast <br />
soap_default_SOAP_ENV__Header(&amp;soap, &amp;header); // init SOAP Header <br />
header.wsa__MessageID = "<i>message ID</i>"; <br />
header.wsa__To = "<i>server URL</i>"; <br />
header.wsa__Action = "<i>server action</i>"; <br />
soap.header = &amp;header; // bind the SOAP Header for transport <br />
// Send the message over UDP to a broadcast address: <br />
<b>if</b>&nbsp;(soap_send_ns__echoString(&amp;soap, "soap.udp://...", NULL, "hello world!")) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // report error <br />
soap_end(&amp;soap); // cleanup <br />
soap_destroy(&amp;soap); // cleanup <br />
soap_done(&amp;soap); // close connection (should not use soap struct after this)
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc17.4">
17.4</a>&nbsp;&nbsp;<font color="#0000FF">Client-side Request-Response Unicast</font></h3>
<div class="p"><!----></div>
This example assumes that the gSOAP header file includes the SOAP Header with
WS-Addressing elements and the <i>ns__echoString</i> function discussed in
Section&nbsp;<a href="#sec:udp.h">17.1</a>
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
<b>struct</b>&nbsp;SOAP_ENV__Header header; // the SOAP Header <br />
<b>struct</b>&nbsp;wsa__EndpointReferenceType replyTo; // (anonymous) reply address <br />
<b>char</b>&nbsp;*res; // server response <br />
soap_init(&amp;soap); <br />
soap.send_timeout = 1; // 1s timeout <br />
soap.recv_timeout = 1; // 1s timeout <br />
soap_default_SOAP_ENV__Header(&amp;soap, &amp;header); // init SOAP Header <br />
soap_default_wsa__EndpointReferenceType(&amp;soap, &amp;replyTo); // init reply address <br />
replyTo.Address = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"; <br />
header.wsa__MessageID = "<i>message ID</i>"; <br />
header.wsa__To = "<i>server URL</i>"; <br />
header.wsa__Action = "<i>server action</i>"; <br />
header.wsa__ReplyTo = &amp;replyTo; <br />
soap.header = &amp;header; // bind the SOAP Header for transport <br />
// Send and receive messages over UDP: <br />
<b>if</b>&nbsp;(soap_call_ns__echoString(&amp;soap, "soap.udp://...", NULL, "hello world!", &amp;res)) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error == SOAP_EOF &amp;&amp; soap.errnum == 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Timeout: no response from server (message already delivered?) <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
} <br />
<b>else</b><br />
&nbsp;&nbsp;&nbsp;// UDP server response is stored in 'res' <br />
// check SOAP header received, if applicable <br />
check_header(&amp;soap.header); <br />
soap_end(&amp;soap); // cleanup <br />
soap_destroy(&amp;soap); // cleanup <br />
soap_done(&amp;soap); // close connection (should not use soap struct after this)
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc17.5">
17.5</a>&nbsp;&nbsp;<font color="#0000FF">Client-side Request-Response Multicast</font></h3>
<div class="p"><!----></div>
This example is similar to the request-response unicast example discussed
above, but uses a broadcast address and the <i>SO_BROADCAST</i> socket option.
Because we expect to receive multiple responses, we also need to use separate
request-response messages to send one request and consume multiple responses.
In this example we defined a <i>bcastString</i> request and a
<i>bcastStringResponse</i> response message, which are essentially declared as
one-way messages in the header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-header-part: bcastString wsa__MessageID <br />
//gsoap ns service method-header-part: bcastString wsa__To <br />
//gsoap ns service method-header-part: bcastString wsa__Action <br />
//gsoap ns service method-header-part: bcastString wsa__ReplyTo <br />
<b>int</b>&nbsp;ns__bcastString(<b>char</b>&nbsp;*str, <b>void</b>); <br />
//gsoap ns service method-header-part: bcastStringResponse wsa__MessageID <br />
//gsoap ns service method-header-part: bcastStringResponse wsa__To <br />
//gsoap ns service method-header-part: bcastStringResponse wsa__Action <br />
//gsoap ns service method-header-part: bcastStringResponse wsa__RelatesTo <br />
<b>int</b>&nbsp;ns__bcastStringResponse(<b>char</b>&nbsp;*res, <b>void</b>);
</td></tr></table><br></i>
The cliend code includes a loop to receive response messages until a timeout occurs:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
<b>struct</b>&nbsp;SOAP_ENV__Header header; <br />
<b>struct</b>&nbsp;wsa__EndpointReferenceType replyTo; <br />
<b>char</b>&nbsp;*res; <br />
soap_init(&amp;soap); <br />
soap.connect_flags = SO_BROADCAST; <br />
soap.send_timeout = 1; // 1s timeout <br />
soap.recv_timeout = 1; // 1s timeout <br />
soap_default_SOAP_ENV__Header(&amp;soap, &amp;header); <br />
soap.header = &amp;header; <br />
soap_default_wsa__EndpointReferenceType(&amp;soap, &amp;replyTo); <br />
replyTo.Address = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"; <br />
header.wsa__MessageID = "<i>message ID</i>"; <br />
header.wsa__To = "<i>server URL</i>"; <br />
header.wsa__Action = "<i>server action</i>"; <br />
header.wsa__ReplyTo = &amp;replyTo; <br />
<b>if</b>&nbsp;(soap_send_ns__bcastString(&amp;soap, "soap.udp://...", NULL, "hello world!")) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
<b>else</b><br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_recv_ns__bcastStringResponse(&amp;soap, &amp;res)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Got response 'res' from a server <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error == SOAP_EOF &amp;&amp; soap.errnum == 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Timeout: no more messages received <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
} <br />
soap_end(&amp;soap); // cleanup <br />
soap_destroy(&amp;soap); // cleanup <br />
soap_done(&amp;soap); // close connection (should not use soap struct after this)
</td></tr></table><br></i>
Note that a server for the <i>bcastString</i> does not need to use two-one way
messages. Thus, multicast request-response message pattern can be declared and
implemented as request-response operations at the server side.
<div class="p"><!----></div>
<h3><a name="tth_sEc17.6">
17.6</a>&nbsp;&nbsp;<font color="#0000FF">SOAP-over-UDP Server</font></h3>
<div class="p"><!----></div>
The following example code illustrates a SOAP-over-UDP server for one-way <i>sendString</i> and request-response <i>echoString</i> messages.
This example assumes that the gSOAP header file includes the SOAP Header with
WS-Addressing elements and the <i>ns__echoString</i> function discussed in
Section&nbsp;<a href="#sec:udp.h">17.1</a>.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;soap_init1(&amp;soap, SOAP_IO_UDP); // must set UDP flag <br />
&nbsp;&nbsp;&nbsp;// bind to host (NULL=current host) and port: <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_valid_socket(soap_bind(&amp;soap, host, port, 100))) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_serve(&amp;soap)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // report the problem <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); // close connection <br />
} <br />
<b>int</b>&nbsp;ns__echoString(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*str, <b>char</b>&nbsp;**res) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>header) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_sender_fault(soap, "No SOAP header", NULL); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_sender_fault(soap, "No WS-Addressing MessageID", NULL); <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__RelatesTo = (<b>struct</b>&nbsp;wsa__Relationship*)soap_malloc(soap, <b>sizeof</b>(<b>struct</b>&nbsp;wsa__Relationship)); <br />
&nbsp;&nbsp;&nbsp;soap_default_wsa__Relationship(soap, soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__RelatesTo); <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__RelatesTo<tt>-&gt;</tt>__item = soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID; <br />
&nbsp;&nbsp;&nbsp;// must check for duplicate messages <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(check_received(soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Request message already received <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_STOP; // don't return response <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__ReplyTo <font face="symbol">|</font
><font face="symbol">|</font
> !soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__ReplyTo<tt>-&gt;</tt>Address) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_sender_fault(soap, "No WS-Addressing ReplyTo address", NULL); <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__To = soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__ReplyTo<tt>-&gt;</tt>Address; <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID = soap_strdup(soap, soap_int2s(soap, id_count++)) ; <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__Action = "http://genivia.com/udp/echoStringResponse"; <br />
&nbsp;&nbsp;&nbsp;*res = str; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>int</b>&nbsp;ns__sendString(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*str) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>header) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_STOP; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_STOP; <br />
&nbsp;&nbsp;&nbsp;// must check for duplicate messages <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(check_received(soap<tt>-&gt;</tt>header<tt>-&gt;</tt>wsa__MessageID)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_STOP; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>int</b>&nbsp;ns__sendStringResponse(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*res) <br />
{ <b>return</b>&nbsp;SOAP_NO_METHOD; } // we don't expect to serve this message
</td></tr></table><br></i>
The server binds to a host and port and accepts messages in a tight sequential
loop. Because UDP does not have the equivalent of an accept the messages
cannot be dispatched to threads, the <i>soap_serve</i> waits for a message and
immediately accepts it. You can use a receive timeout to make <i>soap_serve</i>
non-blocking.
<div class="p"><!----></div>
<h2><a name="tth_sEc18">
18</a>&nbsp;&nbsp;<font color="#0000FF">Advanced Features</font></h2><a name="sec:advanced">
</a>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.1">
18.1</a>&nbsp;&nbsp;<font color="#0000FF">Internationalization</font></h3>
<div class="p"><!----></div>
gSOAP uses regular strings by default. Regular strings cannot be used to hold
UCS characters outside of the character range [1,255]. gSOAP can handle
wide-character content in two ways. First, applications can utilize
wide-character strings (<i>wchar_t*</i>) instead of regular strings to store
wide-character content. For example, the <tt>xsd:string</tt> string schema type
can be declared as a wide-character string and used subsequently:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;wchar_t *xsd__string; <br />
... <br />
<b>int</b>&nbsp;ns__myMethod(xsd__string input, xsd__string *output);
</td></tr></table><br></i>
Second, regular strings can be used to hold wide-character content in UTF-8
format. This is accomplished with the <i>SOAP_C_UTFSTRING</i> flag (for both input/output mode), see Section&nbsp;<a href="#sec:flags">8.12</a>.
With this flag set, gSOAP will deserialize XML into
regular strings in UTF-8 format. An application is responsible for filling
regular strings with UTF-8 content to ensure that strings can be correctly serialized XML.
Third, the <i>SOAP_C_MBSTRING</i> flag (for both input/output mode) can be used to activate multibyte character support. Multibyte support depends on the locale settings for dealing with extended natural language encodings.
<div class="p"><!----></div>
Both regular strings and wide-character strings can be used together within an application.
For example, the following header file declaration introduces two string schema types:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;wchar_t *xsd__string; <br />
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*xsd__string_; // trailing '_' avoids name clash <br />
... <br />
<b>int</b>&nbsp;ns__myMethod(xsd__string input, xsd__string_ *output);
</td></tr></table><br></i>
The <i>input</i> string parameter is a wide-character string and the <i>output</i> string
parameter is a regular string. The regular string has UCS character content
in the range [1,255] unless the
<i>SOAP_C_UTFSTRING</i> flag is set. With this flag, the string has UTF-8
encoded content.
<div class="p"><!----></div>
Please consult the UTF-8 specification for details on the UTF-8 format.
Note that the ASCII character set [1-127] is a subset of UTF-8. Therefore, with the <i>SOAP_C_UTFSTRING</i> flag set, strings may hold ASCII character data and UTF-8 extensions.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.2">
18.2</a>&nbsp;&nbsp;<font color="#0000FF">Customizing the WSDL and Namespace Mapping Table File Contents With gSOAP Directives</font></h3><a name="sec:directives">
</a>
<div class="p"><!----></div>
A header file can be augmented with directives for the gSOAP Stub and Skeleton compiler to automatically generate customized WSDL and namespace mapping tables contents. The WSDL and namespace mapping table files do not need to be modified by hand (Sections&nbsp;<a href="#sec:wsdl">7.2.8</a> and&nbsp;<a href="#sec:nstable">9.4</a>).
In addition, the sample SOAP/XML request and response files generated by the compiler are valid provided that XML Schema namespace
information is added to the header file with directives so that the gSOAP compiler can produce example SOAP/XML messages that are correctly namespace qualified.
These compiler directive are specified as <i>//</i>-comments.
(Note: blanks can be used anywhere in the directive, except between <i>//</i> and <i>gsoap</i>.)
<div class="p"><!----></div>
Three directives are currently supported that can be used to specify details associated with namespace prefixes used by the remote
method names in the header file.
To specify the name of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service name: <i>service-name</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>service-name</i> is the name
of a Web Service (only required to create new Web Services).
The name may be followed by text up to the end of the line which is incorporated into the WSDL service documentation. Alternatively, the service documentation can be provided with the directive below.
<div class="p"><!----></div>
To specify the name of the WSDL definitions in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service definitions: <i>definitions-name</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>definitions-name</i> is the name of the WSDL definitions. By default, the WSDL definitions name is the same as the service name.
<div class="p"><!----></div>
To specify the documentation of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service documentation: <i>text</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>text</i> is the documentation text up to the end of the line.
The text is incorporated into the WSDL service documentation.
<div class="p"><!----></div>
To specify the portType of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service portType: <i>portType-name</i>
</td></tr></table><br></i>
or
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service type: <i>portType-name</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>portType-name</i> is the portType name of the WSDL service portType.
<div class="p"><!----></div>
To specify the binding name of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service binding: <i>binding-name</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>binding-name</i> is the binding name of the WSDL service binding element. By default, the binding name is the same as the service name.
<div class="p"><!----></div>
To specify the binding's transport protocol of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service transport: <i>transport-URL</i>
</td></tr></table><br></i>
where <i>namespace-prefix</i> is a namespace prefix used by identifiers in the header file and <i>transport-URL</i> is the URL of the transport protocol such as <i>http://schemas.xmlsoap.org/soap/http</i> for HTTP. HTTP transport is assumed by default.
<div class="p"><!----></div>
To specify the location (or port endpoint) of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service location: <i>URL</i>
</td></tr></table><br></i>
or alternatively
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service port: <i>URL</i>
</td></tr></table><br></i>
where <i>URL</i> is the location of the Web Service (only required to create new Web Services).
The <i>URL</i> specifies the path to the service executable (so <i><i>URL</i>/<i>service-executable</i></i>
is the actual location of the executable when declared).
<div class="p"><!----></div>
To specify the name of the executable of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service executable: <i>executable-name</i>
</td></tr></table><br></i>
where <i>executable-name</i> is the name of the executable of the Web Service.
<div class="p"><!----></div>
When doc/literal encoding is required for the entire service, the service encoding can be specified in the header file as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service encoding: literal
</td></tr></table><br></i>
or when the <tt>SOAP-ENV:encodingStyle</tt> attribute is different from the SOAP 1.1/1.2 encoding style:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service encoding: <i>encoding-style</i>
</td></tr></table><br></i>
<div class="p"><!----></div>
To specify the namespace URI of a Web Service in the header file, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service namespace: <i>namespace-URI</i>
</td></tr></table><br></i>
where <i>namespace-URI</i> is the URI associated with the namespace prefix.
<div class="p"><!----></div>
In addition, the schema namespace URI can be specified in the header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema namespace: <i>namespace-URI</i>
</td></tr></table><br></i>
where <i>namespace-URI</i> is the schema URI associated with the namespace prefix.
If present, it defines the schema-part of the generated WSDL file and the URI in the namespace mapping table.
This declaration is useful when the service declares its own data types that need to be associated with a namespace.
Furthermore, the header file for client applications do not need the full service details and the specification of the schema
namespaces for namespace prefixes suffices.
<div class="p"><!----></div>
The directive above specifies a new schema and the gSOAP compiler generates a schema files (.xsd) file for the schema.
An existing schema namespace URI can be imported with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema import: <i>namespace-URI</i>
</td></tr></table><br></i>
where <i>namespace-URI</i> is the schema URI associated with the namespace prefix.
gSOAP does not produce XML Schema files for imported schemas and imports the schema namespaces in the generated WSDL file.
<div class="p"><!----></div>
A schema namespace URI can be imported from a location with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema namespace: <i>namespace-URI</i> <br />
//gsoap <i>namespace-prefix</i> schema import: <i>schema-location</i>
</td></tr></table><br></i>
<div class="p"><!----></div>
The elementFormDefault and attributeFormDefault qualification of a schema can be defined with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema elementForm: qualified <br />
//gsoap <i>namespace-prefix</i> schema attributeForm: qualified
</td></tr></table><br></i>
or:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema elementForm: unqualified <br />
//gsoap <i>namespace-prefix</i> schema attributeForm: unqualified
</td></tr></table><br></i>
A shortcut to define the default qualification of elements and attributes of a schema:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema form: qualified
</td></tr></table><br></i>
or:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema form: unqualified
</td></tr></table><br></i>
<div class="p"><!----></div>
To document a data type, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> schema type-documentation: <i>type-name</i> //<i>text</i>
</td></tr></table><br></i>
where <i>type-name</i> is the unqualified name of the data type and <i>text</i>
is a line of text terminated by a newline. Do not use any XML reserved
characters in <i>text</i> such as &lt; and &gt; . Use well-formed XML and XHTML markup instead.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns schema type-documentation: tdata stores <tt>&lt;a&nbsp;href="transaction.html"&gt;</tt>transaction<tt>&lt;/a&gt;</tt> data <br />
<b>class</b>&nbsp;ns__tdata <br />
{ ... }
</td></tr></table><br></i>
<div class="p"><!----></div>
To document a method, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-documentation: <i>method-name</i> //<i>text</i>
</td></tr></table><br></i>
where <i>method-name</i> is the unqualified name of the method and <i>text</i>
is a line of text terminated by a newline. Do not use any XML reserved
characters in <i>text</i> such as &lt; and &gt; . Use well-formed XML and XHTML markup instead.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-documentation: getQuote returns a <tt>&lt;i&gt;</tt>stock quote<tt>&lt;/i&gt;</tt> <br />
<b>int</b>&nbsp;ns__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;_result);
</td></tr></table><br></i>
<div class="p"><!----></div>
To specify the SOAPAction for a method, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-action: <i>method-name</i> <i>action</i>
</td></tr></table><br></i>
where <i>method-name</i> is the unqualified name of the method and <i>action</i>
is a quoted or non-quoted string (spaces and blanks are not allowed).
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-action: getQuote "" <br />
<b>int</b>&nbsp;ns__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;_result);
</td></tr></table><br></i>
<div class="p"><!----></div>
When document style is preferred for a particular service method, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-style: <i>method-name</i> document
</td></tr></table><br></i>
<div class="p"><!----></div>
When SOAP RPC encoding is required for a particular service method, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-encoding: <i>method-name</i> encoded
</td></tr></table><br></i>
When literal encoding is required for a particular service method, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-encoding: <i>method-name</i> literal
</td></tr></table><br></i>
or when the <tt>SOAP-ENV:encodingStyle</tt> attribute is different from the SOAP 1.1/1.2 encoding style, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-encoding: <i>method-name</i> <i>encoding-style</i>
</td></tr></table><br></i>
<div class="p"><!----></div>
When SOAP RPC encoding is required for a particular service method response when the request message is literal, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-response-encoding: <i>method-name</i> encoded
</td></tr></table><br></i>
When literal encoding is required for a particular service method response when the request message is encoded, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-response-encoding: <i>method-name</i> literal
</td></tr></table><br></i>
or when the <tt>SOAP-ENV:encodingStyle</tt> attribute is different from the SOAP 1.1/1.2 encoding style, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-response-encoding: <i>method-name</i> <i>encoding-style</i>
</td></tr></table><br></i>
Note that the <i>method-response-encoding</i> is set to the value of <i>method-encoding</i> by default.
<div class="p"><!----></div>
When header processing is required, each method declared in the WSDL should provide a binding to the parts of the header that may
appear as part of a method request message. Such a binding is given by:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-header-part: <i>method-name</i> <i>header-part</i>
</td></tr></table><br></i>
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*h__transaction; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;UserAuth *h__authentication; <br />
};
</td></tr></table><br></i>
Suppose method <i>ns__login</i> uses both header parts (at most), then this is declared as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-header-part: login h__transaction <br />
//gsoap ns service method-header-part: login h__authentication <br />
<b>int</b>&nbsp;ns__login(...);
</td></tr></table><br></i>
Suppose method <i>ns__search</i> uses only the first header part, then this is declared as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service method-header-part: search h__transaction <br />
int ns__search(...);
</td></tr></table><br></i>
Note that the method name and header part names MUST be namespace qualified.
The headers MUST be present in all operations that declared the header parts.
<div class="p"><!----></div>
To specify the header parts for the method input (method request message), use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-input-header-part: <i>method-name</i> <i>header-part</i>
</td></tr></table><br></i>
Similarly, to specify the header parts for the method output (method response message), use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-output-header-part: <i>method-name</i> <i>header-part</i>
</td></tr></table><br></i>
The declarations above only affect the WSDL.
For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;SOAP_ENV__Header <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*h__transaction; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;UserAuth *h__authentication; <br />
}; <br />
//gsoap ns service method-input-header-part: login h__authentication <br />
//gsoap ns service method-input-header-part: login h__transaction <br />
//gsoap ns service method-output-header-part: login h__transaction <br />
<b>int</b>&nbsp;ns__login(...);
</td></tr></table><br></i>
The headers MUST be present in all operations that declared the header parts.
<div class="p"><!----></div>
To specify MIME attachments for the method input and output (method request and response messages), use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-mime-type: <i>method-name</i> <i>mime-type</i>
</td></tr></table><br></i>
You can repeat this directive for all multipartRelated MIME attachments you want to associate with the method.
<div class="p"><!----></div>
To specify MIME attachments for the method input (method request message), use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-input-mime-type: <i>method-name</i> <i>mime-type</i>
</td></tr></table><br></i>
Similarly, to specify MIME attachments for the method output (method response message), use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap <i>namespace-prefix</i> service method-output-mime-type: <i>method-name</i> <i>mime-type</i>
</td></tr></table><br></i>
You can repeat these directives for all multipartRelated MIME attachments you want to associate with the method.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.2.1">
18.2.1</a>&nbsp;&nbsp;<font color="#0000FF">Example</font></h4>
<div class="p"><!----></div>
The use of directives is best illustrated with an example.
The <i>quotex.h</i> header file of the <i>quotex</i> example in the gSOAP distribution for Unix/Linux is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns1 service namespace: urn:xmethods-delayed-quotes <br />
<b>int</b>&nbsp;ns1__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;result); <br />
<br />
//gsoap ns2 service namespace: urn:xmethods-CurrencyExchange <br />
<b>int</b>&nbsp;ns2__getRate(<b>char</b>&nbsp;*country1, <b>char</b>&nbsp;*country2, <b>float</b>&nbsp;&amp;result); <br />
<br />
//gsoap ns3 service name: quotex <br />
//gsoap ns3 service style: rpc <br />
//gsoap ns3 service encoding: encoded <br />
//gsoap ns3 service location: http://www.cs.fsu.edu/~engelen <br />
//gsoap ns3 service namespace: urn:quotex <br />
<b>int</b>&nbsp;ns3__getQuote(<b>char</b>&nbsp;*symbol, <b>char</b>&nbsp;*country, <b>float</b>&nbsp;&amp;result);
</td></tr></table><br></i>
The <i>quotex</i> example is a new Web Service created by combining two existing Web Services:
the XMethods Delayed Stock Quote service and XMethods Currency Exchange service.
<div class="p"><!----></div>
Namespace prefix <i>ns3</i> is used for the new <i>quotex</i> Web Service with namespace URI <i>urn:quotex</i>,
service name <i>quotex</i>, and location <i>http://www.cs.fsu.edu/~engelen</i>.
Since the new Web Service invokes the <i>ns1__getQuote</i> and <i>ns2__getRate</i> remote methods,
the service namespaces of these methods are given.
The service names and locations of these methods are not given because they
are only required for setting up a new Web Service for these methods
(but may also be provided in the header file for documentation purposes).
After invoking the gSOAP Stub and Skeleton compiler on the <i>quotex.h</i> header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 quotex.h</i>
</td></tr></table><br></span>
the WSDL of the new <i>quotex</i> Web Service is saved as <i>quotex.wsdl</i>.
Since the service name (<i>quotex</i>), location (<i>http://www.cs.fsu.edu/~engelen</i>), and namespace URI
(<i>urn:quotex</i>) were provided in the header file, the generated WSDL file does not need to be changed by hand and can be published
immediately together with the compiled Web Service installed as a CGI application at the designated URL
(<i>http://www.cs.fsu.edu/~engelen/quotex.cgi</i>
and <i>http://www.cs.fsu.edu/~engelen/quotex.wsdl</i>).
<div class="p"><!----></div>
The namespace mapping table for the <i>quotex.cpp</i> Web Service implementation
is saved as <i>quotex.nsmap</i>. This file can be directly included in
<i>quotex.cpp</i> instead of specified by hand in the source of
<i>quotex.cpp</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "quotex.nsmap"
</td></tr></table><br></i>
The automatic generation and inclusion of the namespace mapping table requires
compiler directives for <b>all</b> namespace prefixes to associate each
namespace prefix with a namespace URI. Otherwise, namespace URIs have to be
manually added to the table (they appear as <i>http://tempuri.org</i>).
<div class="p"><!----></div>
<h3><a name="tth_sEc18.3">
18.3</a>&nbsp;&nbsp;<font color="#0000FF">Transient Data Types</font></h3><a name="sec:transient">
</a>
<div class="p"><!----></div>
There are situations when certain data types have to be ignored by gSOAP for
the compilation of (de)marshalling routines. For example, in certain cases
only a few members of a class or struct need not be (de)serialized, or the base
class of a derived class should not be (de)serialized. Certain built-in classes
such as <i>ostream</i> cannot be (de)serialized. Data parts that should be kept
invisible to gSOAP are called "transient". Transient data types and
transient struct/class members are declared with the <i><b>extern</b></i> keyword or
are declared within <i>[</i> and <i>]</i> blocks in the header file. The
<i><b>extern</b></i> keyword has a special meaning to the gSOAP compiler and won't
affect the generated codes. The special <i>[</i> and <i>]</i> block construct
can be used with data type declarations and within <i><b>struct</b></i> and
<i><b>class</b></i> declarations. The use of <i><b>extern</b></i> or <i>[ ]</i> achieve the
same effect, but <i>[ ]</i> may be more convenient to encapsulate transient
types in a larger part of the header file. The use of <i><b>extern</b></i> with
<i><b>typedef</b></i> is reserved for the declaration of user-defined external
(de)serializers for data types, see Section&nbsp;<a href="#sec:extern">18.5</a>.
<div class="p"><!----></div>
First example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>extern</b>&nbsp;<b>class</b>&nbsp;ostream; // ostream can't be (de)serialized, but need to be declared to make it visible to gSOAP <br />
<b>class</b>&nbsp;ns__myClass <br />
{ ... <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;print(ostream &amp;s) <b>const</b>; // need ostream here <br />
&nbsp;&nbsp;&nbsp;... <br />
};
</td></tr></table><br></i>
Second example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
[ <br />
&nbsp;&nbsp;&nbsp;<b>class</b>&nbsp;myBase // base class need not be (de)serialized <br />
&nbsp;&nbsp;&nbsp;{ ... }; <br />
] <br />
<b>class</b>&nbsp;ns__myDerived : myBase <br />
{ ... }; <br />
</td></tr></table><br></i>
Third example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
[ <b>typedef</b>&nbsp;<b>int</b>&nbsp;transientInt; ] <br />
<b>class</b>&nbsp;ns__myClass <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;a; // will be (de)serialized <br />
&nbsp;&nbsp;&nbsp;[ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;b; // transient field <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;s[256]; // transient field <br />
&nbsp;&nbsp;&nbsp;] <br />
&nbsp;&nbsp;&nbsp;<b>extern</b>&nbsp;<b>float</b>&nbsp;d; // transient field <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*t; // will be (de)serialized <br />
&nbsp;&nbsp;&nbsp;transientInt *n; // transient field <br />
&nbsp;&nbsp;&nbsp;[ <br />
&nbsp;&nbsp;&nbsp;<b>virtual</b>&nbsp;<b>void</b>&nbsp;method(<b>char</b>&nbsp;buf[1024]); // does not create a <b>char</b>[1024] (de)serializer <br />
&nbsp;&nbsp;&nbsp;] <br />
};
</td></tr></table><br></i>
In this example, <i><b>class</b>&nbsp;ns__myClass</i> has three transient fields:
<i>b</i>, <i>s</i>, and <i>n</i> which will not be (de)serialized in SOAP. Field
<i>n</i> is transient because the type is declared within a transient block.
Pointers, references, and arrays of transient types are transient. The single
class method is encapsulated within <i>[</i> and <i>]</i> to prevent gSOAP from
creating (de)serializers for the <i><b>char</b>[1024]</i> type. gSOAP will generate
(de)serializers for all types that are not declared within a <i>[</i> and
<i>]</i> transient block.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.4">
18.4</a>&nbsp;&nbsp;<font color="#0000FF">Volatile Data Types</font></h3><a name="sec:volatile">
</a>
<div class="p"><!----></div>
While transient data types are supposed to be hidden from gSOAP, volatile data
types are visible to gSOAP but their declaration and implementation is assumed
to be hidden. That is, volatile data types are assumed to be part of an
existing non-modifiable software package, such as a built-in library. It would
not make sense to redefine the data types in a gSOAP header file. When you need
to (de)serialize such data types, you must declare them in a gSOAP header file
and use the <i><b>volatile</b></i> qualifier.
<div class="p"><!----></div>
Consider for example <i><b>struct</b>&nbsp;tm</i>, declared in <i>time.h</i>. The structure may actually vary between platforms, but the tm structure includes at least the following fields:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>volatile</b>&nbsp;<b>struct</b>&nbsp;tm <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_sec; /* seconds (0 - 60) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_min; /* minutes (0 - 59) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_hour; /* hours (0 - 23) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_mday; /* day of month (1 - 31) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_mon; /* month of year (0 - 11) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_year; /* year - 1900 */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_wday; /* day of week (Sunday = 0) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_yday; /* day of year (0 - 365) */ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;tm_isdst; /* is summer time in effect? */ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*tm_zone; /* abbreviation of timezone name */ <br />
&nbsp;&nbsp;&nbsp;<b>long</b>&nbsp;tm_gmtoff; /* offset from UTC in seconds */ <br />
};
</td></tr></table><br></i>
Note that we qualified the structure <i><b>volatile</b></i> in the gSOAP header file to inform the gSOAP compiler that it should not attempt to redeclare it.
We can now readily serialize and deserialize the tm structure. The following program fragment serializes the local time stored in a tm structure to stdout:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
time_t T = time(NULL); <br />
<b>struct</b>&nbsp;tm *t = localtime(&amp;T); <br />
<b>struct</b>&nbsp;soap *soap = soap_new(); <br />
soap_set_omode(soap, SOAP_XML_GRAPH); // good habit to use this <br />
soap_begin_send(soap); <br />
soap_put_tm(soap, t, "myLocalTime", NULL); <br />
soap_end_send(soap); <br />
soap_end(soap); <br />
soap_done(soap); <br />
free(soap);
</td></tr></table><br></i>
It is also possible to serialize the tm fields as XML attributes using the
@qualifier, see Section&nbsp;<a href="#sec:attributes">10.5.7</a>.
<div class="p"><!----></div>
If you must produce a schema file, say <i>time.xsd</i>, that defines an XML
schema and namespace for the tm struct, you can add a <i><b>typedef</b></i>
declaration to the header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>struct</b>&nbsp;tm time__struct_tm;
</td></tr></table><br></i>
We used the <i><b>typedef</b></i> name <i>time__struct_tm</i> rather than <i>time__
tm</i>, because a schema name clash will occur with the latter since taking off
the <i>time</i> prefix will result in the same name being used.
<div class="p"><!----></div>
Classes should be declared volatile to prevent modification of these classes by gSOAP.
gSOAP adds serialization methods to classes to support polymorphism. However,
this is a problem when you can't modify class declarations because they are
part of a non-modifiable software package. The solution is to declare these
classes <i><b>volatile</b></i>, similar to the tm structure example illustrated above.
You can also use a <i><b>typedef</b></i> to associate a schema with a class.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.5">
18.5</a>&nbsp;&nbsp;<font color="#0000FF">How to Declare User-Defined Serializers and Deserializers</font></h3><a name="sec:extern">
</a>
<div class="p"><!----></div>
Users can declare their own (de)serializers for specific data types instead of relying on the gSOAP-generated (de)serializers.
To declare a external (de)serializer, declare a type with <i><b>extern</b>&nbsp;<b>typedef</b></i>. gSOAP will not generate the (de)serializers
for the type name that is declared. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>extern</b>&nbsp;<b>typedef</b>&nbsp;<b>char</b>&nbsp;*MyData; <br />
<b>struct</b>&nbsp;Sample <br />
{ <br />
&nbsp;&nbsp;&nbsp;MyData s; // use user-defined (de)serializer for this field <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*t; // use gSOAP (de)serializer for this field <br />
};
</td></tr></table><br></i>
The user is required to supply the following routines for each <i><b>extern</b>&nbsp;<b>typedef</b></i>'ed name <u>T</u>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>void</b>&nbsp;soap_serialize_<u><span class="roman">T</span></u>(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<u><span class="roman">T</span></u> *a) <br />
<b>void</b>&nbsp;soap_default_<u><span class="roman">T</span></u>(<b>struct</b>&nbsp;soap *soap, <u><span class="roman">T</span></u> *a) <br />
<b>void</b>&nbsp;soap_out_<u><span class="roman">T</span></u>(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag, <b>int</b>&nbsp;id, <b>const</b>&nbsp;<u><span class="roman">T</span></u> *a, <b>const</b>&nbsp;<b>char</b>&nbsp;*type) <br />
<u><span class="roman">T</span></u> *soap_in_<u><span class="roman">T</span></u>(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag, <u><span class="roman">T</span></u> *a, <b>const</b>&nbsp;<b>char</b>&nbsp;*type)
</td></tr></table><br></i>
The function prototypes can be found in <i>soapH.h</i>.
<div class="p"><!----></div>
For example, the (de)serialization of <i>MyData</i> can be done with the following code:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>void</b>&nbsp;soap_serialize_MyData(<b>struct</b>&nbsp;soap *soap, MyData *<b>const</b>*a) <br />
{ } // no need to mark this node (for multi-ref and cycle detection) <br />
<b>void</b>&nbsp;soap_default_MyData(&amp;soap, MyData **a) <br />
{ *a = NULL } <br />
<b>void</b>&nbsp;soap_out_MyData(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag, <b>int</b>&nbsp;id, MyData *<b>const</b>*a, <b>const</b>&nbsp;<b>char</b>&nbsp;*type) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_element_begin_out(soap, tag, id, type); // print XML beginning tag <br />
&nbsp;&nbsp;&nbsp;soap_send(soap, *a); // just print the string (no XML conversion) <br />
&nbsp;&nbsp;&nbsp;soap_element_end_out(soap, tag); // print XML ending tag <br />
} <br />
MyData **soap_in_MyData(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag, MyData **a, <b>const</b>&nbsp;<b>char</b>&nbsp;*type) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_element_begin_in(soap, tag)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!a) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a = (MyData**)soap_malloc(soap, <b>sizeof</b>(MyData*)); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>null) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a = NULL; // xsi:nil element <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(*soap<tt>-&gt;</tt>type &amp;&amp; soap_match_tag(soap, soap<tt>-&gt;</tt>type, type)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>error = SOAP_TYPE; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; // type mismatch <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(*soap<tt>-&gt;</tt>href) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a = (MyData**)soap_id_forward(soap, soap<tt>-&gt;</tt>href, a, SOAP_MyData, <b>sizeof</b>(MyData*)) <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>body) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*s = soap_value(soap); // fill buffer <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a = (<b>char</b>*)soap_malloc(soap, strlen(s)+1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(*a, s); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>body &amp;&amp; soap_element_end_in(soap, tag)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;a;
</td></tr></table><br></i>
More information on custom (de)serialization will be provided in this document or in a separate document in the future.
The writing of the (de)serializer code requires the use of the low-level gSOAP API.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.6">
18.6</a>&nbsp;&nbsp;<font color="#0000FF">How to Serialize Data Without Generating XSD Type Attributes</font></h3>
<div class="p"><!----></div>
gSOAP serializes data in XML with <tt>xsi:type</tt> attributes when the types are
declared with namespace prefixes to indicate the schema type of the data
contained in the elements. SOAP 1.1 and 1.2 requires <tt>xsi:type</tt> attributes
in the presence of polymorphic data or when the type of the data cannot be
deduced from the SOAP payload. The namespace prefixes are associated with the
type names of <i><b>typedef</b></i>s (Section&nbsp;<a href="#sec:primitive">10.2</a>) for primitive data
types, <i><b>struct</b></i>/<i>class</i> names, and <i><b>enum</b></i> names.
<div class="p"><!----></div>
To prevent the output of these <tt>xsi:type</tt> attributes in the XML
serialization, you can simply use type declarations that do not include these
namespace prefixes. That is, don't use the <i><b>typedef</b></i>s for primitive types
and use unqualified type names with <i><b>struct</b></i>s, <i><b>class</b></i>es, and
<i>enum</i>s.
<div class="p"><!----></div>
However, there are two issues. Firstly, if you want to use a primitive schema
type that has no C/C++ counterpart, you must declare it as a <i><b>typedef</b></i>
name with a leading underscore, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>typedef</b>&nbsp;<b>char</b>&nbsp;*_xsd__date;
</td></tr></table><br></i>
This will produce the necessary <tt>xsd:date</tt> information in the WSDL output
by the gSOAP compiler. But the XML serialization of this type at run time
won't include the <tt>xsi:type</tt> attribute. Secondly, to include the proper
schema definitions in the WSDL produced by the gSOAP compiler, you should
use qualified <i><b>struct</b></i>, <i><b>class</b></i>, and <i><b>enum</b></i> names with a leading
underscore, as in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;_ns__myStruct <br />
{ ... };
</td></tr></table><br></i>
This ensures that <i>myStruct</i> is associated with a schema, and therefore
included in the appropriate schema in the generated WSDL. The leading
underscore prevents the XML serialization of <tt>xsi:type</tt> attributes for this
type in the SOAP/XML payload.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.7">
18.7</a>&nbsp;&nbsp;<font color="#0000FF">Function Callbacks for Customized I/O and HTTP Handling</font></h3><a name="sec:callback">
</a>
<div class="p"><!----></div>
gSOAP provides five callback functions for customized I/O and HTTP handling:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Callback (function pointer)</b></font> </td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fopen)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint, <b>const</b>&nbsp;<b>char</b>&nbsp;*host, <b>int</b>&nbsp;port)</i> </td></tr>
<tr><td width="602">Called from a client proxy to open a connection to a Web Service located at <i>endpoint</i>.
Input parameters <i>host</i> and <i>port</i> are micro-parsed from <i>endpoint</i>.
Should return a valid file descriptor, or <i>SOAP_INVALID_SOCKET</i> and <i>soap</i><tt>-&gt;</tt><i>error</i> set to an error code.
Built-in gSOAP function: <i>tcp_connect</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fget)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Called by the main server loop upon an HTTP GET request. The <i>SOAP_GET_METHOD</i> error is returned by the default <i>fget</i> routine. This callback can be used to respond to HTTP GET methods with content, see Section&nbsp;<a href="#sec:get">18.10</a>.
Should return <i>SOAP_OK</i>, or a gSOAP error code.
Built-in gSOAP function: <i>http_get</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fform)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Called by the main server loop when a user-defined <i>fparsehdr</i> callback returned <i>SOAP_FORM</i> to signal that the HTTP body must be processed by this form handler callback. The HTTP POST form data MUST be read, otherwise keep-alive messages will end up out of sync.
Should return <i>SOAP_OK</i> or a gSOAP error code.
Built-in gSOAP function: none.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fpost)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint, <b>const</b>&nbsp;<b>char</b>&nbsp;*host, <b>int</b>&nbsp;port, <b>const</b>&nbsp;<b>char</b>&nbsp;*path, <b>const</b>&nbsp;<b>char</b>&nbsp;*action, size_t count)</i> </td></tr>
<tr><td width="602">Called from a client proxy to generate the HTTP header to connect to <i>endpoint</i>.
Input parameters <i>host</i>, <i>port</i>, and <i>path</i> are micro-parsed from <i>endpoint</i>, <i>action</i> is the SOAP action,
and <i>count</i> is the length of the SOAP message or 0 when <i>SOAP_ENC_XML</i> is set or when <i>SOAP_IO_LENGTH</i> is reset.
Use function <i>soap_send(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*s)</i> to write the header contents.
Should return SOAP_OK, or a gSOAP error code.
Built-in gSOAP function: <i>http_post</i>.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fposthdr)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*key, <b>const</b>&nbsp;<b>char</b>&nbsp;*val)</i> </td></tr>
<tr><td width="602">Called by <i>http_post</i> and <i>http_response</i> (through the callbacks).
Emits HTTP <i>key</i>: <i>val</i> header entries.
Should return SOAP_OK, or a gSOAP error code.
Built-in gSOAP function: <i>http_post_header</i>.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fresponse)(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;soap_error_code, size_t count)</i> </td></tr>
<tr><td width="602">Called from a service to generate the response HTTP header.
Input parameter <i>soap_error_code</i> is a gSOAP error code (see Section&nbsp;<a href="#sec:errcodes">9.2</a> and
<i>count</i> is the length of the SOAP message or 0 when <i>SOAP_ENC_XML</i> is set or when <i>SOAP_IO_LENGTH</i> is reset.
Use function <i>soap_send(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*s)</i> to write the header contents.
Should return SOAP_OK, or a gSOAP error code
Built-in gSOAP function: <i>http_response</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fparse)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Called by client proxy and service to parse an HTTP header (if present).
When user-defined, this routine must at least skip the header.
Use function <i><b>int</b>&nbsp;soap_getline(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*buf, <b>int</b>&nbsp;len)</i> to read HTTP header lines into
a buffer <i>buf</i> of length <i>len</i> (returns empty line at end of HTTP header).
Should return <i>SOAP_OK</i>, or a gSOAP error code.
Built-in gSOAP function: <i>http_parse</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fparsehdr)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*key, <b>const</b>&nbsp;<b>char</b>&nbsp;*val)</i> </td></tr>
<tr><td width="602">Called by <i>http_parse</i> (through the <i>fparse</i> callback).
Handles HTTP <i>key</i>: <i>val</i> header entries to set gSOAP's internals.
Should return <i>SOAP_OK</i>, <i>SOAP_STOP</i> (see <i>fstop</i>) or a gSOAP error code.
Built-in gSOAP function: <i>http_parse_header</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fclose)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Called by client proxy <b>multiple times</b>, to close a socket connection before a new socket
connection is established and at the end of communications when the <i>SOAP_IO_KEEPALIVE</i> flag is not set
and <i>soap.keep_alive</i> <font face="symbol">¹</font
> 0 (indicating that the other party supports keep alive).
Should return SOAP_OK, or a gSOAP error code.
Built-in gSOAP function: <i>tcp_disconnect</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fsend)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*s, size_t n)</i> </td></tr>
<tr><td width="602">Called for all send operations to emit contents of <i>s</i> of length <i>n</i>.
Should return SOAP_OK, or a gSOAP error code.
Built-in gSOAP function: <i>fsend</i>
</td></tr>
<tr><td width="602"><i>size_t (*soap.frecv)(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*s, size_t n)</i> </td></tr>
<tr><td width="602">Called for all receive operations to fill buffer <i>s</i> of maximum length <i>n</i>.
Should return the number of bytes read or 0 in case of an error, e.g.&nbsp;EOF.
Built-in gSOAP function: <i>frecv</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fignore)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag)</i> </td></tr>
<tr><td width="602">Called when an unknown XML element was encountered on the input. The <i>tag</i> parameter is the offending XML element tag name.
Should return <i>SOAP_OK</i>, or a gSOAP error code such as <i>SOAP_TAG_MISMATCH</i> to throw an exception.
Built-in gSOAP function: none.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fconnect)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint, <b>const</b>&nbsp;<b>char</b>&nbsp;*host, <b>int</b>&nbsp;port)</i> </td></tr>
<tr><td width="602">When non-NULL, this callback is called for all client-to-server connect operations instead of the built-in socket connect code. Therefore, it can be used to override the built-in connection establishment. Parameter <i>endpoint</i> contains the server endpoint URL, <i>host</i> the domain name or IP, and <i>port</i> the port number.
Should return SOAP_OK, or a gSOAP error code.
Built-in gSOAP function: none
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.faccept)(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;sockaddr *a, <b>int</b>&nbsp;*n)</i> </td></tr>
<tr><td width="602">Called by <i>soap_accept</i>. This is a wrapper routine for <i>accept</i>.
Should return a valid socket descriptor or <i>SOAP_INVALID_SOCKET</i> and set <i>soap</i><tt>-&gt;</tt><i>error</i> to an error code.
Built-in gSOAP function: <i>tcp_accept</i>
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fresolve)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*addr, <b>struct</b>&nbsp;in_addr *inaddr)</i> </td></tr>
<tr><td width="602">Called by <i>soap_bind</i> if a host name is given and <i>soap_connect</i> to resolve a domain name <i>addr</i>.
Should set <i>in_addr *a</i> and return <i>SOAP_OK</i> or return <i>SOAP_ERR</i> upon failure.
</td></tr>
<tr><td width="602">Built-in gSOAP function: <i>tcp_gethost</i> </td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fpoll)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Used by clients to check if the server is still responsive.
</td></tr>
<tr><td width="602">Built-in gSOAP function: <i>soap_poll</i> </td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fserveloop)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Called after successful invocation of a server operation in the server loop, immediately after sending the response to a client.
Can be used to clean up resources (e.g.&nbsp;using <i>soap_end()</i>) while serving a long sequence of keep-alive connections.
Should return <i>SOAP_OK</i>, or set <i>soap</i><tt>-&gt;</tt><i>error</i> to a gSOAP error code and return <i>soap</i><tt>-&gt;</tt><i>error</i>.
Built-in gSOAP function: none.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;(*soap.fseterror)(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;**code, <b>const</b>&nbsp;<b>char</b>&nbsp;**string)</i> </td></tr>
<tr><td width="602">Called to set the SOAP Fault <i>code</i> and <i>string</i> values based on the value of <i>soap</i><tt>-&gt;</tt><i>error</i>. Allows user-defined messages to be associated with gSOAP error codes to override gSOAP's built-in error messages.
<div class="p"><!----></div>
Built-in gSOAP function: none.
</td></tr></table>
</td></tr></table><br></span>
In addition, a <i><b>void</b>*user</i> field in the <i><b>struct</b>&nbsp;soap</i> data structure is available to pass user-defined data to the callbacks.
<div class="p"><!----></div>
The following example uses I/O function callbacks for customized serialization of data into a buffer and deserialization back into a
datastructure:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>char</b>&nbsp;buf[10000]; // XML buffer <br />
<b>int</b>&nbsp;len1 = 0; // #chars written <br />
<b>int</b>&nbsp;len2 = 0; // #chars read <br />
// mysend: put XML in buf[] <br />
<b>int</b>&nbsp;mysend(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*s, size_t n) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(len1 + n &gt; <b>sizeof</b>(buf)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;strcpy(buf + len1, s); <br />
&nbsp;&nbsp;&nbsp;len1 += n; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
// myrecv: get XML from buf[] <br />
size_t myrecv(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*s, size_t n) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(len2 + n &gt; len1) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = len1 - len2; <br />
&nbsp;&nbsp;&nbsp;strncpy(s, buf + len2, n); <br />
&nbsp;&nbsp;&nbsp;len2 += n; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;n; <br />
} <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__person p; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;len1 = len2 = 0; // reset buffer pointers <br />
&nbsp;&nbsp;&nbsp;p.name = "John Doe"; <br />
&nbsp;&nbsp;&nbsp;p.age = 25; <br />
&nbsp;&nbsp;&nbsp;soap.fsend = mysend; // assign callback <br />
&nbsp;&nbsp;&nbsp;soap.frecv = myrecv; // assign callback <br />
&nbsp;&nbsp;&nbsp;soap_begin(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_set_omode(&amp;soap, SOAP_XML_GRAPH); <br />
&nbsp;&nbsp;&nbsp;soap_serialize_ns__person(&amp;soap, &amp;p); <br />
&nbsp;&nbsp;&nbsp;soap_put_ns__person(&amp;soap, &amp;p, "ns:person", NULL); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stdout); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_begin(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_get_ns__person(&amp;soap, &amp;p, "ns:person", NULL); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stdout); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); // disable callbacks <br />
}
</td></tr></table><br></i>
The <i>soap_done</i> function can be called to reset the callback to the default internal gSOAP I/O and HTTP handlers.
<div class="p"><!----></div>
The following example illustrates customized I/O and (HTTP) header handling. The SOAP request is saved to a file. The client proxy
then reads the file contents as the service response. To perform this trick, the service response has exactly the same structure as the
request. This is declared by the <i><b>struct</b>&nbsp;ns__test</i> output parameter part of the remote method declaration.
This struct resembles the service request (see the generated <i>soapStub.h</i> file created from the header file).
<div class="p"><!----></div>
The header file is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service name: callback <br />
//gsoap ns service namespace: urn:callback <br />
<b>struct</b>&nbsp;ns__person <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;age; <br />
}; <br />
<b>int</b>&nbsp;ns__test(<b>struct</b>&nbsp;ns__person in, <b>struct</b>&nbsp;ns__test &amp;out);
</td></tr></table><br></i>
The client program is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapH.h" <br />
... <br />
<b>int</b>&nbsp;myopen(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint, <b>const</b>&nbsp;<b>char</b>&nbsp;*host, <b>int</b>&nbsp;port) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(strncmp(endpoint, "file:", 5)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("File name expected<tt>\</tt>n"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;((soap<tt>-&gt;</tt>sendfd = soap<tt>-&gt;</tt>recvfd = open(host, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>void</b>&nbsp;myclose(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;if (soap<tt>-&gt;</tt>sendfd &gt; 2) // still open? <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(soap<tt>-&gt;</tt>sendfd); // then close it <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>recvfd = 0; // set back to stdin <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>sendfd = 1; // set back to stdout <br />
} <br />
<b>int</b>&nbsp;mypost(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*endpoint, <b>const</b>&nbsp;<b>char</b>&nbsp;*host, <b>const</b>&nbsp;<b>char</b>&nbsp;*path, <b>const</b>&nbsp;<b>char</b>&nbsp;*action, size_t count) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_send(soap, "Custom-generated file<tt>\</tt>n"); // writes to soap<tt>-&gt;</tt>sendfd <br />
} <br />
<b>int</b>&nbsp;myparse(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;buf[256]; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(lseek(soap<tt>-&gt;</tt>recvfd, 0, SEEK_SET) &lt; 0 <tt>||</tt> soap_getline(soap, buf, 256)) // go to begin and skip custom header <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOF; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__test r; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;ns__person p; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); // reset <br />
&nbsp;&nbsp;&nbsp;p.name = "John Doe"; <br />
&nbsp;&nbsp;&nbsp;p.age = 99; <br />
&nbsp;&nbsp;&nbsp;soap.fopen = myopen; // use custom open <br />
&nbsp;&nbsp;&nbsp;soap.fpost = mypost; // use custom post <br />
&nbsp;&nbsp;&nbsp;soap.fparse = myparse; // use custom response parser <br />
&nbsp;&nbsp;&nbsp;soap.fclose = myclose; // use custom close <br />
&nbsp;&nbsp;&nbsp;soap_call_ns__test(&amp;soap, "file://test.xml", "", p, r); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stdout); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); // reset to default callbacks <br />
}
</td></tr></table><br></i>
SOAP 1.1 and 1.2 specify that XML elements may be ignored when present in a SOAP payload on the receiving side.
gSOAP ignores XML elements that are unknown, unless the XML attribute <tt>mustUnderstand="true"</tt> is present in the XML element.
It may be undesirable for elements to be ignored when the outcome of the omission is uncertain.
The <i>soap.fignore</i> callback can be set to a function that returns <i>SOAP_OK</i> in case the element can be safely ignored, or
<i>SOAP_MUSTUNDERSTAND</i> to throw an exception, or to perform some application-specific action.
For example, to throw an exception as soon as an unknown element is encountered on the input, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;myignore(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_MUSTUNDERSTAND; // never skip elements (secure) <br />
} <br />
... <br />
soap.fignore = myignore; <br />
soap_call_ns__method(&amp;soap, ...); // or soap_serve(&amp;soap);
</td></tr></table><br></i>
To selectively throw an exception as soon as an unknown element is encountered but element <tt>ns:xyz</tt> can be safely ignored, use:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;myignore(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_match_tag(soap, tag, "ns:xyz") != SOAP_OK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_MUSTUNDERSTAND; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
... <br />
soap.fignore = myignore; <br />
soap_call_ns__method(&amp;soap, ...); // or soap_serve(&amp;soap) <br />
... <br />
<b>struct</b>&nbsp;Namespace namespaces[] = <br />
{ <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, <br />
&nbsp;&nbsp;&nbsp;{"SOAP-ENC","http://schemas.xmlsoap.org/soap/encoding/"}, <br />
&nbsp;&nbsp;&nbsp;{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, <br />
&nbsp;&nbsp;&nbsp;{"xsd", "http://www.w3.org/2001/XMLSchema"}, <br />
&nbsp;&nbsp;&nbsp;{"ns", "some-URI"}, // the namespace of element ns:xyz <br />
&nbsp;&nbsp;&nbsp;{NULL, NULL} <br />
</td></tr></table><br></i>
Function <i>soap_match_tag</i> compares two tags. The third parameter may be a pattern where <i>*</i> is a wildcard
and <i>-</i> is a single character wildcard. So for example
<i>soap_match_tag(tag, "ns:*")</i> will match any element in namespace <i>ns</i> or when no namespace prefix is present in the XML
message.
<div class="p"><!----></div>
The callback can also be used to keep track of unknown elements in an internal data structure such as a list:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;Unknown <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*tag; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;Unknown *next; <br />
}; <br />
<b>int</b>&nbsp;myignore(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*tag) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*s = (<b>char</b>*)soap_malloc(soap, strlen(tag)+1); <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;Unknown *u = (<b>struct</b>&nbsp;Unknown*)soap_malloc(soap, <b>sizeof</b>(<b>struct</b>&nbsp;Unknown)); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(s &amp;&amp; u) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(s, tag); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u<tt>-&gt;</tt>tag = s; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u<tt>-&gt;</tt>next = ulist; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ulist = u; <br />
&nbsp;&nbsp;&nbsp;} <br />
} <br />
... <br />
<b>struct</b>&nbsp;soap *soap; <br />
<b>struct</b>&nbsp;Unknown *ulist = NULL; <br />
soap_init(&amp;soap); <br />
soap.fignore = myignore; <br />
soap_call_ns__method(&amp;soap, ...); // or soap_serve(&amp;soap) <br />
// print the list of unknown elements <br />
soap_end(&amp;soap); // clean up
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.8">
18.8</a>&nbsp;&nbsp;<font color="#0000FF">HTTP 1.0 and 1.1</font></h3>
<div class="p"><!----></div>
gSOAP uses HTTP 1.1 by default. You can revert to HTTP 1.0 as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
... <br />
soap.http_version = "1.0";
</td></tr></table><br></i>
This sets the HTTP version and reconfigures the engine to revert to HTTP 1.0.
Note that you cannot use HTTP chunking with HTTP 1.0.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.9">
18.9</a>&nbsp;&nbsp;<font color="#0000FF">HTTP 307 Temporary Redirect Support</font></h3>
<div class="p"><!----></div>
The client-side handling of HTTP 307 code "Temporary Redirect" and any of the redirect codes 301, 302, and 303 are not automated in gSOAP. Client application developers may want to consider adding a few lines of code to support redirects. It was decided not to automatically support redirects for the following reasons:
<ul>
<li> Redirecting a secure HTTPS address to a non-secure HTTP address via 307 creates a security vulnerability.
<div class="p"><!----></div>
</li>
<li> Cyclic redirects must be detected (e.g. allowing only a limited number of redirect levels).
<div class="p"><!----></div>
</li>
<li> Redirecting HTTP POST will result in re-serialization and re-post of the entire SOAP request. The SOAP request message must be re-posted in its entirity when re-issuing the SOAP operation to a new address.
<div class="p"><!----></div>
</li>
</ul>
To implement client-side 307 redirect, add the following lines of code:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>char</b>&nbsp;*endpoint = NULL; // use default endpoint given in WSDL (or add another one here) <br />
<b>int</b>&nbsp;n = 10; // max redirect count <br />
<b>while</b>&nbsp;(n-) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns1__myMethod(soap, endpoint, ...)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;((soap<tt>-&gt;</tt>error <tt>&gt;=</tt> 301 <tt>&amp;&amp;</tt> soap<tt>-&gt;</tt>error <tt>&lt;=</tt> 303) <tt>||</tt> soap<tt>-&gt;</tt>error == 307) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;endpoint = soap<tt>-&gt;</tt>endpoint; // endpoint from HTTP 301, 302, 303, 307 Location header <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ ... report and handle error <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.10">
18.10</a>&nbsp;&nbsp;<font color="#0000FF">HTTP GET Support</font></h3><a name="sec:get">
</a>
<div class="p"><!----></div>
A gSOAP server normally only grants HTTP (and HTTPS) POST requests. To support HTTP (HTTPS) GET, you need to set the <i>soap.fget</i> callback. The callback is required to produce a response to the request in textual form, such as a Web page or a SOAP/XML response.
<div class="p"><!----></div>
The following example produces a Web page upon a HTTP GET request (e.g. from a browser):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap *soap = soap_new(); <br />
soap<tt>-&gt;</tt>fget = http_get(); <br />
... <br />
soap_serve(soap); <br />
... <br />
<b>int</b>&nbsp;http_get(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_response(soap, SOAP_HTML); // HTTP response header with text/html <br />
&nbsp;&nbsp;&nbsp;soap_send(soap, "&lt;HTML&#62;My Web server is operational.&lt;/HTML&#62;"); <br />
&nbsp;&nbsp;&nbsp;soap_end_send(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
The example below produces a WSDL file upon a HTTP GET with path <i>?wsdl</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;http_get(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*s = strchr(soap<tt>-&gt;</tt>path, '?'); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!s <tt>||</tt> strcmp(s, "?wsdl")) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_GET_METHOD; <br />
&nbsp;&nbsp;&nbsp;fd = fopen("myservice.wsdl", "rb"); // open WSDL file to copy <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!fd) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;404; // return HTTP not found error <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>http_content = "text/xml"; // HTTP header with text/xml content <br />
&nbsp;&nbsp;&nbsp;soap_response(soap, SOAP_FILE); <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r = fread(soap<tt>-&gt;</tt>tmpbuf, 1, sizeof(soap<tt>-&gt;</tt>tmpbuf), fd); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_send_raw(soap, soap<tt>-&gt;</tt>tmpbuf, r)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; // can't send, but little we can do about that <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;fclose(fd); <br />
&nbsp;&nbsp;&nbsp;soap_end_send(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
Using one-way SOAP/XML message, you can also return a SOAP/XML response:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;http_get(<b>struct</b>&nbsp;soap *soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;((soap<tt>-&gt;</tt>omode &amp; SOAP_IO) != SOAP_IO_CHUNK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_set_omode(soap, SOAP_IO_STORE); // if not chunking we MUST buffer entire content to determine content length <br />
&nbsp;&nbsp;&nbsp;soap_response(soap, SOAP_OK); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;soap_send_ns1__mySendMethodResponse(soap, "", NULL, ... params ...); <br />
} <br />
</td></tr></table><br></i>
where <i>ns1__mySendMethodResponse</i> is a one-way message declared in a gSOAP header file as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns1__mySendMethodResponse(... params ..., <b>void</b>);
</td></tr></table><br></i>
The generated <i>soapClient.cpp</i> includes the sending-side stub function.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.11">
18.11</a>&nbsp;&nbsp;<font color="#0000FF">HTTP Keep-Alive</font></h3><a name="sec:keepalive">
</a>
<div class="p"><!----></div>
gSOAP supports keep-alive socket connections. To activate keep-alive support,
set the <i>SOAP_IO_KEEPALIVE</i> flag for both input and output modes, see Section&nbsp;<a href="#sec:flags">8.12</a>.
For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init2(&amp;soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); <br />
</td></tr></table><br></i>
When a client or a service communicates with another client or service that supports keep alive, the
attribute <i>soap.keep_alive</i> will be set to 1, otherwise it is reset to 0 (indicating that the other party
will close the connection).
The connection maybe terminated on either end before the communication completed, for example when the server keep-alive
connection has timed out.
This generates a "Broken Pipe" signal on Unix/Linux platforms. This signal can be caught with a signal handler:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
signal(SIGPIPE, sigpipe_handle);
</td></tr></table><br></i>
where, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>void</b>&nbsp;sigpipe_handle(<b>int</b>&nbsp;x) { }
</td></tr></table><br></i>
Alternatively, broken pipes can be kept silent by setting:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap.socket_flags = MSG_NOSIGNAL;
</td></tr></table><br></i>
This setting will not generate a sigpipe but read/write operations return <i>SOAP_EOF</i> instead.
Note that Win32 systems do not support signals and lack the <i>MSG_NOSIGNAL</i> flag.
The sigpipe handling and flags are not very portable.
<div class="p"><!----></div>
A connection will be kept open only if the request contains an HTTP 1.0 header
with "<tt>Connection: Keep-Alive</tt>" or an HTTP 1.1 header that does not contain
"<tt>Connection: close</tt>". This means that a gSOAP client method call should
use "<tt>http://</tt>" in the endpoint URL of the request to the stand-alone
service to ensure HTTP headers are used.
<div class="p"><!----></div>
If the client does not close the connection, the server will wait forever when
no <i>recv_timeout</i> is specified. In addition, other clients will be denied
service as long as a client keeps the connection to the server open. To
prevent this from happening, the service should be multi-threaded such that
each thread handles the client connection:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;**argv) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap, *tsoap; <br />
&nbsp;&nbsp;&nbsp;pthread_t tid; <br />
&nbsp;&nbsp;&nbsp;int m, s; <br />
&nbsp;&nbsp;&nbsp;soap_init2(&amp;soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); <br />
&nbsp;&nbsp;&nbsp;soap.max_keep_alive = 100; // optional: at most 100 calls per keep-alive session <br />
&nbsp;&nbsp;&nbsp;soap.accept_timeout = 600; // optional: let server time out after ten minutes of inactivity <br />
&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, 18000, BACKLOG); // use port 18000 on the current machine <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(m &lt; 0) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Socket&nbsp;connection&nbsp;successful&nbsp;%d\n"</tt>, m); <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(count = 0; count &gt; = 0; count++) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.socket_flags = MSG_NOSIGNAL; // use this <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap.accept_flags = SO_NOSIGPIPE; // or this to prevent sigpipe <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(s &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.errnum) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Server&nbsp;timed&nbsp;out\n"</tt>); // Assume timeout is long enough for threads to complete serving requests <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, <tt>"Accepts&nbsp;socket&nbsp;%d&nbsp;connection&nbsp;from&nbsp;IP&nbsp;%d.%d.%d.%d\n"</tt>, s, (<b>int</b>)(soap.ip &gt;&gt; 24)&amp;0xFF, (<b>int</b>)(soap.ip &gt;&gt; 16)&amp;0xFF, (<b>int</b>)(soap.ip &gt;&gt; 8)&amp;0xFF, (<b>int</b>)soap.ip&amp;0xFF); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tsoap = soap_copy(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid, NULL, (void*(*)(void*))process_request, (void*)tsoap); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>void</b>&nbsp;*process_request(<b>void</b>&nbsp;*soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;pthread_detach(pthread_self()); <br />
&nbsp;&nbsp;&nbsp;((<b>struct</b>&nbsp;soap*)soap)<tt>-&gt;</tt>recv_timeout = 300; // Timeout after 5 minutes stall on recv <br />
&nbsp;&nbsp;&nbsp;((<b>struct</b>&nbsp;soap*)soap)<tt>-&gt;</tt>send_timeout = 60; // Timeout after 1 minute stall on send <br />
&nbsp;&nbsp;&nbsp;soap_serve((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_destroy((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_end((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_done((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;free(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
}
</td></tr></table><br></i>
To prevent a malicious client from keeping a thread waiting forever by keeping
the connection open, timeouts are set in the <i>process_request</i> routine.
See Section&nbsp;<a href="#sec:timeout">18.17</a> for more details on timeout settings.
<div class="p"><!----></div>
A gSOAP client call will automatically attempt to re-establish a connection to
a server when the server has terminated the connection for any reason. This
way, a sequence of calls can be made to the server while keeping the connection
open. Client stubs will poll the server to check if the connection is still
open. When the connection was terminated by the server, the client will
automatically reconnect.
<div class="p"><!----></div>
A client should reset <i>SOAP_IO_KEEPALIVE</i> just before the last call to a
server to close the connection after this last call. This will close the socket
after the call and also informs the server to gracefully close the connection.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.12">
18.12</a>&nbsp;&nbsp;<font color="#0000FF">HTTP Chunked Transfer Encoding</font></h3><a name="sec:chunked">
</a>
<div class="p"><!----></div>
gSOAP supports HTTP chunked transfer encoding. Un-chunking of inbound messages
takes place automatically. Outbound messages are never chunked, except when the
<i>SOAP_IO_CHUNK</i> flag is set for the output mode. Most Web services,
however, will not accept chunked inbound messages.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.13">
18.13</a>&nbsp;&nbsp;<font color="#0000FF">HTTP Buffered Sends</font></h3>
<div class="p"><!----></div>
The entire outbound message can be stored to determine the HTTP content length
rather than the two-phase encoding used by gSOAP which requires a separate pass
over the data to determine the length of the outbound message. Setting the
flag <i>SOAP_IO_STORE</i> for the output mode will buffer the entire message.
This can speed up the transmission of messages, depending on the content, but
may require significant storage space to hold the verbose XML message.
<div class="p"><!----></div>
Zlib compressed transfers require buffering. The <i>SOAP_IO_STORE</i> flag is
set when the <i>SOAP_ENC_ZLIB</i> flag is set to send compressed messages. The use of chunking
significantly reduces memory usage and may speed up the transmission of compressed SOAP/XML messages.
This is accomplished by setting the <i>SOAP_IO_CHUNK</i> flag with
<i>SOAP_ENC_ZLIB</i> for the output mode.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.14">
18.14</a>&nbsp;&nbsp;<font color="#0000FF">HTTP Authentication</font></h3>
<div class="p"><!----></div>
HTTP authentication (basic) is enabled at the client-side by setting the
<i>soap.userid</i> and <i>soap.passwd</i> strings to a username and password,
respectively. A server may request user authentication
and denies access (HTTP 401 error) when the client tries to connect without HTTP authentication (or with the wrong authentication information).
<div class="p"><!----></div>
Here is an example client code fragment to set the HTTP authentication username and password:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.userid = "guest"; <br />
soap.passwd = "visit"; <br />
...
</td></tr></table><br></i>
A client SOAP request will have the following HTTP header:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
POST /XXX HTTP/1.0 <br />
Host: YYY <br />
User-Agent: gSOAP/2.2 <br />
Content-Type: text/xml; charset=utf-8 <br />
Content-Length: nnn <br />
Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= <br />
...
</td></tr></table><br></tt>
A client MUST set the <i>soap.userid</i> and <i>soap.passwd</i> strings for each call that requires client authentication. The strings are reset after each successful or unsuccessful call.
<div class="p"><!----></div>
When present, the value of the <i>WWW-Authenticate</i> HTTP header with the authentication realm can be obtained from the <i>soap.authrealm</i> string. This is useful for clients to respond intelligently to authentication requests.
<div class="p"><!----></div>
A stand-alone gSOAP Web Service can enforce HTTP authentication upon clients, by checking the <i>soap.userid</i> and <i>soap.passwd</i> strings. These strings are set when a client request contains HTTP authentication headers. The strings SHOULD be checked in each service method (that requires authentication to execute).
<div class="p"><!----></div>
Here is an example service method implementation that enforced client authentication:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;ns__method(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap<tt>-&gt;</tt>.userid <tt>||</tt> !soap<tt>-&gt;</tt>.passwd <tt>||</tt>
strcmp(soap<tt>-&gt;</tt>.userid, "guest") <tt>||</tt>
strcmp(soap<tt>-&gt;</tt>.passwd, "visit"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;401;
... <br />
}
</td></tr></table><br></i>
When the authentication fails, the service response with a SOAP Fault message and a HTTP error code "401 Unauthorized".
The HTTP error codes are described in Section&nbsp;<a href="#sec:errcodes">9.2</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.15">
18.15</a>&nbsp;&nbsp;<font color="#0000FF">HTTP Proxy Authentication</font></h3>
<div class="p"><!----></div>
HTTP proxy authentication (basic) is enabled at the client-side by setting the
<i>soap.proxy_userid</i> and <i>soap.proxy_passwd</i> strings to a username and
password, respectively. For example, a proxy server may request user
authentication. Otherwise, access is denied by the proxy (HTTP 407 error).
Example client code fragment to set proxy server, username, and password:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.proxy_host = "xx.xx.xx.xx"; // IP <br />
soap.proxy_port = 8080; <br />
soap.proxy_userid = "guest"; <br />
soap.proxy_passwd = "guest"; <br />
...
</td></tr></table><br></i>
A client SOAP request will have the following HTTP header:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0B0D0"><tr><td><tt>
POST /XXX HTTP/1.0 <br />
Host: YYY <br />
User-Agent: gSOAP/2.2 <br />
Content-Type: text/xml; charset=utf-8 <br />
Content-Length: nnn <br />
Proxy-Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= <br />
...
</td></tr></table><br></tt>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.16">
18.16</a>&nbsp;&nbsp;<font color="#0000FF">Speed Improvement Tips</font></h3>
<div class="p"><!----></div>
Here are some tips you can use to speed up gSOAP. gSOAP's default settings are choosen to maximize portability and compatibility. The settings can be tweaked to optimize the performance as follows:
<ul>
<li> Increase the buffer size <i>SOAP_BUFLEN</i> by changing the <i>SOAP_BUFLEN</i> macro in <i>stdsoap2.h</i>. Use buffer size 2<sup>1</sup>8=262144 for example.
<div class="p"><!----></div>
</li>
<li> Use HTTP keep-alive at the client-side, see&nbsp;<a href="#sec:keepalive">18.11</a>, when the client needs to make a series of calls to the same server. Server-side keep-alive support can greatly improve performance of both client and server. But be aware that clients and services under Unix/Linux require signal handlers to catch dropped connections.
<div class="p"><!----></div>
</li>
<li> Use HTTP chunked transfers, see&nbsp;<a href="#sec:chunked">18.12</a>.
<div class="p"><!----></div>
</li>
<li> Do NOT use gzip compression, even when transferring data over a modem connection. Modems already compress data transfers.
<div class="p"><!----></div>
</li>
</ul>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.17">
18.17</a>&nbsp;&nbsp;<font color="#0000FF">Timeout Management for Non-Blocking Operations</font></h3><a name="sec:timeout">
</a>
<div class="p"><!----></div>
Socket connect, accept, send, and receive timeout values can be set to manage
socket communication timeouts. The <i>soap.connect_timeout</i>,
<i>soap.accept_timeout</i>, <i>soap.send_timeout</i>, and
<i>soap.recv_timeout</i> attributes of the current gSOAP runtime environment
<i>soap</i> can be set to the appropriate user-defined socket send, receive, and
accept timeout values. A positive value measures the timeout in seconds. A
negative timeout value measures the timeout in microseconds (10<sup><font face="symbol">-</font
>6</sup> sec).
<div class="p"><!----></div>
The <i>soap.connect_timeout</i> specifies the timeout value for
<i>soap_call_ns__method</i> calls.
<div class="p"><!----></div>
The <i>soap.accept_timeout</i> specifies the timeout value for
<i>soap_accept(&amp;soap)</i> calls.
<div class="p"><!----></div>
The <i>soap.send_timeout</i> and <i>soap.recv_timeout</i> specify the timeout
values for non-blocking socket I/O operations.
<div class="p"><!----></div>
Example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.send_timeout = 10; <br />
soap.recv_timeout = 10;
</td></tr></table><br></i>
This will result in a timeout if no data can be send in 10 seconds and no data is received within 10 seconds after initiating
a send or receive operation over the socket. A value of zero disables timeout, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap.send_timeout = 0; <br />
soap.recv_timeout = 0;
</td></tr></table><br></i>
When a timeout occurs in send/receive operations, a <i>SOAP_EOF</i> exception will be raised ("end of file or no input").
Negative timeout values measure timeouts in microseconds, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define uSec *-1 <br />
#define mSec *-1000 <br />
soap.accept_timeout = 10 uSec; <br />
soap.send_timeout = 20 mSec; <br />
soap.recv_timeout = 20 mSec;
</td></tr></table><br></i>
The macros improve readability.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: Many Linux versions do not support non-blocking <i>connect()</i>. Therefore, setting <i>soap.connect_timeout</i> for
non-blocking <i>soap_call_ns__method</i> calls may not work under Linux.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.18">
18.18</a>&nbsp;&nbsp;<font color="#0000FF">Socket Options and Flags</font></h3>
<div class="p"><!----></div>
gSOAP's socket communications can be controlled with socket options and flags.
The gSOAP run-time environment <i><b>struct</b>&nbsp;soap</i> flags are:
<i><b>int</b>&nbsp;soap.socket_flags</i> to control socket send() and recv() calls,
<i><b>int</b>&nbsp;soap.connect_flags</i> to set client connection socket options,
<i><b>int</b>&nbsp;soap.bind_flags</i> to set server-side port bind socket options,
<i><b>int</b>&nbsp;soap.accept_flags</i> to set server-side request message accept
socket options. See the manual pages of <i>send</i> and <i>recv</i> for
<i>soap.socket_flags</i> values and see the manual pages of
<i>setsockopt</i> for
<i>soap.connect_flags</i>, <i>soap.bind_flags</i>, and
<i>soap.accept_flags</i> (SOL_SOCKET) values.
These <i>SO_</i> socket option flags (see <i>setsockopt</i> manual pages)
can be bit-wise or-ed to set multiple
socket options at once.
The client-side flag <i>soap.connect_flags=SO_LINGER</i> is supported with values <i>l_onoff=1</i> and <i>l_linger=0</i>.
<div class="p"><!----></div>
For example, to disable sigpipe signals on Unix/Linux platforms use:
<i>soap.socket_flags=MSG_NOSIGNAL</i> and/or
<i>soap.connect_flags=SO_NOSIGPIPE</i> (i.e.&nbsp;client-side connect) depending
on your platform.
<div class="p"><!----></div>
Use <i>soap.bind_flags=SO_REUSEADDR</i> to enable server-side port reuse and
local port
sharing (but be aware of the security issues when the port is not blocked by a
firewall and open to the Internet).
<div class="p"><!----></div>
<h3><a name="tth_sEc18.19">
18.19</a>&nbsp;&nbsp;<font color="#0000FF">Secure SOAP Web Services with HTTPS/SSL</font></h3>&nbsp;<a name="sec:serveropenssl">
</a>
<div class="p"><!----></div>
When a Web Service is installed as CGI, it uses standard I/O that is encrypted/decrypted by the Web server that runs the CGI
application.
Therefore, HTTPS/SSL support must be configured for the Web server (not CGI-based Web Service application itself).
<div class="p"><!----></div>
To enable OpenSSL, first install OpenSSL and use option <i>-DWITH_OPENSSL</i> to compile the sources with your C or C++ compiler, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_OPENSSL -o myprog myprog.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lssl -lcrypto</i>
</td></tr></table><br></span>
SSL support for stand-alone gSOAP Web services is enabled by calling <i>soap_ssl_accept</i> after <i>soap_accept</i>.
In addition, a key file, a CA file (or path to certificates), DH file (if RSA is not used), and password need to be supplied. Instructions on how to do this can be found in the
OpenSSL documentation <i>http://www.openssl.org</i>. See also Section&nbsp;<a href="#sec:ssl">18.22</a>.
<div class="p"><!----></div>
Let's take a look at an example SSL secure
multi-threaded stand-alone SOAP Web Service:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;m, s; <br />
&nbsp;&nbsp;&nbsp;pthread_t tid; <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap, *tsoap; <br />
&nbsp;&nbsp;&nbsp;soap_ssl_init(); /* init OpenSSL (just once) */<br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(CRYPTO_thread_setup()) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Cannot setup thread mutex\n"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_ssl_server_context(&amp;soap, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOAP_SSL_DEFAULT, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"server.pem", /* keyfile: required when server must authenticate to clients (see SSL docs on how to obtain this file) */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password", /* password to read the key file */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"cacert.pem", /* optional cacert file to store trusted certificates */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, /* optional capath to directory with trusted certificates */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"dh512.pem", /* DH file, if NULL use RSA */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, /* if randfile!=NULL: use a file with random data to seed randomness */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL /* optional server identification to enable SSL session cache (must be a unique name) */
&nbsp;&nbsp;&nbsp;)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, 18000, 100); // use port 18000 <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(m &lt; 0) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;fprintf(stderr, "Socket connection successful: master socket = %d<tt>\</tt>n", m); <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(;;) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Socket connection successful: slave socket = %d<tt>\</tt>n", s); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(s &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tsoap = soap_copy(&amp;soap); /* should call soap_ssl_accept on a copy */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!tsoap) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>break</b>; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_ssl_accept(tsoap)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(tsoap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_done(tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(tsoap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>continue</b>; /* when soap_ssl_accept fails, we should just go on */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;tid, NULL, &amp;process_request, (<b>void</b>*)tsoap); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap_done(&amp;soap); /* deallocates SSL context */<br />
&nbsp;&nbsp;&nbsp;CRYPTO_thread_cleanup(); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>void</b>&nbsp;*process_request(<b>void</b>&nbsp;*soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;pthread_detach(pthread_self()); <br />
&nbsp;&nbsp;&nbsp;soap_serve((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_destroy((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_end((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;soap_done((<b>struct</b>&nbsp;soap*)soap); <br />
&nbsp;&nbsp;&nbsp;free(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;NULL; <br />
}
</td></tr></table><br></i>
The <i>soap_ssl_server_context</i> function initializes the server-side SSL context. The <i>server.pem</i> key file is the server's private key. The <i>cacert.pem</i> is used to authenticate clients and contains the client certificates. Alternatively a directory name can be specified. This directory is assumed to contain the certificates. The <i>dh512.pem</i> file specifies that DH will be used for key agreement instead of RSA. The randfile entry can be used to seed the PRNG. The last entry enable server-side session caching. A unique server name is required.
<div class="p"><!----></div>
The <i>CRYPTO_thread_setup()</i> and <i>CRYPTO_thread_cleanup()</i> routines can be found in <i>openssl/crypto/threads/th-lock.c</i>. These routines are required to setup locks for multi-threaded applications that use SSL.
We give a Windows and POSIX threads implementation of these here:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include &lt; unistd.h &gt; /* defines _POSIX_THREADS if pthreads are available */ <br />
#ifdef _POSIX_THREADS <br />
# include &lt; pthread.h &gt; <br />
#endif <br />
#if defined(WIN32) <br />
# define MUTEX_TYPE HANDLE <br />
# define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL) <br />
# define MUTEX_CLEANUP(x) CloseHandle(x) <br />
# define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE) <br />
# define MUTEX_UNLOCK(x) ReleaseMutex(x) <br />
# define THREAD_ID GetCurrentThreadID() <br />
#elif defined(_POSIX_THREADS) <br />
# define MUTEX_TYPE pthread_mutex_t <br />
# define MUTEX_SETUP(x) pthread_mutex_init(&amp;(x), NULL) <br />
# define MUTEX_CLEANUP(x) pthread_mutex_destroy(&amp;(x)) <br />
# define MUTEX_LOCK(x) pthread_mutex_lock(&amp;(x)) <br />
# define MUTEX_UNLOCK(x) pthread_mutex_unlock(&amp;(x)) <br />
# define THREAD_ID pthread_self() <br />
#else <br />
# error "You must define mutex operations appropriate for your platform" <br />
# error "See OpenSSL /threads/th-lock.c on how to implement mutex on your platform" <br />
#endif <br />
<b>struct</b>&nbsp;CRYPTO_dynlock_value { MUTEX_TYPE mutex; }; <br />
<b>static</b>&nbsp;MUTEX_TYPE *mutex_buf; <br />
<b>static</b>&nbsp;<b>struct</b>&nbsp;CRYPTO_dynlock_value *dyn_create_function(<b>const</b>&nbsp;<b>char</b>&nbsp;*file, <b>int</b>&nbsp;line) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;CRYPTO_dynlock_value *value; <br />
&nbsp;&nbsp;&nbsp;value = (<b>struct</b>&nbsp;CRYPTO_dynlock_value*)malloc(<b>sizeof</b>(<b>struct</b>&nbsp;CRYPTO_dynlock_value)); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(value) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_SETUP(value<tt>-&gt;</tt>mutex); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;value; <br />
} <br />
<b>static</b>&nbsp;<b>void</b>&nbsp;dyn_lock_function(<b>int</b>&nbsp;mode, <b>struct</b>&nbsp;CRYPTO_dynlock_value *l, <b>const</b>&nbsp;<b>char</b>&nbsp;*file, <b>int</b>&nbsp;line) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(mode &amp; CRYPTO_LOCK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_LOCK(l<tt>-&gt;</tt>mutex); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_UNLOCK(l<tt>-&gt;</tt>mutex); <br />
} <br />
<b>static</b>&nbsp;<b>void</b>&nbsp;dyn_destroy_function(<b>struct</b>&nbsp;CRYPTO_dynlock_value *l, <b>const</b>&nbsp;<b>char</b>&nbsp;*file, <b>int</b>&nbsp;line) <br />
{ <br />
&nbsp;&nbsp;&nbsp;MUTEX_CLEANUP(l<tt>-</tt>&#62;mutex); <br />
&nbsp;&nbsp;&nbsp;free(l); <br />
} <br />
<b>void</b>&nbsp;locking_function(<b>int</b>&nbsp;mode, <b>int</b>&nbsp;n, <b>const</b>&nbsp;<b>char</b>&nbsp;*file, <b>int</b>&nbsp;line) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(mode &amp; CRYPTO_LOCK) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_LOCK(mutex_buf[n]); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_UNLOCK(mutex_buf[n]); <br />
} <br />
<b>unsigned</b>&nbsp;<b>long</b>&nbsp;id_function() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;(<b>unsigned</b>&nbsp;<b>long</b>)THREAD_ID; <br />
} <br />
<b>int</b>&nbsp;CRYPTO_thread_setup() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;i; <br />
&nbsp;&nbsp;&nbsp;mutex_buf = (MUTEX_TYPE*)malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!mutex_buf) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOM; <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; CRYPTO_num_locks(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_SETUP(mutex_buf[i]); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_id_callback(id_function); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_locking_callback(locking_function); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_create_callback(dyn_create_function); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_lock_callback(dyn_lock_function); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>void</b>&nbsp;CRYPTO_thread_cleanup() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;i; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!mutex_buf) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>; <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_id_callback(NULL); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_locking_callback(NULL); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_create_callback(NULL); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_lock_callback(NULL); <br />
&nbsp;&nbsp;&nbsp;CRYPTO_set_dynlock_destroy_callback(NULL); <br />
&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(i = 0; i &lt; CRYPTO_num_locks(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MUTEX_CLEANUP(mutex_buf[i]); <br />
&nbsp;&nbsp;&nbsp;free(mutex_buf); <br />
&nbsp;&nbsp;&nbsp;mutex_buf = NULL; <br />
}
</td></tr></table><br></i>
For Unix and Linux, make sure you have signal handlers set in your service and/or client applications to catch broken connections (<i>SIGPIPE</i>):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
signal(SIGPIPE, sigpipe_handle);
</td></tr></table><br></i>
where, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>void</b>&nbsp;sigpipe_handle(<b>int</b>&nbsp;x) { }
</td></tr></table><br></i>
By default, clients are not required to authenticate. To support client authentication use the following:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_ssl_server_context(&amp;soap, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"server.pem", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"cacert.pem", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"dh512.pem", <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL <br />
&nbsp;&nbsp;&nbsp;)) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;}
</td></tr></table><br></i>
This requires each client to authenticate with its certificate.
<div class="p"><!----></div>
The <i>cacert</i> file and <i>capath</i> are optional. Either one can be
specified when clients must run on non-trusted systems. We want to avoid
storing trusted certificates in the default location on the file system when
that is not secure. Therefore, a flat <i>cacert.pem</i> file or directory can be
specified to store trusted certificates.
<div class="p"><!----></div>
The gSOAP distribution includes a <i>cacerts.pem</i> file with the certificates
of all certificate authorities such as Verisign. You can use this file to
verify the authentication of servers that provide certificates issued by these
CAs.
<div class="p"><!----></div>
The <i>cacert.pem</i>, <i>client.pem</i>, and <i>server.pem</i> files in the gSOAP
distribution are examples of self-signed certificates.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: it is important that the <i>WITH_OPENSSL</i> macro MUST be consistently defined to
compile the sources, such as <i>stdsoap2.cpp</i>, <i>soapC.cpp</i>,
<i>soapClient.cpp</i>, <i>soapServer.cpp</i>, and all application sources that
include <i>stdsoap2.h</i> or <i>soapH.h</i>. If the macros are not consistently
used, the application will crash due to a mismatches in the declaration and
access of the gSOAP environment.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.20">
18.20</a>&nbsp;&nbsp;<font color="#0000FF">Secure SOAP Clients with HTTPS/SSL</font></h3><a name="sec:clientopenssl">
</a>
<div class="p"><!----></div>
You need to install the OpenSSL library on your platform to enable secure SOAP clients to utilize HTTPS/SSL.
After installation, compile all the sources of your application with option <i>-DWITH_OPENSSL</i>. For example on Linux:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_OPENSSL myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lssl -lcrypto</i>
</td></tr></table><br></span>
or Unix:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_OPENSSL myclient.cpp stdsoap.cpp soapC.cpp soapClient.cpp -lxnet -lsocket -lnsl -lssl -lcrypto</i>
</td></tr></table><br></span>
or you can add the following line to <i>soapdefs.h</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define WITH_OPENSSL
</td></tr></table><br></i>
and compile with option <i>-DWITH_SOAPDEFS_H</i> to include <i>soapdefs.h</i> in your project.
A client program simply uses the prefix <i>https:</i> instead of <i>http:</i> in the endpoint URL of a remote method call to a
Web Service to use encrypted transfers (if the service supports HTTPS). You need to specify the client-side key file and password of the keyfile:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_ssl_init(); /* init OpenSSL (just once) */<br />
<b>if</b>&nbsp;(soap_ssl_client_context(&amp;soap, <br />
&nbsp;&nbsp;&nbsp;SOAP_SSL_DEFAULT, <br />
&nbsp;&nbsp;&nbsp;"client.pem", /* keyfile: required only when client must authenticate to server (see SSL docs on how to obtain this file) */ <br />
&nbsp;&nbsp;&nbsp;"password", /* password to read the key file */ <br />
&nbsp;&nbsp;&nbsp;"cacert.pem", /* optional cacert file to store trusted certificates (needed to verify server) */
&nbsp;&nbsp;&nbsp;NULL, /* optional capath to direcoty with trusted certificates */ <br />
&nbsp;&nbsp;&nbsp;NULL /* if randfile!=NULL: use a file with random data to seed randomness */ <br />
)) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;exit(1); <br />
} <br />
soap_call_ns__mymethod(&amp;soap, "https://domain/path/secure.cgi", "", ...);
</td></tr></table><br></i>
<div class="p"><!----></div>
By default, server authentication is enabled. To disable server authentication for testing purposes, use the following:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>if</b>&nbsp;(soap_ssl_client_context(&amp;soap, <br />
&nbsp;&nbsp;&nbsp;SOAP_SSL_NO_AUTHENTICATION, <br />
&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;NULL, <br />
&nbsp;&nbsp;&nbsp;NULL <br />
)) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;exit(1); <br />
} <br />
</td></tr></table><br></i>
This also assumes that the server does not require clients to authenticate (the keyfile is absent).
<div class="p"><!----></div>
The <i>cacert</i> file and <i>capath</i> are optional. Either one can be specified when clients must run on non-trusted systems. We want to avoid storing trusted certificates in the default location on the file system when that is not secure. Therefore, a flat <i>cacert.pem</i> file or directory can be specified to store trusted certificates.
<div class="p"><!----></div>
Make sure you have signal handlers set in your application to catch broken connections (<i>SIGPIPE</i>):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
signal(SIGPIPE, sigpipe_handle);
</td></tr></table><br></i>
where, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>void</b>&nbsp;sigpipe_handle(<b>int</b>&nbsp;x) { }
</td></tr></table><br></i>
<font color="#FF0000"><b>Caution</b></font>: it is important that the <i>WITH_OPENSSL</i> macro MUST be consistently defined to
compile the sources, such as <i>stdsoap2.cpp</i>, <i>soapC.cpp</i>,
<i>soapClient.cpp</i>, <i>soapServer.cpp</i>, and all application sources that
include <i>stdsoap2.h</i> or <i>soapH.h</i>. If the macros are not consistently
used, the application will crash due to a mismatches in the declaration and
access of the gSOAP environment.
<font color="#FF0000"><b>Caution</b></font>: concurrent client calls MUST be made using separate soap structs copied with <i>soap_copy</i> from an originating struct initialized with <i>soap_ssl_client_context</i>. In addition, the thread initialization code discussed in Section&nbsp;<a href="#sec:serveropenssl">18.19</a> MUST be used to properly setup OpenSSL in a multi-threaded client application.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.21">
18.21</a>&nbsp;&nbsp;<font color="#0000FF">SSL Authentication Callback</font></h3>
<div class="p"><!----></div>
gSOAP provides a callback function for authentication initialization:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Callback (function pointer)</b></font> </td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;(*soap.fsslauth)(<b>struct</b>&nbsp;soap *soap)</i> </td></tr>
<tr><td width="602">Initialize the authentication information for clients and services, such as the
certificate chain, password, read the key and/or DH file, generate an RSA key,
and initialization of the RNG. Should return a gSOAP error code or
<i>SOAP_OK</i>. Built-in gSOAP function: <i>ssl_auth_init</i>
</td></tr></table>
</td></tr></table><br></span>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.22">
18.22</a>&nbsp;&nbsp;<font color="#0000FF">SSL Certificates</font></h3><a name="sec:ssl">
</a>
<div class="p"><!----></div>
The gSOAP distribution includes a <i>cacerts.pem</i> file with the certificates
of all certificate authorities (such as Verisign). You can use this file to
verify the authentication of servers that provide certificates issued by these
CAs. Just set the <i>cafile</i> parameter to the location of this file on your file system.
Therefore, when you obtain a certifice signed by a trusted CA such as Verisign, you
can simply use the <i>cacerts.pem</i> file to develop client applications
that can verify the authenticity of your server.
<div class="p"><!----></div>
The other <i>.pem</i> files in the gSOAP distribution are examples
of self-signed certificates for testing purposes (<i>cacert.pem</i>, <i>client.pem</i>, <i>server.pem</i>).
<div class="p"><!----></div>
You can also create your own self-signed certificates.
There is more than one way to generate the necessary files for clients and servers.
See <i>http://www.openssl.org</i> for information on OpenSSL and
<i>http://sial.org/howto/openssl/ca/</i> on how to setup and manage a local CA
and <i>http://sial.org/howto/openssl/self-signed/</i> on how to setup self-signed
test certificates.
<div class="p"><!----></div>
It is also possible to convert IIS-generated certificates to PEM format, see <i>http://www.icewarp.com/Knowledgebase/617.htm</i> for a discussion and examples.
<div class="p"><!----></div>
Here is the simplest way to setup self-signed certificates. First you need to create a private Certificate Authority (CA). The CA is used in SSL to verify the authenticity of a given
certificate. The CA acts as a trusted third party who has authenticated the
user of the signed certificate as being who they say. The certificate is
signed by the CA, and if the client trusts the CA, it will trust your
certificate. For use within your organization, a private CA will probably
serve your needs. However, if you intend use your certificates for a public
service, you should probably obtain a certificate from a known CA (e.g.&nbsp;VeriSign).
In addition to identification, your certificate is also used for encryption.
<div class="p"><!----></div>
Creating certificates should be done through a CA to obtain signed certificates. But you can create your own certificates for testing purposes as follows.
<ul>
<li> Go to the OpenSSL bin directory (<i>/usr/local/ssl</i> by default and
<i>/System/Library/OpenSSL</i> on Mac OS X)
<div class="p"><!----></div>
</li>
<li> There should be a file called openssl.cnf
<div class="p"><!----></div>
</li>
<li> Create a new directory in your home account, e.g. $HOME/CA, and copy the openssl.cnf file to this directory
<div class="p"><!----></div>
</li>
<li> Modify openssl.cnf by changing the 'dir' value to HOME/CA
<div class="p"><!----></div>
</li>
<li> Copy the README.txt, root.sh, and cert.sh scripts from the gSOAP distribution package located in the samples/ssl directory to HOME/CA
<div class="p"><!----></div>
</li>
<li> Follow the README.txt instructions
<div class="p"><!----></div>
</li>
</ul>
You now have a self-signed CA root certificate cacert.pem and a server.pem (or client.pem) certificate in PEM format.
The cacert.pem certificate is used in the <i>cafile</i> parameter of the <i>soap_ssl_client_context</i> (or <i>soap_ssl_server_context</i>) at the client (or server) side to verify the authenticity of the peer. You can also provide a capath parameter to these trusted certificates. The server.pem (or client.pem) must be provided with the <i>soap_ssl_server_context</i> at the server side (or <i>soap_ssl_client_context</i> at the client side) together with the password you entered when generating the certificate using cert.sh to access the file. These certificates must be present to grant authentication requests by peers. In addition, the server.pem (and client.pem) include the host name of the machine on which the application runs (e.g. localhost), so you need to generate new certificates when migrating a server (or client).
<div class="p"><!----></div>
Finally you need to generate Diffie-Helmann parameters for the server if you don't want to use RSA.
Do the following at the prompt:
<div class="p"><!----></div>
<i>openssl dhparam -outform PEM -out dh.pem 512</i>
<div class="p"><!----></div>
File <i>dh512.pem</i> is the output file and 512 is the number of bits used.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.23">
18.23</a>&nbsp;&nbsp;<font color="#0000FF">SSL Hardware Acceleration</font></h3>
<div class="p"><!----></div>
You can specify a hardware engine to enable hardware support for cryptographic acceleration. This can be done once in a server or client with the following statements:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>static</b>&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;*engine = "cswift"; /* engine name */ <br />
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;ENGINE *e; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!(e = ENGINE_by_id(engine))) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Error finding engine %s\n", engine); <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<b>if</b>&nbsp;(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Error using engine %s\n", engine); <br />
&nbsp;&nbsp;&nbsp;...
</td></tr></table><br></i>
The following table lists the names of the hardware and software engines:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Name</b></font> </td><td width="501"><font color="#FF0000"><b>Description</b></font> </td></tr>
<tr><td>openssl </td><td width="501">The default software engine for cryptographic operations </td></tr>
<tr><td>openbsd_dev_crypto </td><td width="501">OpenBSD supports kernel level cryptography </td></tr>
<tr><td>cswift </td><td width="501">CryptoSwift acceleration hardware </td></tr>
<tr><td>chil </td><td width="501">nCipher CHIL acceleration hardware </td></tr>
<tr><td>atalla </td><td width="501">Compaq Atalla acceleration hardware </td></tr>
<tr><td>nuron </td><td width="501">Nuron acceleration hardware </td></tr>
<tr><td>ubsec </td><td width="501">Broadcom uBSec acceleration hardware </td></tr>
<tr><td>aep </td><td width="501">Aep acceleration hardware </td></tr>
<tr><td>sureware </td><td width="501">SureWare acceleration hardware </td></tr></table>
</td></tr></table><br></span>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.24">
18.24</a>&nbsp;&nbsp;<font color="#0000FF">SSL on Windows</font></h3>
<div class="p"><!----></div>
Set the full path to libssl.lib and libcrypto.lib
under the MSVC++ "Projects" menu, then choose "Link": &#214;bject/Modules". The path
to libssl32.dll and libeay32.dll need to be specified in the PATH
environment variable when running gSOAP applications.
<div class="p"><!----></div>
Alternatively, you can use the WinInet interface available in the <i>mod_gsoap</i> directory of the gSOAP package. API instructions are included in the source.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.25">
18.25</a>&nbsp;&nbsp;<font color="#0000FF">Zlib Compression</font></h3><a name="sec:compression">
</a>
<div class="p"><!----></div>
To enable deflate and gzip compression with Zlib, install Zlib from
<tt>http://www.zlib.org</tt> if not already installed on your system. Compile
<i>stdsoap2.cpp</i> (or <i>stdsoap2.c</i>) and <b>all</b> your sources that include
<i>stdsoap2.h</i> or <i>soapH.h</i> with compiler option <i>-DWITH_GZIP</i> and
link your code with the Zlib library, e.g. <i>-lz</i> on Unix/Linux platforms.
<div class="p"><!----></div>
The gzip compression is orthogonal to all transport encodings such as HTTP,
SSL, DIME, and can be used with other transport layers. You can even save and
load compressed XML data to/from files.
<div class="p"><!----></div>
gSOAP supports two compression formats: deflate and gzip. The gzip format is
used by default. The gzip format has several benefits over deflate. Firstly,
gSOAP can automatically detect gzip compressed inbound messages, even without
HTTP headers, by checking for the presence of a gzip header in the message
content. Secondly, gzip includes a CRC32 checksum to ensure messages have been
correctly received. Thirdly, gzip compressed content can be decompressed with
other compression software, so you can decompress XML data saved by gSOAP in
gzip format.
<div class="p"><!----></div>
Gzip compression is enabled by compiling the sources with <i>-DWITH_GZIP</i>.
To transmit gzip compressed SOAP/XML data, set the output mode flags to
<i>SOAP_ENC_ZLIB</i>. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_init(&amp;soap); <br />
... <br />
soap_set_omode(&amp;soap, SOAP_ENC_ZLIB); // enable Zlib's gzip <br />
<b>if</b>&nbsp;(soap_call_ns__myMethod(&amp;soap, ...)) <br />
... <br />
soap_clr_omode(&amp;soap, SOAP_ENC_ZLIB); // disable Zlib's gzip <br />
...
</td></tr></table><br></i>
This will send a compressed SOAP/XML request to a service, provided that Zlib is
installed and linked with the application and the <i>-DWITH_GZIP</i> option was used to compile the sources.
Receiving compressed SOAP/XML over HTTP either in gzip or deflate formats is automatic. The <i>SOAP_ENC_ZLIB</i> flag does not have
to be set at the server side to accept compressed messages. Reading and receiving gzip compressed SOAP/XML without HTTP headers (e.g. with other transport protocols) is also automatic.
<div class="p"><!----></div>
To control the level of compression for outbound messages, you can set the <i>soap.z_level</i> to a value between 1 and 9, where 1 is the best speed and 9 is the best compression (default is 6). For example
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_init(&amp;soap); <br />
... <br />
soap_set_omode(&amp;soap, SOAP_ENC_ZLIB); <br />
soap.z_level = 9; // best compression <br />
...
</td></tr></table><br></i>
To verify and monitor compression rates, you can use the values <i>soap.z_ratio_in</i> and <i>soap.z_ratio_out</i>. These two float values lie between 0.0 and 1.0 and express the ratio of the compressed message length over uncompressed message length.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_call_ns__myMethod(&amp;soap, ...); <br />
... <br />
printf("Compression ratio: %f%% (in) %f%% (out)\n", 100*soap.z_ratio_out, 100*soap.z_ratio_in); <br />
...
</td></tr></table><br></i>
Note: lower ratios mean higher compression rates.
<div class="p"><!----></div>
Compressed transfers require buffering the entire output message to determine HTTP message length.
This means that the <i>SOAP_IO_STORE</i> flag is
automatically set when the <i>SOAP_ENC_ZLIB</i> flag is set to send compressed messages. The use of HTTP chunking
significantly reduces memory usage and may speed up the transmission of compressed SOAP/XML messages.
This is accomplished by setting the <i>SOAP_IO_CHUNK</i> flag with
<i>SOAP_ENC_ZLIB</i> for the output mode.
However, some Web servers do not accept HTTP chunked request messages (even when they return HTTP chunked messages!). Stand-alone gSOAP services always accept chunked request messages.
<div class="p"><!----></div>
To restrict the compression to the deflate format only, compile the sources with <i>-DWITH_ZLIB</i>. This limits compression and decompression to the deflate format. Only plain and deflated messages can be exchanged, gzip is not supported with this option.
Receiving gzip compressed content is automatic, even in the absence of HTTP headers.
Receiving deflate compressed content is not automatic in the absence of HTTP headers and requires the flag
<i>SOAP_ENC_ZLIB</i> to be set for the input mode to decompress deflated data.
<div class="p"><!----></div>
<font color="#FF0000"><b>Caution</b></font>: it is important that the <i>WITH_GZIP</i> and <i>WITH_ZLIB</i> macros MUST be consistently defined to
compile the sources, such as <i>stdsoap2.cpp</i>, <i>soapC.cpp</i>,
<i>soapClient.cpp</i>, <i>soapServer.cpp</i>, and all application sources that
include <i>stdsoap2.h</i> or <i>soapH.h</i>. If the macros are not consistently
used, the application will crash due to a mismatches in the declaration and
access of the gSOAP environment.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.26">
18.26</a>&nbsp;&nbsp;<font color="#0000FF">Client-Side Cookie Support</font></h3><a name="sec:clientcookie">
</a>
<div class="p"><!----></div>
Client-side cookie support is optional. To enable cookie support, compile all sources with option <i>-DWITH_COOKIES</i>, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_COOKIES -o myclient stdsoap2.cpp soapC.cpp soapClient.cpp</i>
</td></tr></table><br></span>
or add the following line to <i>stdsoap.h</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define WITH_COOKIES
</td></tr></table><br></i>
Client-side cookie support is fully automatic. So just (re)compile <i>stdsoap2.cpp</i> with <i>-DWITH_COOKIES</i> to enable
cookie-based session control in your client.
<div class="p"><!----></div>
A database of cookies is kept and returned to the appropriate servers.
Cookies are not automatically saved to a file by a client. An example cookie
file manager is included as an extras in the distribution. You should
explicitly remove all cookies before terminating a gSOAP environment by
calling <i>soap_free_cookies(soap)</i> or by calling <i>soap_done(soap)</i>.
<div class="p"><!----></div>
To avoid "cookie storms" caused by malicious servers that return an
unreasonable amount of cookies, gSOAP clients/servers are restricted to
a database size that the user can limit (32 cookies by default), for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.cookie_max = 10;
</td></tr></table><br></i>
The cookie database is a linked list pointed to by <i>soap.cookies</i> where each node is declared as:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap_cookie <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*name; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*value; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*domain; <br />
&nbsp;&nbsp;&nbsp;<b>char</b>&nbsp;*path; <br />
&nbsp;&nbsp;&nbsp;<b>long</b>&nbsp;expire; /* client-side: local time to expire; server-side: seconds to expire */ <br />
&nbsp;&nbsp;&nbsp;<b>unsigned</b>&nbsp;<b>int</b>&nbsp;version; <br />
&nbsp;&nbsp;&nbsp;<b>short</b>&nbsp;secure; <br />
&nbsp;&nbsp;&nbsp;<b>short</b>&nbsp;session; /* server-side */ <br />
&nbsp;&nbsp;&nbsp;<b>short</b>&nbsp;env; /* server-side: 1 = got cookie from client */ <br />
&nbsp;&nbsp;&nbsp;<b>short</b>&nbsp;modified; /* server-side: 1 = client cookie was modified */ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap_cookie *next; <br />
};
</td></tr></table><br></i>
Since the cookie database is linked to a <i>soap</i> struct, each thread has a local cookie database in a multi-threaded
implementation.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.27">
18.27</a>&nbsp;&nbsp;<font color="#0000FF">Server-Side Cookie Support</font></h3><a name="sec:servercookie">
</a>
<div class="p"><!----></div>
Server-side cookie support is optional. To enable cookie support, compile all sources with option <i>-DWITH_COOKIES</i>, for example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_COOKIES -o myserver ...</i>
</td></tr></table><br></span>
gSOAP provides the following cookie API for server-side cookie session control:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td width="602"><font color="#FF0000"><b>Function</b></font> </td></tr>
<tr><td width="602"><i><b>struct</b>&nbsp;soap_cookie *soap_set_cookie(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*value, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Add a cookie to the database with name <i>name</i> and value <i>value</i>.
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns pointer to a cookie node in the linked list, or NULL otherwise.
</td></tr>
<tr><td width="602"><i><b>struct</b>&nbsp;soap_cookie *soap_cookie(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Find a cookie in the database with name <i>name</i> and value <i>value</i>.
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns pointer to a cookie node in the linked list, or NULL otherwise.
</td></tr>
<tr><td width="602"><i><b>char</b>&nbsp;*soap_cookie_value(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Get value of a cookie in the database with name <i>name</i>.
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns the string pointer to the value, or NULL otherwise.
</td></tr>
<tr><td width="602"><i><b>long</b>&nbsp;soap_cookie_expire(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Get expiration value of the cookie in the database with name <i>name</i> (in seconds).
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
Returns the expiration value, or -1 if cookie does not exist.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_set_cookie_expire(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>long</b>&nbsp;expire, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Set expiration value <i>expire</i> of the cookie in the database with name <i>name</i> (in seconds).
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns <i>SOAP_OK</i>, or <i>SOAP_EOF</i> otherwise.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_set_cookie_session(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Set cookie in the database with name <i>name</i> to be a session cookie.
This means that the cookie will be returned to the client.
(Only cookies that are modified are returned to the client).
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns <i>SOAP_OK</i>, or <i>SOAP_EOF</i> otherwise.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_clr_cookie_session(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Clear cookie in the database with name <i>name</i> to be a session cookie.
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
If successful, returns <i>SOAP_OK</i>, or <i>SOAP_EOF</i> otherwise.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_clr_cookie(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*name, <b>const</b>&nbsp;<b>char</b>&nbsp;*domain, <b>const</b>&nbsp;<b>char</b>&nbsp;*path);</i> </td></tr>
<tr><td width="602">Remove cookie from the database with name <i>name</i>.
<i>domain</i> and <i>path</i> may be NULL to use the current domain and path given by <i>soap_cookie_domain</i> and <i>soap_cookie_path</i>.
</td></tr>
<tr><td width="602"><i><b>int</b>&nbsp;soap_getenv_cookies(<b>struct</b>&nbsp;soap *soap);</i> </td></tr>
<tr><td width="602">Initializes cookie database by reading the 'HTTP_COOKIE' environment variable.
This provides a means for a CGI application to read cookies send by a client.
If successful, returns <i>SOAP_OK</i>, or <i>SOAP_EOF</i> otherwise.
</td></tr>
<tr><td width="602"><i><b>void</b>&nbsp;soap_free_cookies(<b>struct</b>&nbsp;soap *soap);</i> </td></tr>
<tr><td width="602">Release cookie database. </td></tr></table>
</td></tr></table><br></span>
The following global variables are used to define the current domain and path:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<table>
<tr><td><font color="#FF0000"><b>Attribute</b></font> </td><td><font color="#FF0000"><b>value</b></font> </td></tr>
<tr><td><i><b>const</b>&nbsp;<b>char</b>&nbsp;*cookie_domain</i> </td><td>MUST be set to the domain (host) of the service </td></tr>
<tr><td><i><b>const</b>&nbsp;<b>char</b>&nbsp;*cookie_path</i> </td><td>MAY be set to the default path to the service </td></tr>
<tr><td><i><b>int</b>&nbsp;cookie_max</i> </td><td>maximum cookie database size (default=32) </td></tr></table>
</td></tr></table><br></span>
The <i>cookie_path</i> value is used to filter cookies intended for this service according to the path prefix rules outlined in
RFC2109.
<div class="p"><!----></div>
The following example server adopts cookies for session control:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;m, s; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap.cookie_domain = "..."; <br />
&nbsp;&nbsp;&nbsp;soap.cookie_path = "/"; // the path which is used to filter/set cookies with this destination <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; 2) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_getenv_cookies(&amp;soap); // CGI app: grab cookies from 'HTTP_COOKIE' env var <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = soap_bind(&amp;soap, NULL, atoi(argv[1]), 100); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(m &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>for</b>&nbsp;(<b>int</b>&nbsp;i = 1; ; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = soap_accept(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(s &lt; 0) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_serve(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // clean up <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_free_cookies(&amp;soap); // remove all old cookies from database so no interference occurs with the arrival of new cookies <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
} <br />
<b>int</b>&nbsp;ck__demo(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;n; <br />
&nbsp;&nbsp;&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;*s; <br />
&nbsp;&nbsp;&nbsp;s = soap_cookie_value(soap, "demo", NULL, NULL); // cookie returned by client? <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!s) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = "init-value"; // no: set initial cookie value <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... // modify 's' to reflect session control <br />
&nbsp;&nbsp;&nbsp;soap_set_cookie(soap, "demo", s, NULL, NULL); <br />
&nbsp;&nbsp;&nbsp;soap_set_cookie_expire(soap, "demo", 5, NULL, NULL); // cookie may expire at client-side in 5 seconds <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
<h3><a name="tth_sEc18.28">
18.28</a>&nbsp;&nbsp;<font color="#0000FF">Connecting Clients Through Proxy Servers</font></h3>
<div class="p"><!----></div>
When a client needs to connect to a Web Service through a proxy server, set the <i>soap.proxy_host</i> string and
<i>soap.proxy_port</i> integer attributes of the current <i>soap</i> runtime environment to the proxy's host name and port, respectively. For example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap.proxy_host = "proxyhostname"; <br />
soap.proxy_port = 8080; <br />
<b>if</b>&nbsp;(soap_call_ns__method(&amp;soap, "http://host:port/path", "action", ...)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
<b>else</b><br />
&nbsp;&nbsp;&nbsp;...
</td></tr></table><br></i>
The attributes <i>soap.proxy_host</i> and <i>soap.proxy_port</i> keep their values through the remote method calls,
so they only need to be set once.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.29">
18.29</a>&nbsp;&nbsp;<font color="#0000FF">FastCGI Support</font></h3><a name="sec:fastcgi">
</a>
<div class="p"><!----></div>
To enable FastCGI support, install FastCGI and compile <em>all</em> sources (including your application sources that use <i>stdsoap2.h</i>) with option <i>-DWITH_FASTCGI</i> or add
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#define WITH_FASTCGI
</td></tr></table><br></i>
to <i>stdsoap2.h</i>.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.30">
18.30</a>&nbsp;&nbsp;<font color="#0000FF">How to Create gSOAP Applications With a Small Memory Footprint</font></h3><a name="sec:lean">
</a>
<div class="p"><!----></div>
To compile gSOAP applications intended for small memory devices, you may want
to remove all non-essential features that consume precious code and data space.
To do this, compile the gSOAP sources with <i>-DWITH_LEAN</i> (i.e.&nbsp;<i>#define WITH_LEAN</i>) to remove many
non-essential features. The features that will be disabled are:
<ul>
<li> No I/O timeouts. Note that many socket operations already obey some form of timeout handling, such as a connect timeout for example.
<div class="p"><!----></div>
</li>
<li> No HTTP keep alive
<div class="p"><!----></div>
</li>
<li> No HTTP cookies
<div class="p"><!----></div>
</li>
<li> No HTTP authentication
<div class="p"><!----></div>
</li>
<li> No HTTP chunked output (but input is OK)
<div class="p"><!----></div>
</li>
<li> No HTTP compressed output (but input is OK when compiled with <i>WITH_GZIP</i>)
<div class="p"><!----></div>
</li>
<li> No send/recv timeouts
<div class="p"><!----></div>
</li>
<li> No socket flags (no <i>soap.socket_flag, soap.connect_flag, soap.bind_flag, soap.accept_flag</i>)
<div class="p"><!----></div>
</li>
<li> No canonical XML output
<div class="p"><!----></div>
</li>
<li> No logging
<div class="p"><!----></div>
</li>
<li> Limited TCP/IP and HTTP error diagnostic messages
<div class="p"><!----></div>
</li>
<li> No support for <i>time_t</i> serialization
<div class="p"><!----></div>
</li>
<li> No support for <i>LONG64</i>/<i>ULONG64</i> serialization (use <i><b>typedef</b>&nbsp;<b>long</b>&nbsp;xsd__long</i>)
<div class="p"><!----></div>
</li>
</ul>
Use <i>-DWITH_LEANER</i> to make the executable even smaller by removing DIME
and MIME attachment handling, <i>wchar_t*</i> serialization, and support for XML DOM operations.
Note that DIME/MIME attachments are not essential to achieve
SOAP/XML interoperability. DIME attachments are a convenient way to exchange
non-text-based (i.e.&nbsp;binary) content, but are not required for basic SOAP/XML
interoperability. Attachment requirements are predictable. That is,
applications won't suddenly decide to use DIME or MIME instead of XML to exchange
content.
<div class="p"><!----></div>
It is safe to try to compile your application with <i>-DWITH_LEAN</i>, provided
that your application does not rely on I/O timeouts. When no linkage error
occurs in the compilation process, it is safe to assume that your application
will run just fine.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.31">
18.31</a>&nbsp;&nbsp;<font color="#0000FF">How to Eliminate BSD Socket Library Linkage</font></h3><a name="sec:noio">
</a>
<div class="p"><!----></div>
The <i>stdsoap2.c</i> and <i>stdsoap2.cpp</i> gSOAP runtime libraries should be linked with a BSD socket library in the project build, e.g. winsock for Win32. To eliminate the need to link a socket library, you can compile <i>stdsoap2.c</i> (for C) and <i>stdsoap2.cpp</i> (for C++) with the <i>-DWITH_NOIO</i> macro set (i.e.&nbsp;<i>#define WITH_NOIO</i>). This eliminates the dependency on the BSD socket API, IO streams, <i>FILE</i> type, and <i>errno</i>.
<div class="p"><!----></div>
As a consequence, you MUST define callbacks to replace the missing socket stack. To do so, add to your code the following definitions:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
/* fsend is used to transmit data in blocks */ <br />
soap.fsend = my_send; <br />
/* frecv is used to receive data in blocks */ <br />
soap.frecv = my_recv; <br />
/* fopen is used to connect */ <br />
soap.fopen = my_tcp_connect; <br />
/* fclose is used to disconnect */ <br />
soap.fclose = my_tcp_disconnect; <br />
/* fclosesocket is used only to close the master socket in a server upon soap_done() */ <br />
soap.fclosesocket = my_tcp_closesocket; <br />
/* fshutdownsocket is used after completing a send operation to send TCP FIN */ <br />
soap.fshutdownsocket = my_tcp_shutdownsocket; <br />
/* setting fpoll is optional, leave it NULL to omit polling the server */ <br />
soap.fpoll = my_poll; <br />
/* faccept is used only by a server application */ <br />
soap.faccept = my_accept;
</td></tr></table><br></i>
These functions are supposed to provide a (minimal) transport stack.
See Section&nbsp;<a href="#sec:callback">18.7</a> for more details on the use of these callbacks.
All callback function pointers should be non-NULL, except <i>fpoll</i>.
<div class="p"><!----></div>
You cannot use <i>soap_print_fault</i> and <i>soap_print_fault_location</i> to print error diagnostics. Instead, the value of <i>soap.error</i>, which contains the gSOAP error code, can be used to determine the cause of a fault.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.32">
18.32</a>&nbsp;&nbsp;<font color="#0000FF">How to Combine Multiple Client and Server Implementations into one Executable</font></h3>
<div class="p"><!----></div>
The <i>wsdl2h</i> tool can be used to import multiple WSDLs and schemas at once.
The service definitions are combined in one header file to be parsed by
<i>soapcpp2</i>. It is important to assign namespace prefixes to namespace URIs
using the <i>typemap.dat</i> file. Otherwise, <i>wsdl2h</i> will assign namespace
prefixes <i>ns1</i>, <i>ns2</i>, and so on to the service operations and schema
types. Thus, any change to a WSDL or schema may result in a new prefix
assignment. For more details, please see Section&nbsp;<a href="#sec:typemap">7.2.11</a>.
<div class="p"><!----></div>
For example, consider the XMethods delayed stock quote and exchange rate services. We can import both WSDLs at once with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>wsdl2h -s -o qx.h http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl</i>
</td></tr></table><br></span>
This generates the <i>qx.h</i> file for C++ (option -s for non-STL). The
next step is to use the <i>soapcpp2</i> compiler on this file to generate client
code (option -C):
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -C qx.h</i>
</td></tr></table><br></span>
The resuling header file can be viewed with Doxygen to pretty-print the service definitions in HTML.
<div class="p"><!----></div>
You will notice that the <i>qx.h</i> file contains a very lengthy service
name "net_x002exmethods_x002eservices_x002estockquote_x002eStockQuoteBinding".
Since this is undesirable for naming files, operations, and proxies, we
manually change its name into "StockQuote" and re-run <i>soapcpp2</i>.
<div class="p"><!----></div>
This gives us a couple of files we need to build the application in C++:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
soapStub.h <br />
soapH.h <br />
soapC.cpp <br />
soapClient.cpp <br />
soapStockQuoteProxy.h <br />
soapCurrencyExchangeBindingProxy.h <br />
StockQuote.nsmap
</td></tr></table><br></span>
The two .cpp files and <i>stdsoap2.cpp</i> are compiled and linked with the main application:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "soapStockQuoteProxy.h" <br />
#include "soapCurrencyExchangeBindingProxy.h" <br />
#include "StockQuote.nsmap" <br />
main() <br />
{ <br />
&nbsp;&nbsp;&nbsp;StockQuote stock; <br />
&nbsp;&nbsp;&nbsp;CurrencyExchangeBinding exchange; <br />
&nbsp;&nbsp;&nbsp;float quote, rate; <br />
&nbsp;&nbsp;&nbsp;stock.ns1__getQuote("IBM", quote); // get quote for IBM <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(stock.soap<tt>-&gt;</tt>error) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;exchange.ns2__getRate(&#252;s", &#252;k", rate); // get US to UK rate <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(exchange.soap<tt>-&gt;</tt>error) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1); <br />
&nbsp;&nbsp;&nbsp;cout <tt>&lt;&lt;</tt> "IBM in UK pounds = " <tt>&lt;&lt;</tt> rate*quote <tt>&lt;&lt;</tt> endl; <br />
}
</td></tr></table><br></i>
This application prints the value of the IBM stock in UK pounds.
<div class="p"><!----></div>
Note that the prefixes <i>ns1</i> and <i>ns2</i> can be changed using the
<i>typemap.dat</i> file for <i>wsdl2h</i>, see Section&nbsp;<a href="#sec:typemap">7.2.11</a>.
<div class="p"><!----></div>
Another approach to combine multiple client and service applications into one
executable is by using C++ namespaces to logically separate the definitions or
by creating C libraries for the client/server objects as explained in
subsequent sections.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.33">
18.33</a>&nbsp;&nbsp;<font color="#0000FF">How to Build a Client or Server in a C++ Code Namespace</font></h3><a name="sec:codenamespace">
</a>
<div class="p"><!----></div>
You can use a C++ code namespace of your choice in your header file to build
a client or server in that code namespace. In this way, you can create multiple
clients and servers that can be combined and linked together without conflicts,
which is explained in more detail in the next section (which also shows an
example combining two client libraries defined in two C++ code namespaces).
<div class="p"><!----></div>
At most one namespace can be defined for the entire gSOAP header file. The code
namespace MUST completely encapsulate the entire contents of the header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>namespace</b>&nbsp;myNamespaceName { <br />
... gSOAP header file contents ... <br />
}
</td></tr></table><br></i>
When compiling this header file with the gSOAP compiler, all type definitions,
the (de)serializers for these types, and the stub/skeleton codes will be placed
in this namespace. The XML namespace mapping table (saved in a <i>.nsmap</i>
file) will not be placed in the code namespace to allow it to be linked as a
global object. You can use option <i>-n</i> to create local XML namespace
tables, see Section&nbsp;<a href="#sec:options">8.1</a> (but remember that you explicitly need to
initialize the <i>soap.namespaces</i> to point to a table at run time). The
generated files are prefixed with the code namespace name instead of the usual
<i>soap</i> file name prefix to enable multiple client/server codes to be build
in the same project directory (a code namespace automatically sets the <i>-p</i>
compiler option, see Section&nbsp;<a href="#sec:options">8.1</a> for options).
<div class="p"><!----></div>
Because the SOAP Header and Fault serialization codes will also be placed in
the namespace, they cannot be called from the <i>stdsoap2.cpp</i> run time
library code and are therefore rendered unusable. Therefore, these serializers
are not compiled at all (enforced with <i>#define WITH_NOGLOBAL</i>). To add SOAP
Header and Fault serializers, you MUST compile them separately as follows.
First, create a new header file <i>env.h</i> with the SOAP Header and Fault
definitions. You can leave this header file empty if you want to use the
default SOAP Header and Fault. Then compile this header file with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -penv env.h</i>
</td></tr></table><br></span>
The generated <i>envC.cpp</i> file holds the SOAP Header and Fault serializers and you can
link this file with your client or server application.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.34">
18.34</a>&nbsp;&nbsp;<font color="#0000FF">How to Create Client/Server Libraries</font></h3><a name="sec:dylibs">
</a>
<div class="p"><!----></div>
The gSOAP compiler produces <i>soapClientLib.cpp</i> and <i>soapServerLib.cpp</i>
codes that are specifically intended for building static or dynamic
client/server libraries. These codes export the stubs and skeletons, but keep
all marshaling code (i.e.&nbsp;parameter serializers and deserializers) local (i.e.&nbsp;
as static functions) to avoid link symbol conflicts when combining multiple
clients and/or servers into one executable. Note that it is far simpler to use
the <i>wsdl2h</i> tool on multiple WSDL files to generate a header file that
combines all service definitions. However, the approach presented in this
section is useful when creating (dynamic) libraries for client and server
objects, such as DLLs as described in Section&nbsp;<a href="#sec:dll">18.35</a>.
<div class="p"><!----></div>
To build multiple libraries in the same project directory, you can define a C++
code namespace in your header file (see Section&nbsp;<a href="#sec:codenamespace">18.33</a>) or you
can use <i>soapcpp2</i> with option <i>-p</i> to rename the generated
<i>soapClientLib.cpp</i> and <i>soapServerLib.cpp</i> (and associated) files. The
<i>-p</i> option specifies the file name prefix to replace the <i>soap</i>
prefix. The libraries don't have to be C++ codes. You can use option <i>-c</i>
to generate C code. A clean separation of libraries can also be achieved with
C++ code namespaces, see Section&nbsp;<a href="#sec:codenamespace">18.33</a>.
<div class="p"><!----></div>
The library codes do not define SOAP Header and Fault serializers. You MUST
add SOAP Header and Fault serializers to your application, which are compiled
separately as follows. First, create a new header file <i>env.h</i> with the
SOAP Header and Fault definitions. You can leave this header file empty if you
want to use the default SOAP Header and Fault. Then compile this header file
with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -penv env.h</i>
</td></tr></table><br></span>
The generated <i>envC.cpp</i> file holds the SOAP Header and Fault serializers and you can
create a (dynamic) library for it to link this code with your client or server application.
<div class="p"><!----></div>
You MUST compile the <i>stdsoap2.cpp</i> library using <i>-DWITH_NONAMESPACES</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -DWITH_NONAMESPACES -c stdsoap2.cpp</i>
</td></tr></table><br></span>
This omits the reference to the global namespaces table, which is nowhere
to be defined since we will use XML namespaces for each client/service separately. Therefore, you MUST explicitly set the
namespaces value of the gSOAP environment in your code every time after initialization of the soap struct.
<div class="p"><!----></div>
For example, suppose we have two clients defined in header files <i>client1.h</i> and <i>client2.h</i>. We first generate the <i>envH.h</i> file for the SOAP Header and Fault definitions:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -penv env.h</i>
</td></tr></table><br></span>
Then we generate the code for client1 and client2:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -n -pmyClient1 client1.h</i> <br />
<i>soapcpp2 -c -n -pmyClient2 client2.h</i>
</td></tr></table><br></span>
This generates <i>myClient1ClientLib.c</i> and <i>myClient2ClientLib.c</i> (among many other files).
These two files should be compiled and linked with your application.
The source code of your application should include the generated <i>envH.h</i>, <i>myClient1H.h</i>, <i>myClient2.h</i> files and <i>myClient1.nsmap</i>, <i>myClient2.nsmap</i> files:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "envH.h" // include this file first! <br />
#include "myClient1H.h" // include client 1 stubs <br />
#include "myClient2H.h" // include client 2 stubs <br />
... <br />
#include "myClient1H.nsmap" // include client 1 nsmap <br />
#include "myClient2H.nsmap" // include client 2 nsmap <br />
... <br />
soap_init(&amp;soap); <br />
soap_set_namespaces(&amp;soap, myClient1_namespaces); <br />
... make Client 1 invocations ... <br />
... <br />
soap_set_namespaces(&amp;soap, myClient2_namespaces); <br />
... make Client 2 invocations ...
</td></tr></table><br></i>
It is important to use <i>soapcpp2</i> option <i>-n</i>, see Section&nbsp;<a href="#sec:options">8.1</a>, to rename the namespace tables so we can include them all without running into redefinitions.
<div class="p"><!----></div>
Note: Link conflicts may still occur in the unlikely situation that identical remote method names are defined in
two or more client stubs or server skeletons when these methods share the same XML namespace prefix. You may have to use C++ code
namespaces to avoid these link conflicts or rename the namespace prefixes used by the remote method defined in the header files.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.34.1">
18.34.1</a>&nbsp;&nbsp;<font color="#0000FF">C++ Example</font></h4>
<div class="p"><!----></div>
As an example we will build a Delayed Stock Quote client library and a Currency Exchange Rate client library.
<div class="p"><!----></div>
First, we create an empty header file <i>env.h</i> (which may contain optional SOAP Header and Fault definitions), and compile it as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -penv env.h</i> <br />
<i>g++ -c envC.cpp</i> <br />
</td></tr></table><br></span>
We also compile <i>stdsoap2.cpp</i> without namespaces:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>g++ -c -DWITH_NONAMESPACES stdsoap2.cpp</i>
</td></tr></table><br></span>
Note: when you forget to use <i>-DWITH_NONAMESPACES</i> you will get an unresolved link error for the global <i>namespaces</i> table. You can define a dummy table to avoid having to recompile <i>stdsoap2.cpp</i>.
<div class="p"><!----></div>
Second, we create the Delayed Stock Quote header file specification, which may be obtained using the WSDL importer. If you want to use C++ namespaces then you need to manually add the <i><b>namespace</b></i> declaration to the generated header file:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>namespace</b>&nbsp;quote { <br />
//gsoap ns service name: Service <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://services.xmethods.net/soap <br />
//gsoap ns schema namespace: urn:xmethods-delayed-quotes <br />
//gsoap ns service method-action: getQuote "" <br />
<b>int</b>&nbsp;ns__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;&amp;Result); <br />
}
</td></tr></table><br></i>
We then compile it as a library and we use option <i>-n</i> to rename the namespace table to avoid link conflicts later:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -n quote.h</i> <br />
<i>g++ -c quoteClientLib.cpp</i>
</td></tr></table><br></span>
If you don't want to use a C++ code namespace, you should compile <i>quote.h</i> "as is" with soapcpp2 option <i>-pquote</i>:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -n -pquote quote.h</i> <br />
<i>g++ -c quoteClientLib.cpp</i>
</td></tr></table><br></span>
Third, we create the Currency Exchange Rate header file specification:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>namespace</b>&nbsp;rate { <br />
//gsoap ns service name: Service <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://services.xmethods.net/soap <br />
//gsoap ns schema namespace: urn:xmethods-CurrencyExchange <br />
//gsoap ns service method-action: getRate "" <br />
<b>int</b>&nbsp;ns__getRate(<b>char</b>&nbsp;*country1, <b>char</b>&nbsp;*country2, <b>float</b>&nbsp;&amp;Result); <br />
}
</td></tr></table><br></i>
Similar to the Quote example above, we compile it as a library and we use option <i>-n</i> to rename the namespace table to avoid link conflicts:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -n rate.h</i> <br />
<i>g++ -c rateServerProxy.cpp</i> <br />
</td></tr></table><br></span>
Fourth, we consider linking the libraries to the main program.
The main program can import the <i>quoteServiceProxy.h</i> and <i>rateServiceProxy.h</i> files to obtain client proxies to invoke the services. The proxy implementations are defined in the <i>quoteServiceProxy.cpp</i> and <i>rateServiceProxy.cpp</i> files compiled above.
The <i>-n</i> option also affects the generation of the <i>quoteServiceProxy.cpp</i> and <i>rateServiceProxy.cpp</i> C++ proxy codes to ensure that the gSOAP environment is properly initialized with the appropriate namespace table (so you don't have to initialize explicitly - this feature is only available with C++ proxy and server object classes).
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "quoteServiceProxy.h" // get quote Service proxy <br />
#include "rateServiceProxy.h" // get rate Service proxy <br />
#include "quote.nsmap" // get quote namespace bindings <br />
#include "rate.nsmap" // get rate namespace bindings <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;*argv[]) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; = 1) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr <tt>&lt;&lt;</tt> "Usage: main ticker [currency]" <tt>&lt;&lt;</tt> std::endl <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;quote::Service quote; <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;q; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(quote.getQuote(argv[1], q)) // get quote <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(quote.soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &gt; 2) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rate::Service rate; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;r; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(rate.getRate("us", argv[2], r)) // get rate in US dollars <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(rate.soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q *= r; // convert the quote <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout <tt>&lt;&lt;</tt> argv[1] <tt>&lt;&lt;</tt> ": " <tt>&lt;&lt;</tt> q <tt>&lt;&lt;</tt> std::endl; <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
Compile and link this application with <i>stdsoap2.o</i>, <i>envC.o</i>, <i>quoteServerProxy.o</i>, and <i>rateServerProxy.o</i>.
<div class="p"><!----></div>
To compile and link a server object is very similar. For example, assume that we need to implement a calculator service and we want to create a library for it.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>namespace</b>&nbsp;calc { <br />
//gsoap ns service name: Service <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://www.cs.fsu.edu/&nbsp;engelen/calc.cgi <br />
//gsoap ns schema namespace: urn:calc <br />
<b>int</b>&nbsp;ns__add(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
<b>int</b>&nbsp;ns__sub(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
<b>int</b>&nbsp;ns__mul(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
<b>int</b>&nbsp;ns__div(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
}
</td></tr></table><br></i>
We compile this with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -n calc.h</i> <br />
<i>g++ -c calcServiceObject.cpp</i>
</td></tr></table><br></span>
The effect of the <i>-n</i> option is that it creates local namespace tables, and a modified <i>calcServiceObject.h</i> server class definitions that properly initialize the gSOAP run time with the table.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "calcServiceObject.h" // get Service object <br />
#include "calc.nsmap" // get calc namespace bindings <br />
... <br />
calc::Service calc; <br />
calc.serve(); // calls request dispatcher to invoke one of the functions below <br />
... <br />
<b>int</b>&nbsp;calc::Service::add(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
{ result = a + b; <b>return</b>SOAP_OK; } <br />
<b>int</b>&nbsp;calc::Service::sub(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
{ result = a - b; <b>return</b>SOAP_OK; } <br />
<b>int</b>&nbsp;calc::Service::mul(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
{ result = a * b; <b>return</b>SOAP_OK; } <br />
<b>int</b>&nbsp;calc::Service::div(<b>double</b>&nbsp;a, <b>double</b>&nbsp;b, <b>double</b>&nbsp;&amp;result); <br />
{ result = a / b; <b>return</b>SOAP_OK; } <br />
</td></tr></table><br></i>
In fact, the <i>calc::Service</i> class is derived from the <i><b>struct</b>&nbsp;soap</i>. So the environment
is available as <i>this</i>, which can be passed to all gSOAP functions that require a soap struct
context.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.34.2">
18.34.2</a>&nbsp;&nbsp;<font color="#0000FF">C Example</font></h4>
<div class="p"><!----></div>
This is the same example as above, but the clients are build with pure C.
<div class="p"><!----></div>
First, we create an empty header file (which may contain optional SOAP Header and Fault definitions), and compile it as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -penv env.h</i> <br />
<i>gcc -c envC.c</i> <br />
</td></tr></table><br></span>
We also compile <i>stdsoap2.c</i> without namespaces:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>gcc -c -DWITH_NONAMESPACES stdsoap2.c</i>
</td></tr></table><br></span>
Second, we create the Delayed Stock Quote header file specification, which may be obtained using the WSDL importer.
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service name: Service <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://services.xmethods.net/soap <br />
//gsoap ns schema namespace: urn:xmethods-delayed-quotes <br />
//gsoap ns service method-action: getQuote "" <br />
<b>int</b>&nbsp;ns__getQuote(<b>char</b>&nbsp;*symbol, <b>float</b>&nbsp;*Result);
</td></tr></table><br></i>
We compile it as a library and we use options <i>-n</i> and <i>-p</i> to rename the namespace table to avoid link conflicts:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -n -pquote quote.h</i> <br />
<i>gcc -c quoteClientLib.c</i>
</td></tr></table><br></span>
Third, we create the Currency Exchange Rate header file specification:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
//gsoap ns service name: Service <br />
//gsoap ns service style: rpc <br />
//gsoap ns service encoding: encoded <br />
//gsoap ns service location: http://services.xmethods.net/soap <br />
//gsoap ns schema namespace: urn:xmethods-CurrencyExchange <br />
//gsoap ns service method-action: getRate "" <br />
<b>int</b>&nbsp;ns__getRate(<b>char</b>&nbsp;*country1, <b>char</b>&nbsp;*country2, <b>float</b>&nbsp;*Result);
</td></tr></table><br></i>
We compile it as a library and we use options <i>-n</i> and <i>-p</i> to rename the namespace table to avoid link conflicts:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -c -n -prate rate.h</i> <br />
<i>gcc -c rateClientLib.c</i>
</td></tr></table><br></span>
The main program is:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "quoteStub.h" // get quote Service stub <br />
#include "rateStub.h" // get rate Service stub <br />
#include "quote.nsmap" // get quote namespace bindings <br />
#include "rate.nsmap" // get rate namespace bindings <br />
<b>int</b>&nbsp;main(<b>int</b>&nbsp;argc, <b>char</b>&nbsp;*argv[]) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &lt; = 1) <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "Usage: main ticker [currency]\n"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;soap soap; <br />
&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;q; <br />
&nbsp;&nbsp;&nbsp;soap_init(&amp;soap); <br />
&nbsp;&nbsp;&nbsp;soap_set_namespaces(&amp;soap, quote_namespaces); <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns__getQuote(&amp;soap, "http://services.xmethods.net/soap", "", argv[1], &amp;q)) // get quote <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(argc &gt; 2) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_set_namespaces(&amp;soap, rate_namespaces); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>float</b>&nbsp;r; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns__getRate(&amp;soap, "http://services.xmethods.net/soap", "", "us", argv[2], &amp;r)) // get rate in US dollars <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>else</b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q *= r; // convert the quote <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%s: %f \n", argv[1], q); <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;0; <br />
}
</td></tr></table><br></i>
Compile and link this application with <i>stdsoap2.o</i>, <i>envC.o</i>, <i>quoteClientLib.o</i>, and <i>rateClientLib.o</i>.
<div class="p"><!----></div>
To compile and link a server library is very similar. Assuming that the server is named "<i>calc</i>" (as specified with options <i>-n</i> and <i>-p</i>), the application needs to include the <i>calcStub.h</i> file, link the <i>calcServerLib.o</i> file, and call <i>calc_serve(&amp;soap)</i> function at run time.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.35">
18.35</a>&nbsp;&nbsp;<font color="#0000FF">How to Create DLLs</font></h3><a name="sec:dll">
</a>
<div class="p"><!----></div>
<h4><a name="tth_sEc18.35.1">
18.35.1</a>&nbsp;&nbsp;<font color="#0000FF">Create the Base stdsoap2.dll</font></h4>
<div class="p"><!----></div>
First, create a new header file <i>env.h</i> with the SOAP Header and Fault
definitions. You can leave this header file empty if you want to use the
default SOAP Header and Fault. Then compile this header file with:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i>soapcpp2 -penv env.h</i>
</td></tr></table><br></span>
The generated <i>envC.cpp</i> file holds the SOAP Header and Fault serializers, which need to be part of the base library functions.
<div class="p"><!----></div>
The next step is to create <i>stdsoap2.dll</i> which consists of the file
<i>stdsoap2.cpp</i> and <i>envC.cpp</i>. This DLL contains all common functions
needed for all other clients and servers based on gSOAP. Compile
<i>envC.cpp</i> and <i>stdsoap2.cpp</i> into <i>stdsoap2.dll</i> using the C++
compiler option <i>-DWITH_NONAMESPACES</i> and the MSVC Pre-Processor
definitions <i>SOAP_FMAC1=__declspec(dllexport)</i> and <i>SOAP_FMAC3=__declspec(dllexport)</i> (or you
can compile with
<i>-DWITH_SOAPDEFS_H</i> and put the macro definitions in <i>soapdefs.h</i>).
This exports all functions which are preceded by the macro <i>SOAP_FMAC1</i> in
the <i>soapcpp2.cpp</i> source file and macro <i>SOAP_FMAC3</i> in the <i>envC.cpp</i> source file.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.35.2">
18.35.2</a>&nbsp;&nbsp;<font color="#0000FF">Creating Client and Server DLLs</font></h4>
<div class="p"><!----></div>
Compile the <i>soapClientLib.cpp</i> and <i>soapServerLib.cpp</i> sources as DLLs
by using the MSVC Pre-Processor definitions <i>SOAP_FMAC5=__declspec(dllexport)</i> and <i>SOAP_CMAC=__(dllexport)</i>, and by using the C++ compiler option <i>-DWITH_NONAMESPACES</i>.
This DLL links to <i>stdsoap2.dll</i>.
<div class="p"><!----></div>
To create multiple DLLs in the same project directory, you SHOULD use option
<i>-p</i> to rename the generated <i>soapClientLib.cpp</i> and
<i>soapServerLib.cpp</i> (and associated) files. The <i>-p</i> option specifies
the file name prefix to replace the <i>soap</i> prefix.
A clean separation of libraries can also be achieved with C++ namespaces, see Section&nbsp;<a href="#sec:codenamespace">18.33</a>.
<div class="p"><!----></div>
Unless you use the client proxy and server object classes (<i>soapXProxy.h</i> and <i>soapXObject.h</i> where <i>X</i> is the name of the service), all client and server applications MUST explicitly set the namespaces value of the gSOAP environment:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
soap_init(&amp;soap); <br />
soap_set_namespaces(&amp;soap, namespaces);
</td></tr></table><br></i>
where the <i>namespaces[]</i> table should be defined in the client/server source. These tables are generated in the <i>.nsmap</i> files. You can rename the tables using option <i>-n</i>, see Section&nbsp;<a href="#sec:options">8.1</a>.
<div class="p"><!----></div>
<h3><a name="tth_sEc18.36">
18.36</a>&nbsp;&nbsp;<font color="#0000FF">gSOAP Plug-ins</font></h3><a name="sec:plugins">
</a>
<div class="p"><!----></div>
The gSOAP plug-in feature enables a convenient extension mechanism of gSOAP
capabilities. When the plug-in registers with gSOAP, it has full access
to the run-time settings and the gSOAP function callbacks.
Upon registry, the plug-in's local data is associated with the gSOAP run-time.
By overriding gSOAP's function callbacks with the plug-in's function callbacks,
the plug-in can extend gSOAP's capabilities. The local plug-in data can be
accessed through a lookup function, usually invoked within a callback function
to access the plug-in data.
The registry and lookup functions are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i><b>int</b>&nbsp;soap_register_plugin_arg(<b>struct</b>&nbsp;soap *soap, <b>int</b>&nbsp;(*fcreate)(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *p, <b>void</b>&nbsp;*arg), <b>void</b>&nbsp;*arg)</i> <br />
<i><b>void</b>* soap_lookup_plugin(<b>struct</b>&nbsp;soap*, <b>const</b>&nbsp;<b>char</b>*);</i>
</td></tr></table><br></span>
Other functions that deal with plug-ins are:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#D0D0D0"><tr><td><span class="roman">
<i><b>int</b>&nbsp;soap_copy(<b>struct</b>&nbsp;soap *soap);</i> <br />
<i><b>void</b>&nbsp;soap_done(<b>struct</b>&nbsp;soap *soap);</i>
</td></tr></table><br></span>
The <i>soap_copy</i> function returns a new dynamically allocated gSOAP
environment that is a copy of another, such that no data is shared between the
copy and the original environment. The <i>soap_copy</i> function invokes the
plug-in copy callbacks to copy the plug-ins' local data.
The <i>soap_copy</i> function returns a gSOAP error code or <i>SOAP_OK</i>.
The <i>soap_done</i> function de-registers all plugin-ins, so this function
should be called to cleanly terminate a gSOAP run-time environment.
<div class="p"><!----></div>
An example will be used to illustrate these functions.
This example overrides the send and receive callbacks to copy all messages
that are sent and received to the terminal (stderr).
<div class="p"><!----></div>
First, we write a header file <i>plugin.h</i> to define the local plug-in data
structure(s) and we define a global name to identify the plug-in:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "stdsoap2.h" <br />
#define PLUGIN_ID "PLUGIN-1.0" // some name to identify plugin <br />
<b>struct</b>&nbsp;plugin_data // local plugin data <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>int</b>&nbsp;(*fsend)(<b>struct</b>&nbsp;soap*, <b>const</b>&nbsp;<b>char</b>*, size_t); // to save and use send callback <br />
&nbsp;&nbsp;&nbsp;size_t (*frecv)(<b>struct</b>&nbsp;soap*, <b>char</b>*, size_t); // to save and use recv callback <br />
}; <br />
<b>int</b>&nbsp;plugin(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *plugin, <b>void</b>&nbsp;*arg);
</td></tr></table><br></i>
Then, we write the plugin registry function and the callbacks:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "plugin.h" <br />
<b>static</b>&nbsp;<b>const</b>&nbsp;<b>char</b>&nbsp;plugin_id[] = PLUGIN_ID; // the plugin id <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_init(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;plugin_data *data); <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_copy(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *dst, <b>struct</b>&nbsp;soap_plugin *src); <br />
<b>static</b>&nbsp;<b>void</b>&nbsp;plugin_delete(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *p); <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_send(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*buf, size_t len); <br />
<b>static</b>&nbsp;size_t plugin_recv(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*buf, size_t len); <br />
// the registry function: <br />
<b>int</b>&nbsp;plugin(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *p, <b>void</b>&nbsp;*arg) <br />
{ <br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>id = plugin_id; <br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>data = (<b>void</b>*)malloc(<b>sizeof</b>(<b>struct</b>&nbsp;plugin_data)); <br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>fcopy = plugin_copy; /* optional: when set the plugin must copy its local data */<br />
&nbsp;&nbsp;&nbsp;p<tt>-&gt;</tt>fdelete = plugin_delete; <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(p<tt>-&gt;</tt>data) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(plugin_init(soap, (<b>struct</b>&nbsp;plugin_data*)p<tt>-&gt;</tt>data)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(p<tt>-&gt;</tt>data); // error: could not init <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOM; // return error <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_init(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;plugin_data *data) <br />
{ <br />
&nbsp;&nbsp;&nbsp;data<tt>-&gt;</tt>fsend = soap<tt>-&gt;</tt>fsend; // save old recv callback <br />
&nbsp;&nbsp;&nbsp;data<tt>-&gt;</tt>frecv = soap<tt>-&gt;</tt>frecv; // save old send callback <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>fsend = plugin_send; // replace send callback with new <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>frecv = plugin_recv; // replace recv callback with new <br />
&nbsp;&nbsp;&nbsp;return SOAP_OK; <br />
} <br />
// copy plugin data, called by soap_copy()
// This is important: we need a deep copy to avoid data sharing by two run-time environments <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_copy(<b>struct</b>&nbsp;soap *soap, struct soap_plugin *dst, <b>struct</b>&nbsp;soap_plugin *src) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!(dst<tt>-&gt;</tt>data = (<b>struct</b>&nbsp;plugin_data*)malloc(<b>sizeof</b>(<b>struct</b>&nbsp;plugin_data)))) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_EOM; <br />
&nbsp;&nbsp;&nbsp;*dst<tt>-&gt;</tt>data = *src<tt>-&gt;</tt>data; <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
} <br />
// plugin deletion, called by soap_done() <br />
<b>static</b>&nbsp;<b>void</b>&nbsp;plugin_delete(<b>struct</b>&nbsp;soap *soap, <b>struct</b>&nbsp;soap_plugin *p) <br />
{ free(p<tt>-&gt;</tt>data); // free allocated plugin data <br />
} <br />
// the new send callback <br />
<b>static</b>&nbsp;<b>int</b>&nbsp;plugin_send(<b>struct</b>&nbsp;soap *soap, <b>const</b>&nbsp;<b>char</b>&nbsp;*buf, size_t len) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;plugin_data *data = (<b>struct</b>&nbsp;plugin_data*)soap_lookup_plugin(soap, plugin_id); // fetch plugin's local data <br />
&nbsp;&nbsp;&nbsp;fwrite(buf, len, 1, stderr); // write message to stderr <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;data<tt>-&gt;</tt>fsend(soap, buf, len); // pass data on to old send callback <br />
} <br />
// the new receive callback <br />
<b>static</b>&nbsp;size_t plugin_recv(<b>struct</b>&nbsp;soap *soap, <b>char</b>&nbsp;*buf, size_t len) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;plugin_data *data = (<b>struct</b>&nbsp;plugin_data*)soap_lookup_plugin(soap, plugin_id); // fetch plugin's local data <br />
&nbsp;&nbsp;&nbsp;size_t res = data<tt>-&gt;</tt>frecv(soap, buf, len); // get data from old recv callback <br />
&nbsp;&nbsp;&nbsp;fwrite(buf, res, 1, stderr); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;res; <br />
}
</td></tr></table><br></i>
The <i>fdelete</i> callback of <i><b>struct</b>&nbsp;soap_plugin</i>
MUST be set to register the plugin. It is the responsibility of the plug-in to
handle registry (init), copy, and deletion of the plug-in data and callbacks.
<div class="p"><!----></div>
A plugin is copied with the <i>soap_copy()</i> call. This function copies a soap struct
and the chain of plugins. It is up to the plugin implementation to share the plugin data
or not:
<ol type="1">
<li> if the <i>fcopy()</i> callback is set by the plugin initialization, this callback will be called to allow
the plugin to copy its local data upon a <i>soap_copy()</i> call. When <i>soap_done()</i> is called on
the soap struct copy, the <i>fdelete()</i> callback is called for deallocation and cleanup of the local data.
<div class="p"><!----></div>
</li>
<li>
if the <i>fcopy()</i> callback is not set, then the plugin data
will be shared (i.e. the data pointer points to the same address).
The <i>fdelete()</i> callback will not be called upon a <i>soap_done()</i> on a
copy of the soap struct. The <i>fdelete()</i> callback will be called for
the original soap struct with which the plugin was registered.
<div class="p"><!----></div>
</li>
</ol>
The example plug-in should be used as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>struct</b>&nbsp;soap soap; <br />
soap_init(&amp;soap); <br />
soap_register_plugin(&amp;soap, plugin); <br />
... <br />
soap_done(&amp;soap);
</td></tr></table><br></i>
Note: <i>soap_register_plugin(...)</i> is an alias for
<i>soap_register_plugin_arg(..., NULL)</i>. That is, it passes NULL as an
argument to plug-in's registry callback.
<div class="p"><!----></div>
A number of example plug-ins are included in the gSOAP package's <i>plugin</i> directory. Some of these plug-ins are discussed.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.36.1">
18.36.1</a>&nbsp;&nbsp;<font color="#0000FF">The Message Logging and Statistics Plug-in</font></h4>
<div class="p"><!----></div>
The message logging and access statistics plug-in can be used to selectively log inbound and outbound messages to a file or stream. It also keeps access statistics to log the total number of bytes sent and received.
<div class="p"><!----></div>
To use the plug-in, compile and link your application with <i>logging.c</i> located in the <i>plugin</i> directory of the package.
To enable the plug-in in your code, register the plug-in and set the streams as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "logging.h" <br />
... <br />
<b>if</b>&nbsp;(soap_register_plugin(&amp;soap, logging)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register <br />
... <br />
<b>struct</b>&nbsp;logging_data *logdata; <br />
logdata = (<b>struct</b>&nbsp;logging_data*)soap_lookup_plugin(&amp;soap, logging_id); <br />
<b>if</b>&nbsp;(!logdata) <br />
&nbsp;&nbsp;&nbsp;... // if the plug-in registered OK, there is certainly data but can't hurt to check <br />
logdata<tt>-&gt;</tt>inbound = stdout; // log to stdout <br />
logdata<tt>-&gt;</tt>outbound = stdout; // log to stdout <br />
... process messages ... <br />
logdata<tt>-&gt;</tt>inbound = NULL; // don't log <br />
logdata<tt>-&gt;</tt>outbound = NULL; // don't log <br />
... process messages ... <br />
size_t bytes_in = logdata<tt>-&gt;</tt>stat_recv; <br />
size_t bytes_out = logdata<tt>-&gt;</tt>stat_sent;
</td></tr></table><br></i>
If you use <i>soap_copy</i> to copy the soap struct with the plug-in, the plug-in's data will be shared by the copy.
Therefore, the statistics are not 100% guaranteed to be accurate for multi-threaded services since race conditions on the counters may occur. Mutex is not used to update the counters to avoid introducing expensive synchronization points. If 100% server-side accuracy is required, add mutex at the points indicated in the <i>logging.c</i> code.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.36.2">
18.36.2</a>&nbsp;&nbsp;<font color="#0000FF">The HTTP GET Plug-in</font></h4>
<div class="p"><!----></div>
The HTTP GET plug-in allows your server to handle HTTP GET requests as well as SOAP-based POST request.
HTTP GET requests can also be handled with the <i>fget</i> callback, see Section&nbsp;<a href="#sec:callback">18.7</a>. However, the HTTP GET plug-in also keeps statistics on the number of successful POST and GET exchanges and failed operations (HTTP faults, SOAP Faults, etc.). It also keeps hit histograms accumulated for up to a year.
<div class="p"><!----></div>
To use the plug-in, compile and link your application with <i>httpget.c</i> located in the <i>plugin</i> directory of the package.
To enable the plug-in in your code, register the plug-in with your HTTP GET handler function as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "httpget.h" <br />
... <br />
<b>if</b>&nbsp;(soap_register_plugin_arg(&amp;soap, httpget, (<b>void</b>*)my_http_get_handler)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register <br />
... <br />
<b>struct</b>&nbsp;http_get_data *httpgetdata; <br />
httpgetdata = (<b>struct</b>&nbsp;http_get_data*)soap_lookup_plugin(&amp;soap, http_get_id); <br />
<b>if</b>&nbsp;(!httpgetdata) <br />
&nbsp;&nbsp;&nbsp;... // if the plug-in registered OK, there is certainly data but can't hurt to check <br />
... process messages ... <br />
size_t get_ok = httpgetdata<tt>-&gt;</tt>stat_get; <br />
size_t post_ok = httpgetdata<tt>-&gt;</tt>stat_post; <br />
size_t errors = httpgetdata<tt>-&gt;</tt>stat_fail; <br />
... <br />
time_t now = time(NULL); <br />
<b>struct</b>&nbsp;tm *T; <br />
T = localtime(&amp;now); <br />
size_t hitsthisminute = httpgetdata<tt>-&gt;</tt>min[T<tt>-&gt;</tt>tm_min]; <br />
size_t hitsthishour = httpgetdata<tt>-&gt;</tt>hour[T<tt>-&gt;</tt>tm_hour]; <br />
size_t hitstoday = httpgetdata<tt>-&gt;</tt>day[T<tt>-&gt;</tt>tm_yday];
</td></tr></table><br></i>
An HTTP GET handler can simply produce HTML content, or any other type of information:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
<b>int</b>&nbsp;my_http_get_handler(<b>struct</b>&nbsp;soap) <br />
{ <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>http_content = "text/html"; <br />
&nbsp;&nbsp;&nbsp;soap_response(soap, SOAP_FILE); <br />
&nbsp;&nbsp;&nbsp;soap_send(soap, &#171;html&#62;Hello&lt;/html&#62;"); <br />
&nbsp;&nbsp;&nbsp;soap_end_send(soap); <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; // return SOAP_OK or HTTP error code, e.g. 404 <br />
}
</td></tr></table><br></i>
If you use <i>soap_copy</i> to copy the soap struct with the plug-in, the plug-in's data will be shared by the copy.
Therefore, the statistics are not 100% guaranteed to be accurate for multi-threaded services since race conditions on the counters may occur. Mutex is not used to update the counters to avoid introducing expensive synchronization points. If 100% server-side accuracy is required, add mutex at the points indicated in the <i>httpget.c</i> code.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.36.3">
18.36.3</a>&nbsp;&nbsp;<font color="#0000FF">The HTTP MD5 Plug-in</font></h4>
<div class="p"><!----></div>
The HTTP MD5 plug-in works in the background to automatically verify the
content of messages using MD5 checksums. With the plug-in, messages can be
transferred over (trusted but) unreliable connections. The plug-in can be used
on the client side and server side.
<div class="p"><!----></div>
To use the plug-in, compile and link your application with <i>httpmd5.c</i> and <i>md5evp.c</i> located in the <i>plugin</i> directory of the package. The <i>md5evp.c</i> implementation uses the EVP interface to compute MD5 checksums with OpenSSL (compiled with <i>-DWITH_OPENSSL</i>).
<div class="p"><!----></div>
To enable the plug-in in your code, register the plug-in as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "httpmd5.h" <br />
... <br />
<b>if</b>&nbsp;(soap_register_plugin(&amp;soap, http_md5)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register
</td></tr></table><br></i>
Once registered, MD5 checksums are produced for all outbound messages. Inbound messages with MD5 checksums in the HTTP header are automatically verified.
<div class="p"><!----></div>
The plug-in requires you to set the <i>SOAP_IO_STORE</i> flag when sending SOAP with attachments:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "httpmd5.h" <br />
... <br />
<b>struct</b>&nbsp;soap soap; <br />
soap_init1(&amp;soap, SOAP_IO_STORE); <br />
<b>if</b>&nbsp;(soap_register_plugin(&amp;soap, http_md5) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register <br />
... now safe to send SOAP with attachments ...
</td></tr></table><br></i>
Unfortunately, this eliminates streaming.
<div class="p"><!----></div>
<h4><a name="tth_sEc18.36.4">
18.36.4</a>&nbsp;&nbsp;<font color="#0000FF">The HTTP Digest Authentication Plug-in</font></h4>
<div class="p"><!----></div>
The HTTP digest authentication plug-in enables a more secure authentication
scheme compared to basic authentication. HTTP basic authentication sends
unencrypted userids and passwords over the net, while digest authentication
does not exchange passwords but exchanges checksums of passwords (and other
data such as nonces to avoid replay attacks). For more details, please see
RFC 2617.
<div class="p"><!----></div>
The HTTP digest authentication can be used next to the built-in basic
authentication, or basic authentication can be rejected to tighten security.
The server must have a database with userid's and passwords (in plain text
form). The client, when challenged by the server, checks the authentication
realm provided by the server and sets the userid and passwords for digest
authentication. The client application can temporarily store the userid and
password for a sequence of message exchanges with the server, which is faster
than repeated authorization challenges and authentication responses.
<div class="p"><!----></div>
At the client side, the plug-in is registered and service invocations are
checked for authorization challenges (HTTP error code 401). When the server
challenges the client, the client should set the userid and password and retry
the invocation. The client can determine the userid and password based on the
authentication realm part of the server's challenge. The authentication information can be temporarily saved for multiple invocations.
<div class="p"><!----></div>
Client-side example:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "httpda.h" <br />
... <br />
<b>if</b>&nbsp;soap_register_plugin(&amp;soap, http_da)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register <br />
... <br />
<b>if</b>&nbsp;(soap_call_ns__method(&amp;soap, ...) != SOAP_OK) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap.error == 401) // challenge: HTTP authentication required <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!strcmp(soap.authrealm, authrealm)) // determine authentication realm
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>struct</b>&nbsp;http_da_info info; // to store userid and passwd <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http_da_save(&amp;soap, &amp;info, authrealm, userid, passwd); // set userid and passwd for this realm<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap_call_ns__method(&amp;soap, ...) == SOAP_OK) // retry <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ ... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(&amp;soap); // userid and passwd were deallocated <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http_da_restore(&amp;soap, &amp;info); // restore userid and passwd <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!soap_call_ns__method(&amp;soap, ...) == SOAP_OK) // another call <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http_da_release(&amp;soap, &amp;info); // remove userid and passwd
</td></tr></table><br></i>
This code supports both basic and digest authentication.
<div class="p"><!----></div>
The server can challenge a client using HTTP code 401. With the plug-in, HTTP digest authentication challenges are send. Without the plug-in, basic authentication challenges are send.
<div class="p"><!----></div>
Each server method can implement authentication as desired and may enforce
digest authentication or may also accept basic authentication responses. To
verify digest authentication responses, the server should compute and compare
the checksums using the plug-in's <i>http_da_verify_post</i> function for
HTTP POST requests (and <i>http_da_verify_get</i> for HTTP GET requests with
the HTTP GET plugin) as follows:
<br><br><table border=0 width="100%" cellpadding="8" bgcolor="#B0D0B0"><tr><td><i>
#include "httpda.h" <br />
... <br />
<b>if</b>&nbsp;(soap_register_plugin(&amp;soap, http_da)) <br />
&nbsp;&nbsp;&nbsp;soap_print_fault(&amp;soap, stderr); // failed to register <br />
... <br />
soap_serve(&amp;soap); <br />
... <br />
<b>int</b>&nbsp;ns__method(<b>struct</b>&nbsp;soap *soap, ...) <br />
{ <br />
&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>userid &amp;&amp; soap<tt>-&gt;</tt>passwd) // client used basic authentication
&nbsp;&nbsp;&nbsp;{ // may decide not to handle, but if ok then go ahead and compare info:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!strcmp(soap<tt>-&gt;</tt>userid, userid) &amp;&amp; !strcmp(soap<tt>-&gt;</tt>passwd, passwd)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ ... handle request ... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;<b>else</b>&nbsp;<b>if</b>&nbsp;(soap<tt>-&gt;</tt>authrealm &amp;&amp; soap<tt>-&gt;</tt>userid) // Digest authentication <br />
&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passwd = ... // database lookup on userid and authrealm to find passwd <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!strcmp(soap<tt>-&gt;</tt>authrealm, authrealm) &amp;&amp; !strcmp(soap<tt>-&gt;</tt>userid, userid)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>if</b>&nbsp;(!http_da_verify_post(soap, passwd)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ ... handle request ... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;SOAP_OK; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;soap<tt>-&gt;</tt>authrealm = authrealm; // set realm for challenge <br />
&nbsp;&nbsp;&nbsp;<b>return</b>&nbsp;401; // Not authorized, challenge digest authentication <br />
}
</td></tr></table><br></i>
<div class="p"><!----></div>
</body>
<br /><br /><hr /><small>File translated from
T<sub><font size="-1">E</font></sub>X
by <a href="http://hutchinson.belmont.ma.us/tth/">
T<sub><font size="-1">T</font></sub>H</a>,
version 3.72.<br />On 19 Feb 2006, 11:36.</small>
</html>