Getting Started with gSOAP

Introduction to XML data bindings with gSOAP {#bindings} --- XML is a universally accepted data format to push structured information along, just as many other structured data formats are designed to do. But XML has an advantage over so-called "schemaless" data formats: XML schemas describe types, elements, and attributes with their properties to validate XML content. Validation gives us a strong safety net that ensures that invalid content is automatically rejected, before the data is processed by the application. XML schemas also allow us to build larger and more complex data structures and systems from other schemas as building blocks, without having to worry about name and type clashes. To benefit most from XML (and benefit from using Web service protocols that are built on top of XML) we should strongly consider using **XML data bindings** when working with XML. XML data bindings for C/C++ bind XML schema types to C/C++ types. So integers in XML are bound to C integers, strings in XML are bound to C or C++ strings, complex types in XML are bound to C structs or C++ classes, and so on. So we know for sure that the structured data you create and accept will fit the data model and is **static type safe**. In other words, by leveraging strong typing in C/C++, your XML data meets **XML validation requirements** and satisfies **XML interoperability requirements**. You can also **serialize application-specific data structures** in XML with our data binding tools that map your application's C/C++ data types to XML schema. So even legacy C/C++ applications and data can be converted to XML and used in Web services. This article presents the basics to understand the XML data bindings for C and C++ with gSOAP. We give an overview of the gSOAP tools and libraries and present example client and server applications. To download the gSOAP toolkit, see [download and installation.](http://www.genivia.com/downloads.html) To learn more after reading this article, visit [XML data bindings.](http://www.genivia.com/doc/databinding/html/index.html) Consider the following example XML schema `hr.xsd` with an *`employee`* type defined in an *`HR`* schema namespace: [xml] <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="HR" xmlns:tns="HR"> <complexType name="employee"> <sequence> <element name="manages" type="tns:employee" minOccurs="0" maxOccurs="12"/> </sequence> <attribute name="name" type="string" use="required"/> <attribute name="ID" type="int" use="default" default="9999"/> </complexType> <element name="employee" type="tns:employee"/> </schema> This schema describes the following example XML document, also called an instance of the schema: [xml] <ns:employee xmlns:ns="HR" name="Jane Doe" ID="123"> <manages name="John Smith" ID="456"/> <manages name="Mike Johnson" ID="789"/> </ns:employee> An XML data binding for C/C++ maps schemas to C/C++ types and vice versa. The gSOAP XML data binding for this complex type in C++ is a `ns__employee` class: #import "gsoap/import/stlvector.h" // import std::vector XML data binding //gsoap ns schema namespace: HR class ns__employee { public: @std::string name 1; // required name attribute @int ID 0 = 9999; // optional ID attribute, defaults to 9999 std::vector<ns__employee*> manages 0:12; // up to 12 <manages> elements }; This **data binding interface** in C/C++ is auto-generated from the example schema with the **wsdl2h** tool. But you can also declare your own interface to make your C/C++ types XML serializable and generate XML schemas for these. The wsdl2h command takes WSDL and/or XSD files or URLs to these files as command-line arguments: [command] wsdl2h -o hr.h hr.xsd This generates the `hr.h` interface file with interface declarations and the `ns__employee` class shown above. The `ns__employee` class has a required name (`1` means that member occurs exactly once in XML content), an integer ID with default value `9999` which is used when the value is omitted (`0` means may be optional in XML content), and up to twelve employees whom he or she manages (`0:12` means up to 12 occurrences). The pointers in the vector may not be stricly needed, but pointers can be useful for two main reasons. Firstly, you can serialize objects of base and derived classes via pointers. Secondly, you can serialize object graphs. That is, (cyclic) graphs are accurately serialized in XML using the context flag `SOAP_XML_GRAPH` or in SOAP-encoded format, otherwise all cycles will be cut by the gSOAP engine to serialize finite XML document trees. Note the use of a prefix `ns` in the `ns__employee` class. We use this convention to bind XML namespace prefixes to C/C++ types, member names, and to Web service functions. A prefix is not absolutely required to serialize types in XML, but it is strongly recommended to ensure that the type is bound to a schema. - a colon can be used to prefix names in data bindings. For example `ns:employee` instead of `ns__employee`. However, the colon notation cannot guarantee the absence of C/C++ name clashes caused by identical names defined in different XML namespaces (e.g. `ns:employee` clashes with `xy:employee` in C/C++, yet they are different tags in XML). - the `//gsoap` directives and class member annotations are part of the data binding specification that is auto-generated from WSDLs and schemas with **wsdl2h**. These annotations are used to generate the **data binding implementation** code with **soapcpp2**. You can set various properties of the schema using [directives](http://www.genivia.com/doc/databinding/html/index.html#directives). An XML data binding makes it easy to write code to read, write, and manipulate XML-sourced data. The binding allows you to populate and extract XML data by working on C/C++ data structures that are equivalent to schema structures. Therefore, the benefit of the gSOAP data binding is that you can work with native C/C++ types, thereby creating and accepting valid XML data that is static type safe in C/C++. As an example, suppose we create a `boss` instance of the `ns__employee` class and add an employee to the list of employees that the boss manages, where the new employee is read from an XML file: #include "soapH.h" // include auto-generated data bindings #include "ns.nsmap" // include auto-generated XML namespaces struct soap *soap = soap_new(); // a new gSOAP runtime engine context, for memory management, IO, etc. ns__employee boss; boss.name = "Jane Doe"; boss.ID = 123; ns__employee temp; soap_read_ns__employee(soap, &temp); // read temp XML data from stdin (auto-generated function) boss.manages.push_back(&temp); soap_write_ns__employee(soap, &boss); // write boss XML data to stdout (auto-generated function) soap_destroy(soap); // delete managed and deserialized data soap_end(soap); // delete other data soap_free(soap); // we're done Use the **soapcpp2** tool on the data binding interface `hr.h` (that was shown earlier) to generate **data binding implementation** code with efficient **streaming XML serializers** for the C/C++ types in your application. Then compile the generated code `soapC.cpp` with the engine code `stdsoap2.cpp` together with the application code `hr.cpp`, e.g. on the command line: [command] soapcpp2 hr.h c++ -o hr hr.cpp soapC.cpp stdsoap2.cpp Here, the soapcpp2 tool is executed on `hr.h` that was generated by wsdl2h from a schema. However, you can also execute the soapcpp2 tool on your own interface file by declaring the C/C++ data types that you want to serialize and let soapcpp2 generate the schema together with the XML serializers. The soapcpp2 tool generates a set of functions for each serializable C/C++ type declared in the interface file. These functions use names that follow simple naming conventions, see e.g. auto-generated [operations on classes and structs.](http://www.genivia.com/doc/databinding/html/index.html#toxsd9-13). There are only a few auto-generated functions per serializable type that you will ever need to use, so you don't need to read in detail what is in the generated files `soapStub.h`, `soapH.h` and `soapC.cpp` that implement these functions for each serializable type. The auto-generated functions to create, read, write, and deep copy and delete data for each C/C++ type declared in the data binding interface are illustrated below for the `ns__employee` class type: // managed instantiation supporting automatic deletion ns__employee *employee = soap_new_ns__employee(soap); // instantiate and set only the required (as per schema) member(s) ns__employee *employee = soap_new_req_ns__employee(soap, "Jane Doe"); // also std::string is a serializable type and has a managed instantiator std::string *name = soap_new_std__string(soap); *name = "Jane Doe"; // instantiate and set all members of an employee std::vector<ns__employee*> manages; ns__employee *employee = soap_new_set_ns__employee(soap, name, 123, manages); // write to std::cout via std::ostream* soap->os (std::istream* soap->is is for reading) soap->os = &std::cout; if (soap_write_ns__employee(soap, employee)) ... // handle IO error soap->os = NULL; // reset to use default streams // read from a file via soap->recvfd (soap->sendfd is for writing) soap->recvfd = open("employee.xml", O_RDONLY); if (soap_read_ns__employee(soap, employee)) ... // handle IO error close(soap->recvfd); soap->recvfd = 0; // reset to stdin // deep copy employee to another managing context (soapcpp2 option -Ec to generate) struct soap *other_soap = soap_new(); ns__employee *employee_copy = employee->soap_dup(other_soap); // reset employee to default member values employee->soap_default(soap); // delete all objects managed by the context, must be called before soap_end(soap) soap_destroy(soap); // free all data allocated with soap_malloc and internal data soap_end(soap); To serialize XML to strings and parse XML from strings you can set the C++ streams `soap->os` and `soap->is` to point to `std::stringstream` objects: #include "soapH.h" #include "ns.nsmap" #include <sstream> std::stringstream ss; struct soap *soap = soap_new(); // write to string via std::ostream* soap->os soap->os = &ss; if (soap_write_ns__employee(soap, employee)) ... // handle IO error soap->os = NULL; ... = ss.str(); // read from string via std::istream* soap->is ss.str("<ns:employee ...>...</ns:employee>"); soap->is = &ss; if (soap_read_ns__employee(soap, employee)) ... // handle IO error soap->is = NULL; soap_destroy(soap); soap_end(soap); soap_free(soap); For gSOAP 2.8.28 and later, serializing XML to C `char*` strings and parsing XML from C strings and buffers is fairly easy. You can simply set `soap->os` to point to an output string and set `soap->is` to point to an input string to parse from: #include "soapH.h" #include "ns.nsmap" struct soap *soap = soap_new(); // C string we want to set to the NUL-terminated string with XML output const char *cs = NULL; soap->os = &cs; if (soap_write_ns__employee(soap, employee)) ... // handle IO error soap->os = NULL; ... = cs; // use the string (do not free(cs): cs is managed by context and freed with soap_end()) // C string we want to read from soap->is = "<ns:employee ...>...</ns:employee>"; if (soap_read_ns__employee(soap, employee)) ... // handle IO error soap->is = NULL; soap_destroy(soap); soap_end(soap); soap_free(soap); SOAP/XML and REST-XML service operations essentially work the same way and require very few lines of code to send and receive data serialized in XML. Most of the SOAP/XML processing logic and details are hidden, allowing you to focus on your application logic. Continue reading the next section to learn more. The gSOAP tools also support JSON and XML-RPC data formats and services. See our [tutorials](tutorials.html) and [XML-RPC and JSON/JSONPath.](doc/xml-rpc-json/html/index.html) To learn more about XML data bindings, see [XML data bindings.](http://www.genivia.com/doc/databinding/html/index.html) To learn more about the tools and libraries, see the [overview of gSOAP tools and libraries.](#overview) To get gSOAP, visit [download and installation.](downloads.html) [![To top](images/go-up.png) To top](tutorials.html) Introduction to Web Services with gSOAP {#services} --- You can implement client and server-side XML Web services in C or in C++ without much coding effort by taking advantage of the gSOAP autocoding tools to implement the Web services API. This introduction presents the basics that you will need to know to get started quickly developing your own services and to consume services. Use the **wsdl2h** tool to convert a set of WSDL and/or XSD files to a gSOAP header file, for example from the command line: [command] wsdl2h [options] -o file.h ... XSD and WSDL files ... This command converts WSDL and XSD files to C++ (or pure C with wsdl2h option `-c`) and saves the declarations in `file.h`. This special header file with the **data binding interface** uses familiar C/C++ syntax extended with directives and annotations that are used by the **soapcpp2** tool to generate the **data binding implementation** code and services from the command line: [command] soapcpp2 [options] file.h This code generation process is shown below and illustrates our two-stage approach in more detail. The interface file (lightly shaded document at the top right) is generated by wsdl2h from a set of WSDL and XSD files (the dark shaded documents at the top left). Optional parts are shown dashed. The interface file is then input (bottom left) to the soapcpp2 tool together with imported protocol declarations (for plugins) and custom serializers. The soapcpp2 tool generates the data binding implementation and service code for the application (the dark shaded box at the lower right): <div class="chart"><a href="images/flowchart.png" data-lightbox="image-1"><img src="images/flowchart.png"/></a></div> Omitting the first step in this two-stage process is possible. You can write your own interface file to generate data binding code, services, and the WSDL and XML schema files that describe your services and your serialized XML. An interface file can be as simple as a [one liner](examples/time/index.html) Web service. The default option for soapcpp2 is to generate both client and server code in `soapClient.c`[`pp`] and `soapServer.c`[`pp`], respectively. These files implement the Web service API declared in the interface file `file.h`, meaning that the service API functions in `file.h` of the form: int prefix__func(arg1, arg2, ..., argn, result); are implemented in the auto-generated `soapClient.c`[`pp`] as client-side stub functions: int soap_call_prefix__func(struct soap*, const char *URL, const char *action, arg1, arg2, ..., argn, result); where `URL` is the Web service endpoint URL to connect to and `action` is a SOAP action header. The `arg` service request parameters are values serialized in XML and sent with the request to the Web service. The `result` is the service response, usually a struct with data members for the service response parameters. You can use NULL for the default URL and action set by the `//gsoap prefix port:` and `//gsoap prefix method-action:` directives in `file.h`, which are copied from the source WSDL. The auto-generated `soapServer.c`[`pp`] implements a service dispatcher: int soap_serve(struct soap*); You can use this dispatcher directly to deploy CGI-hosted services or put it in a loop to accept incoming requests on a port (see the server examples in this article). You should also implement all of the service API functions declared in `file.h` but with an additional first argument: int prefix__func(struct soap*, arg1, arg2, ..., argn, result); By convention, gSOAP functions take the engine context `struct soap*` as the first argument and return `SOAP_OK` (zero) or an error code. To display an error, use: void soap_print_fault(struct soap*, FILE*); void soap_stream_fault(struct soap*, std::ostream&); To build your client and server, you will also need to compile `soapC.c`[`pp`] and `stdsoap2.c`[`pp`] (or link with a library, see [overview of tools and libraries](#overview)). You can generate more powerful C++ proxy and service classes with soapcpp2 option `-j`. Otherwise, your C++ code will be similar to C code with stub functions and a service dispatcher. With option `-j`, the `NameProxy` class is saved in `soapNameProxy.h` and `soapNameProxy.cpp`. The `NameService` class is saved in `soapNameService.h` and `soapNameService.cpp`. The details of the auto-generated class-based APIs are saved in the proxy and service header files, which we will not describe in detail here, but that are used in the C++ client and server examples in this article. We also recommend that you read about the examples below to understand how a [C++ client](#client-cpp) and a [C++ server](#server-cpp) are implemented (both with option `-j`), and how a [C client](#client-c) and a [C server](#server-c) are implemented. [![To top](images/go-up.png) To top](tutorials.html) How portable, fast, and big will my code be? {#performance} --- The gSOAP toolkit supports a wide variety of platforms and is portable to Windows Win32/Win64 (XP, Vista, Windows 7/8/10), MS-DOS, Cygwin, MinGW, Linux (RedHat, SuSE, etc.), Unix (Mac OS X, Solaris, HP-UX, BSD, FreeBSD, Irix, QNX, AIX, TRU64), OpenVMS, NonStop Tandem, VxWorks, WinCE, Palm OS, Symbian, iOS, Raspberry Pi, and embedded systems/RTOS. You can deploy your gSOAP C and C++ services with [Apache modules](doc/apache/html/index.html) and with [IIS ISAPI.](doc/isapi/html/index.html) Also CGI and FastCGI can be used to deploy your services. You can use [WinInet](doc/wininet/html/index.html) to develop Windows client applications. Or you can simply deploy stand-alone SOAP and RESTful services and clients with the built-in HTTP/S stack. You can also leverage the gSOAP toolkit to deploy legacy C and C++ systems as modernized Web services with SaaS. The Web service API and WSDL service descriptions are auto-generated for you. ### Interoperable Applications developed with gSOAP are interoperable with other SOAP and RESTful XML stacks such as .NET WCF, Axis, PHP5, SOAP::Lite, SOAP4R, Weblogic, ZSI and many others. Furthermore, XML data binding enables interoperable XML data processing in non-SOAP/REST environments. The assurance of interoperability is strong. The gSOAP toolkit participated early on in [SOAP interoperability](http://www.whitemesa.com/interop.htm) testing and in establishing the more recent [W3C XML Schema Patterns for Databinding Interoperability.](https://www.w3.org/2002/ws/databinding/edcopy/report/all.html) The gSOAP toolkit meets W3C and OASIS standards requirements for WSDL, XSD, SOAP, RESTful XML, WS-I Basic and Security Profiles, WS-Policy, WS-SecurityPolicy, WS-Security, WS-Addressing, WS-ReliableMessaging, WS-Discovery, and passes W3C Databinding interoperability tests. The toolkit also includes libraries for XML-RPC and JSON. ### High performance The gSOAP toolkit generates efficient XML serialization code for fast Web services and XML-enabled applications. The serializers push and pull XML directly to and from sockets without the overhead of DOM or SAX or third-party HTTP and XML stacks. Also MIME/MTOM attachments can be streamed for efficient binary content transfers. A SOAP/XML message throughput test with a stand-alone echo string SOAP service over HTTP on quad core Intel Core i7 1.8GHz machines gives a sustained performance of **5,600 service invocations per second**. That is **11,200 one-way messages per second**, with IPv4 and keep-alive enabled. With IPv6 the performance drops slightly to 4,500 service invocations per second. A stand-alone HTTP1.1 gSOAP server with keep-alive enabled is fast for two-way messaging. We observed that **the WebSockets protocol gave no speed improvement**. When socket connections are established from scratch without connection persistence (i.e. no keep-alive), the performance is 2,230 service invocations per second. That is 4,460 one-way messages per second. Here, the TCP/IP connection overhead dominates the execution time. The throughput of SOAP-over-UDP messaging with gSOAP is similar. However, network and TCP/IP or UDP connection latencies will vary from system to system. With HTTPS encryption and server authentication using a stand-alone gSOAP server with OpenSSL RSA 2048 bits, the sustained performance is 3,700 service invocations per second with HTTP keep-alive. Without connection persistence, i.e. each invocation demands a full TLS handshake and certificate authentication, 1,200 service invocations per second can be achieved which is still **less than 1ms to complete an HTTPS service invocation**. ### Small memory footprint The memory footprint of a gSOAP application is typically low. The code size depends linearly on the size of the WSDL and/or XML schemas that are mapped to C/C++ types. Each serializable struct and class requires some code. Runtime memory usage depends on your application's runtime data, which includes the size of the C/C++ data (de)serialized in XML. Your data is directly serialized in XML. There is no other significant memory overhead. Some stack or heap memory is used by the gSOAP engine context that has an internal IO buffer (the default 64K size of the buffer can be changed). Also, we make it very easy for you to [manage](doc/databinding/html/index.html#memory) your data in memory, including allocation, deep copy, and deallocation. A stand-alone C client such as a calculator or a stock quote ticker for example, compiled `-DWITH_LEANER` uses 94K code (Linux/i386/GCC -O1), 4K heap, and 3K stack footprint. With standard non-lean compilation, these numbers are 142K code, 5K heap, and 66K stack, where stack space is used for the engine context that includes a 64K read/write buffer to optimize socket message transfers. [![To top](images/go-up.png) To top](tutorials.html) Overview of gSOAP tools and libraries {#overview} --- After installation of the software, you will get several development tools and libraries: - The **wsdl2h** tool translates WSDL and XSD files to a gSOAP header file with the **data binding interface**. - The **soapcpp2** tool takes a header file with the data binding interface and generates the **data binding implementation** with **XML serializers** to implement Web services and XML data bindings. The generated code is platform independent and portable. - The **runtime engine** handles HTTP and XML transport over any IO device and sockets and is responsible for memory allocation. The runtime is configured per platform and declared in `stdsoap2.h` and implemented in `stdsoap2.c` (for C) and `stdsoap2.cpp` (for C++). Also, gSOAP installs `libgsoap`, `libgsoapssl`, `libgsoap++`, and `libgsoapssl++` libraries, see further below. - The **XML DOM API** and **DOM parser** are implemented in `dom.c` (for C) and `dom.cpp` (for C++). XML DOM is used by the WS-Security plugin and to store xsd:anyType and xsd:any XML data. The gSOAP DOM API offers a hybrid **DOM + data binding approach** that allows you to embed serializable C/C++ data types in a DOM node graph. See [XML DOM and XPath.](http://www.genivia.com/doc/dom/html/index.html) - The new **domcpp** tool generates C or C++ source code to parse, search, manipulate, and write raw XML using the DOM API and DOM parser. The tool takes an XML file or XPath query. The domcpp tool is part of the XML DOM examples in `gsoap/samples/dom` in the download package. See [XML DOM and XPath.](http://www.genivia.com/doc/dom/html/index.html) - The **XML-RPC** and **JSON** libraries and examples are located in `gsoap/samples/xml-rpc-json` in the download package. See [XML-RPC and JSON/JSONPath.](http://www.genivia.com/doc/xml-rpc-json/html/index.html) - The new **jsoncpp** tool generates C or C++ source code to parse, manipulate, and write JSON data. The tool takes a JSON file or JSONPath query. See [XML-RPC and JSON/JSONPath.](http://www.genivia.com/doc/xml-rpc-json/html/index.html) - Many other demonstration examples are located in `gsoap/samples` in the download package to get you started. The wsdl2h tool does exactly what the name suggests: it translates WSDL files into .h header files with data binding interface declarations of services and their C/C++ data. The wsdl2h tool is a gSOAP application itself and uses data binding code generated for the schemas of WSDL specifications and the W3C XML schema-of-schemas. The soapcpp2 tool runs as a C/C++ preprocessor on a .h header file with the data binding interface to generate the source code "glue" that implements services and XML data bindings with XML serializers for your projects. It is also possible to use soapcpp2 without wsdl2h by declaring services and XML data binding types directly in familiar C/C++ syntax. In this scenario, the soapcpp2 tool also generates WSDL and XSD files that describe the services and data bindings. The gSOAP runtime engine is also installed as a library compiled from `stdsoap2.c` + `dom.c` and `stdsoap2.cpp` + `dom.cpp` that you can link to your project code: - `gsoap/libgsoap.a` the C runtime engine (plain and compact, no HTTPS) - `gsoap/libgsoapssl.a` the C runtime engine with DOM support, cookies, zlib, and SSL - `gsoap/libgsoap++.a` the C++ runtime engine (plain and compact, no HTTPS) - `gsoap/libgsoapssl++.a` the C++ runtime engine with DOM support, cookies, zlib, and SSL The extended SSL versions of the library are recommended to use in your project, since HTTPS and HTTP compression are widely in use (but cookies are often ignored). If you want to use the source code of the runtime engine and DOM parser instead of the extended SSL versions of the library, then you must compile all sources with compiler flags `-DWITH_DOM`, `-DWITH_GZIP`, `-DWITH_OPENSSL`, `-DWITH_COOKIES`, and optionally with `-DWITH_IPV6` for IPv6 support. [![To top](images/go-up.png) To top](tutorials.html) Example calculator client (C++) {#client-cpp} --- Let's put the gSOAP tools to work to convert a calculator WSDL to a working C++ client that invokes the calculator service: [command] wsdl2h -o calc.h http://www.genivia.com/calc.wsdl The `calc.h` file includes the following declarations (showing only one operation here for brievety): //gsoap ns2 schema namespace: urn:calc //gsoap ns2 schema form: unqualified //gsoap ns2 service name: calc //gsoap ns2 service type: calcPortType //gsoap ns2 service port: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi //gsoap ns2 service namespace: urn:calc //gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http //gsoap ns2 service method-protocol: add SOAP //gsoap ns2 service method-style: add rpc //gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/ //gsoap ns2 service method-action: add "" //gsoap ns2 service method-output-action: add Response int ns2__add( double a, // Input parameter double b, // Input parameter double &result // Output parameter ); As you can see, gSOAP uses three basic forms of source code annotations in the auto-generated data binding interface file: - [directives](doc/databinding/html/index.html#directives), such as `//gsoap ns2 schema namespace: urn:calc` - [identifier naming conventions](doc/databinding/html/index.html#toxsd2), such as `ns2__add` - other annotations (not shown in this example) for declaring XML attributes and for enforcing XML validation rules. The directives in this example describe the Web service API properties of this calculator service: this is a SOAP RPC style messaging service over HTTP. Other possible protocols include REST protocols (POST, GET, PUT, and DELETE) and `SOAP-GET`. Service operations are declared in the gSOAP interface file as functions with parameters that are all input arguments except for the last parameter, which is a reference (or a pointer for C) to the result. The result argument is set by the response data of the service. We selected this example because it has simple parameters to illustrate the operational aspects. Next, you run the soapcpp2 tool to generate the data binding implementation that "glues" your code to the service operations: [command] soapcpp2 -j -CL -I/path/to/gsoap/import calc.h Option `-j` produces C++ proxy classes with `-CL` indicating client-side (non-libs), using an import path for the `#import` files in `calc.h`. Several files are generated, among those are: [command] Saving soapStub.h annotated copy of the source input Saving soapH.h declarations to #include Saving soapcalcProxy.h client proxy class Saving soapcalcProxy.cpp client proxy class Saving calc.nsmap namespace mapping table Saving soapC.cpp serializers See the [calc++ report](examples/calc++/index.html) generated with soapcpp2 option `-r`. Use the generated proxy in your main program `calcclient.cpp` to invoke the calculator service: #include "calc.nsmap" // XML namespace mapping table (only needed once at the global level) #include "soapcalcProxy.h" // the proxy class, also #includes "soapH.h" and "soapStub.h" int main() { calcProxy calc; double sum; if (calc.add(1.23, 4.56, sum) == SOAP_OK) std::cout << "Sum = " << sum << std::endl; else calc.soap_stream_fault(std::cerr); calc.destroy(); // same as: soap_destroy(calc.soap); soap_end(calc.soap); } To compile the program and run it, execute on the command line: [command] c++ -o calcclient calcclient.cpp soapC.cpp soapcalcProxy.cpp stdsoap2.cpp ./calcclient Sum = 5.79 It is highly recommended to change the `n2__` prefix that wsdl2h produced to something more maintainable. To do so, add the following line to `typemap.dat` that is used by wsdl2h (put `typemap.dat` in your build directory or use wsdl2h with option `-t/path/to/gsoap/typemap.dat`): [command] c = "urn:calc" Then run wsdl2h again to generate a new `calc.h` file with the temporary default namespace prefix `ns2` permanently replaced by prefix `c`. Finally, you may want to add timeouts to avoid the client from indefinitely blocking on an unresponsive server: calc.soap->connect_timeout = 10; // connect within 10s calc.soap->send_timeout = 5; // send timeout is 5s calc.soap->recv_timeout = 5; // receive timeout is 5s if (calc.add(1.23, 4.56, sum) == SOAP_OK) ... Some systems (Linux) do no support connection timeouts. To prevent connection reset errors (UNIX sigpipe), set one of these: calc.soap->socket_flags = MSG_NOSIGNAL; calc.soap->accept_flags = SO_NOSIGPIPE; or install a sigpipe handler: void sigpipe_handle(int x) { } signal(SIGPIPE, sigpipe_handle); [![To top](images/go-up.png) To top](tutorials.html) Example calculator client (C) {#client-c} --- The C client is similar to the C++ client described in the previous section. However, you cannot use a proxy class. Instead, you use an auto-generated client stub function to invoke the service. Use wsdl2h option `-c` to generate pure C code: [command] wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl Next, execute soapcpp2 on `calc.h` on the command line to generate the data binding implementation: [command] soapcpp2 -CL calc.h Several files are generated, among those are: [command] Saving soapStub.h annotated copy of the source input Saving soapH.h declarations to #include Saving calc.nsmap namespace mapping table Saving soapClient.c client proxy class Saving soapC.c serializers See the [calc report](examples/calc/index.html) generated with soapcpp2 option `-r`. The generated "client stub function" `soap_ns2__add` defined in `soapClient.c` implements the interface function `ns2__add` that is declared in `calc.h`. Use this stub function to invoke the service: #include "calc.nsmap" // XML namespace mapping table (only needed once at the global level) #include "soapH.h" // client stubs, serializers, etc. int main() { struct soap soap = soap_new(); // allocate and initalize a context double sum; if (soap_call_ns2__add(soap, NULL, NULL, 1.23, 4.56, &sum) == SOAP_OK) printf("Sum = %g\n", sum); else soap_print_fault(soap, stderr); soap_destroy(soap); // delete deserialized objects soap_end(soap); // delete allocated data soap_free(soap); // free the soap struct context data } To compile the program and run it, execute on the command line: [command] cc -o calcclient calcclient.c soapC.c soapClient.c stdsoap2.c ./calcclient Sum = 5.79 It is highly recommended to change the `n2__` prefix that wsdl2h produced to something more maintainable. To do so, add the following line to `typemap.dat` that is used by wsdl2h (put `typemap.dat` in your build directory or use wsdl2h option `-t/path/to/gsoap/typemap.dat`): [command] c = "urn:calc" Then run wsdl2h with option `-c` (for C code) again to generate a new `calc.h` file with the temporary default namespace prefix `ns2` permanently replaced by prefix `c`. Finally, you may want to add timeouts to avoid the client from indefinitely blocking on an unresponsive server: soap->connect_timeout = 10; // connect within 10s soap->send_timeout = 5; // send timeout is 5s soap->recv_timeout = 5; // receive timeout is 5s if (soap_call_c__add(soap, NULL, NULL, 1.23, 4.56, &sum) == SOAP_OK) ... Some systems (Linux) do no support connection timeouts. To prevent connection reset errors (UNIX sigpipe), set one of these: soap->socket_flags = MSG_NOSIGNAL; soap->accept_flags = SO_NOSIGPIPE; or install a sigpipe handler: void sigpipe_handle(int x) { } signal(SIGPIPE, sigpipe_handle); [![To top](images/go-up.png) To top](tutorials.html) Example calculator server (C++) {#server-cpp} --- For this example we start with a WSDL file and execute wsdl2h on this file from the command line: [command] wsdl2h -o calc.h http://www.genivia.com/calc.wsdl This command saves `calc.h`, declaring the interface to the calculator service. Here we only show one of the service operations with the other essential parts: //gsoap ns2 schema namespace: urn:calc //gsoap ns2 schema form: unqualified //gsoap ns2 service name: calc //gsoap ns2 service type: calcPortType //gsoap ns2 service port: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi //gsoap ns2 service namespace: urn:calc //gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http //gsoap ns2 service method-protocol: add SOAP //gsoap ns2 service method-style: add rpc //gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/ //gsoap ns2 service method-action: add "" //gsoap ns2 service method-output-action: add Response int ns2__add( double a, // Input parameter double b, // Input parameter double &result // Output parameter ); In addition to `ns2__add`, the service implements `ns2__sub`, `ns2__mul`, `ns2__div`, and `ns2__pow` functions with `double` parameters. We selected this example because it has simple parameters to illustrate the operational aspects. Next, we generate the server-side code and serializers using soapcpp2 on the command line: [command] soapcpp2 -j -SL -I/path/to/gsoap/import calc.h Option `-j` produces C++ service classes. The option `-SL` indicates server-side (non-libs) and `-I` specifies an import path for the `#import` directives located in `calc.h` (if any). Use the generated skeleton service class `calcService` that is declared in `soapcalcService.h` and defined in `soapcalcService.cpp`. The class declares the service operations as methods without actually implementing them. We implement the service operations in a new main program `calcserver.cpp`. We intent to deploy the service as a simple CGI-hosted service using the [Common Gateway Interface](http://en.wikipedia.org/wiki/Common_Gateway_Interface), which means you just need to call the `serve` method of the generated `calcService` class: #include "calc.nsmap" // XML namespace mapping table (only needed once at the global level) #include "soapcalcService.h" // the service class, also #includes "soapH.h" and "soapStub.h" int main() { calcService calc(SOAP_XML_INDENT); if (calc.serve() != SOAP_OK) calc.soap_stream_fault(std::cerr); calc.destroy(); // same as: soap_destroy(calc.soap); soap_end(calc.soap); } int calcService::add(double a, double b, double &result) { result = a + b; return SOAP_OK; } int calcService::sub(double a, double b, double &result) { result = a - b; return SOAP_OK; } int calcService::mul(double a, double b, double &result) { result = a * b; return SOAP_OK; } int calcService::div(double a, double b, double &result) { if (b == 0.0) { char *msg = (char*)soap_malloc(this->soap, 1024); snprintf(msg, 1024, "Trying to divide %f by zero", a); return this->soap_senderfault(msg, NULL); } result = a / b; return SOAP_OK; } int calcService::pow(double a, double b, double &result) { result = ::pow(a, b); // soap_errno is like errno, but compatible with Win32 if (soap_errno == EDOM) { char *msg = (char*)soap_malloc(this->soap, 1024); snprintf(msg, 1024, "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b); return this->soap_senderfault("Power function domain error", msg); } return SOAP_OK; } Note that you can use `soap_malloc` to malloc data that will be automatically released when the service is done. For class instances, use the auto-generated `soap_new_X(this->soap)` functions to allocate objects of a class `X` that will be deallocated after the service responded. Here are some examples on how to create temporary data managed by the `soap` engine context and to set default values: // allocate N bytes (managed by the 'soap' context) char *str = soap_malloc(soap, N); // duplicate a char string (managed by the 'soap' context) char *dup = soap_dup(soap, str); // instantiate one object X (managed by the 'soap' context) X *object = soap_new_X(soap); // instantiate an array of N objects X (managed by the 'soap' context) X *objects = soap_new_X(soap, N); // instantiate and set only the required (as per schema) members m1, ..., mk (managed by the 'soap' context) X *object = soap_new_req_X(soap, m1, m2, ..., mk); // instantiate and set all members m1, ..., mk (managed by the 'soap' context) X *object = soap_new_set_X(soap, m1, m2, ..., mk); // reset object to default member values object->soap_default_X(soap); After sending the Web service response, invoke `calc.destroy()` as shown in the `calcservice.cpp` code above. This calls `soap_destroy(this->soap)` and `soap_end(this->soap)` to delete context-managed objects and temporary data, respectively. Let's compile the program `calcserver.cpp` together with the auto-generated `soapcalcService.cpp` and `soapC.cpp` XML data bindings. Then we run it on the request message `calc.add.req.xml` that was auto-generated by soapcpp2 in the previous step: [command] c++ -o calcserver calcserver.cpp soapC.cpp soapcalcService.cpp stdsoap2.cpp ./calcserver < calc.add.req.xml Status: 200 OK Server: gSOAP/2.8 Content-Type: text/xml; charset=utf-8 Content-Length: 466 Connection: close <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:calc"> <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <ns2:addResponse> <result>0</result> </ns2:addResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> To host the service on the Web with CGI, install `calcserver` in `cgi-bin` on your Web server and set the permissions appropriately (this won't work if the file permissions are wrong or if CGI is not enabled). For FastCGI, compile the generated source code and `stdsoap2.cpp` with `-DWITH_FASTCGI`. To host the service as a stand-alone HTTP server, change the main program to invoke the `run` method with a port number as follows: int main() { calcService calc(SOAP_XML_INDENT); if (calc.run(8080) != SOAP_OK) calc.soap_stream_fault(std::cerr); calc.destroy(); } This runs the service as an iterative Web server on port 8080, but any error will terminate it. You may want to put this in an infinite loop to restart a `run()` on the same port. You also may want to add timeouts to avoid the server from indefinitely blocking on an unresponsive client: calc.soap->send_timeout = 5; // send timeout is 5s calc.soap->recv_timeout = 5; // receive timeout is 5s while (calc.run(8080) != SOAP_OK && calc.error != SOAP_TCP_ERROR) calc.soap_stream_fault(std::cerr); To prevent connection reset errors (UNIX sigpipe), set one of these: calc.soap->socket_flags = MSG_NOSIGNAL; calc.soap->accept_flags = SO_NOSIGPIPE; or install a sigpipe handler: void sigpipe_handle(int x) { } signal(SIGPIPE, sigpipe_handle); When deploying the Web server, we strongly recommend to use threads and set IO timeouts to harden the server. See the `samples/webserver` example in the gSOAP package. You can also deploy gSOAP services as fast and robust [Apache modules](http://www.genivia.com/doc/apache/html/index.html) and [ISAPI extensions.](http://www.genivia.com/doc/isapi/html/index.html) See also the [calc++ report](examples/calc++/index.html) generated with soapcpp2 option `-r`. [![To top](images/go-up.png) To top](tutorials.html) Example calculator server (C) {#server-c} --- For implementing a C service similar to the C++ service described in the previous section we cannot use a service class. Instead, use wsdl2h option `-c` to generate pure C code: [command] wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl soapcpp2 -SL calc.h Several files are generated, among those are: [command] Saving soapStub.h annotated copy of the source input Saving soapH.h declarations to #include Saving calc.nsmap namespace mapping table Saving soapServer.c server request dispatcher Saving soapC.c serializers The C implementation of the service requires global functions for the service operations: #include "calc.nsmap" // XML namespace mapping table (only needed once at the global level) #include "soapH.h" // server stubs, serializers, etc. int main() { struct soap *soap = soap_new1(SOAP_XML_INDENT); if (soap_serve(soap) != SOAP_OK) soap_print_fault(soap, stderr); soap_destroy(soap); // delete deserialized objects soap_end(soap); // delete allocated (deserialized) data soap_free(soap); // free the soap struct context data } int ns2__add(struct soap *soap, double a, double b, double &result) { result = a + b; return SOAP_OK; } int ns2__sub(struct soap *soap, double a, double b, double &result) { result = a - b; return SOAP_OK; } int ns2__mul(struct soap *soap, double a, double b, double &result) { result = a * b; return SOAP_OK; } int ns2__div(struct soap *soap, double a, double b, double &result) { if (b == 0.0) { char *msg = (char*)soap_malloc(soap, 1024); snprintf(msg, 1024, "Trying to divide %f by zero", a); return soap_sender_fault(soap, msg, NULL); } result = a / b; return SOAP_OK; } int ns2__pow(struct soap *soap, double a, double b, double &result) { result = ::pow(a, b); // soap_errno is like errno, but compatible with Win32 if (soap_errno == EDOM) { char *msg = (char*)soap_malloc(soap, 1024); snprintf(msg, 1024, "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b); return soap_sender_fault(soap, "Power function domain error", s); } return SOAP_OK; } Note the use of `soap_malloc` to allocate a temporary message string (in C we have no classes and thus we cannot use `soap_new_X` functions). Here are some examples on how to create temporary data managed by the `soap` engine context and to set default values: // allocate N bytes (managed by 'soap' context) char *str = soap_malloc(soap, N); // duplicate a char string (managed by 'soap' context) char *dup = soap_dup(soap, str); // allocate struct X (managed by 'soap' context) struct X *object = soap_malloc(soap, sizeof(struct X)); // reset struct X to default soap_default_X(soap, object); After sending the Web service response, call `soap_destroy(soap)` and `soap_end(soap)` to delete all context-managed objects and data, respectively. Let's compile the program `calcserver.c` together with the auto-generated `soapService.c` and `soapC.cpp` XML data bindings. Then we run it on the request message `calc.add.req.xml` that was auto-generated by soapcpp2 in the previous step: [command] cc -o calcserver calcserver.c soapC.c soapcalcService.c stdsoap2.c ./calcserver < calc.add.req.xml Status: 200 OK Server: gSOAP/2.8 Content-Type: text/xml; charset=utf-8 Content-Length: 466 Connection: close <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:calc"> <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <ns2:addResponse> <result>0</result> </ns2:addResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> To host the service on the Web with CGI, install `calcserver` in `cgi-bin` on your Web server and set the permissions appropriately (this won't work if the file permissions are wrong or if CGI is not enabled). For FastCGI, compile the generated source code and `stdsoap2.c` with `-DWITH_FASTCGI`. To host the service as a stand-alone HTTP server, change the main program: int main() { struct soap *soap = soap_new1(SOAP_XML_INDENT); if (!soap_valid_socket(soap_bind(soap, NULL, 8080, 100))) exit(EXIT_FAILURE); while (soap_valid_socket(soap_accept(soap))) { if (soap_serve(soap) != SOAP_OK) break; soap_destroy(soap); // delete deserialized objects soap_end(soap); // delete allocated (deserialized) data } soap_print_fault(soap, stderr); soap_free(soap); // free the soap struct context data } This runs the service as an iterative Web server on port 8080. You may want to add timeouts to avoid the server from indefinitely blocking on an unresponsive client: soap->send_timeout = 5; // send timeout is 5s soap->recv_timeout = 5; // receive timeout is 5s if (!soap_valid_socket(soap_bind(soap, NULL, 8080, 100))) ... To prevent connection reset errors (UNIX sigpipe), set one of these: soap->socket_flags = MSG_NOSIGNAL; soap->accept_flags = SO_NOSIGPIPE; or install a sigpipe handler: void sigpipe_handle(int x) { } signal(SIGPIPE, sigpipe_handle); When deploying the Web server, we strongly recommend to use threads and set IO timeouts to harden the server. See the `samples/webserver` example in the gSOAP package. You can also deploy gSOAP services as fast and robust [Apache modules](http://www.genivia.com/doc/apache/html/index.html) and [ISAPI extensions.](http://www.genivia.com/doc/isapi/html/index.html) See also the [calc report](examples/calc/index.html) generated with soapcpp2 option `-r`. [![To top](images/go-up.png) To top](tutorials.html) Example AWS S3 SOAP API client (C++) {#aws} --- This is a more advanced example of a stand-alone C++ client application for the AWS S3 API. You can generate the data binding interface file for AWS S3 API from the AWS S3 WSDL with wsdl2h. Then use soapcpp2 to generate the client-side (soapcpp2 option `-C`) data binding implementation with a C++ proxy class (soapcpp2 option `-j`): [command] wsdl2h -t typemap.dat -o aws-s3.h http://doc.s3.amazonaws.com/2006-03-01/AmazonS3.wsdl soapcpp2 -C -j aws-s3.h The example C++ stand-alone AWS S3 client application [aws-s3.cpp](files/aws-s3.cpp) uses the generated `soapAmazonS3SoapBindingProxy.h` and namespace mapping table: #include "soapAmazonS3SoapBindingProxy.h" #include "AmazonS3SoapBinding.nsmap" We add a convenient template function to allocate primitive values on the managed heap using `soap_malloc()` with context `soap`. While all struct and class objects can be allocated with auto-generated `soap_new_T` functions in C++, primitive values do not have such an auto-generated allocation function and we will use malloc-like allocation on the managed heap: // Make allocation and assignment of primitive values quick and easy: template<class T> T * soap_make(struct soap *soap, T val = T()) { T *p = (T*)soap_malloc(soap, sizeof(T)); *p = val; return p; } This template simplifies coding to allocate and assign a value to a primitive type pointer, for example to assign a primitive value to a pointer member as shown further below. Similarly, to allocate and set a `std::string` value: // Make allocation and assignment of std::string quick and easy: std::string * soap_make_string(struct soap *soap, const char *s = "") { std::string *p = soap_new_std__string(soap); *p = s; return p; } The main program instantiates a proxy to invoke the AWS S3 API and populates the argument `arg` of the `ListAllMyBuckets` service operation method by using the template we created above and the auto-generated allocation functions: int main(int argc, char **argv) { // Create a proxy to invoke AWS S3 services AmazonS3SoapBindingProxy aws(SOAP_XML_INDENT); // Set the argument of the ListAllMyBuckets service operation _s3__ListAllMyBuckets arg; arg.AWSAccessKeyId = soap_make_string(aws.soap, argc > 1 ? argv[1] : "..."); // use your access key arg.Timestamp = soap_make(aws.soap, time(0)); arg.Signature = soap_make_string(aws.soap, argc > 2 ? argv[2] : "..."); // use your signature // Store the result of the service _s3__ListAllMyBucketsResponse response; // Get list of my buckets if (aws.ListAllMyBuckets(&arg, response)) aws.soap_stream_fault(std::cerr); else if (response.ListAllMyBucketsResponse) { s3__ListAllMyBucketsResult &result = *response.ListAllMyBucketsResponse; s3__CanonicalUser *owner = result.Owner; if (owner) std::cout << "ID = " << owner->ID << std::endl; if (owner && owner->DisplayName) std::cout << "DisplayName = " << *owner->DisplayName << std::endl; s3__ListAllMyBucketsList *buckets = result.Buckets; if (buckets) { for (std::vector<s3__ListAllMyBucketsEntry*>::const_iterator it = buckets->Bucket.begin(); it != buckets->Bucket.end(); ++it) { s3__ListAllMyBucketsEntry *entry = *it; if (entry) std::cout << "Name = " << entry->Name << " created " << soap_dateTime2s(aws.soap, entry->CreationDate) << std::endl; } } } // Delete all managed data aws.destroy(); return 0; } As you can see, the proxy has an internal managing context `aws.soap` that we conveniently used to allocate managed data such as `std::string` with `soap_new_std__string(aws.soap)`. After the service invocation with `aws.ListAllMyBuckets` the result is displayed if the request was successful. This example demonstrates one API operation only. To add more service invocations, see the [AWS S3 SOAP API report](examples/aws/index.html) that was generated with soapcpp2 option `-r` for the `aws-s3.h` interface file. To compile the code from the command line we must use OpenSSL because the AWS S3 service requires HTTPS to ensure that the credentials are securely transmitted: [command] c++ -DWITH_OPENSSL -o aws-s3 aws-s3.cpp soapAmazonS3SoapBindingProxy.cpp \ soapC.cpp stdsoap2.cpp -lssl -lcrypto For client-side connection timeouts, please see the example [client](#client-cpp) above. To learn more about memory management in gSOAP, see [memory management.](doc/databinding/html/index.html#memory) [![To top](images/go-up.png) To top](tutorials.html) Example GitHub JSON API v3 client (C++) {#git} --- This example uses the [GitHub API v3](http://developer.github.com/v3) for JSON. The gSOAP toolkit also offers a comprehensive [XML-RPC and JSON/JSONPath](doc/xml-rpc-json/html/index.html) API for C and C++. This includes a new code generator **jsoncpp** (gSOAP 2.8.26 and later) to generate JSON and JSONPath code for your projects. To start from scratch, create a project directory and copy the gSOAP JSON API and XML-RPC API files to your project, together with the gSOAP engine source code (or link with libgsoapssl++.a): [command] cp gsoap/samples/xml-rpc-json/json.h . cp gsoap/samples/xml-rpc-json/json.cpp . cp gsoap/samples/xml-rpc-json/xml-rpc.h . cp gsoap/samples/xml-rpc-json/xml-rpc-iters.h . cp gsoap/samples/xml-rpc-json/xml-rpc.cpp . cp gsoap/stdsoap2.h . cp gsoap/stdsoap2.cpp . Then generate the C++ XML-RPC data binding implementation code, which is also used by the JSON API (e.g. for memory management and other functions): [command] soapcpp2 -CSL xml-rpc.h This generates soapStub.h, soapH.h, and soapC.cpp. Alternatively, you can put the gSOAP JSON API files and functions in a C++ namespace as discussed [here](doc/xml-rpc-json/html/index.html#json-cc). The client application makes a JSON REST call (HTTP POST) to retrieve GitHub repository information as follows: #include "json.h" struct Namespace namespaces[] = { {NULL, NULL} }; // no XML namespaces needed int main(int argc, char **argv) { if (argc >= 2) { // new context with JSON indentation formatting (same as XML indent) soap *ctx = soap_new1(SOAP_C_UTFSTRING | SOAP_XML_INDENT); // create a value for the GitHub API response value response(ctx); // private repos require authentication (should check that we use HTTPS!) if (argc > 3) { ctx->userid = argv[2]; ctx->passwd = argv[3]; } // JSON REST call and show response if OK (returns SOAP_OK (0) or error code) if (json_call(ctx, argv[1], NULL, &response)) soap_stream_fault(ctx, std::cerr); else std::cout << response; std::cout << "\n\nOK\n"; soap_destroy(ctx); // delete managed objects soap_end(ctx); // delete managed data soap_free(ctx); // delete context } return 0; } To compile the GitHub API client from the command line: [command] c++ -DWITH_OPENSSL -DWITH_GZIP -o json-GitHub json-GitHub.cpp \ xml-rpc.cpp json.cpp stdsoap2.cpp soapC.cpp -lcrypto -lssl -lz Let's it out: [command] ./json-GitHub https://api.github.com/orgs/Genivia/repos For client-side connection timeouts, please see the example [client](#client-cpp) above. To learn more about the gSOAP JSON API for C and C++, see the [tutorials](tutorials.html) and [XML-RPC and JSON/JSONPath](doc/xml-rpc-json/html/index.html) documentation. [![To top](images/go-up.png) To top](dev.html)