Resources and FAQ

How to report bugs and patches and get help --- ### Commercial edition users You are entitled to our timely expert professional support. Please [contact us](contact.html) for more details. ### Open source users Report bugs and submit patches by visiting the [SourceForge gSOAP issue tracker.](http://sourceforge.net/p/gsoap2/bugs/) We monitor these trackers and you can receive status updates as the issues are addressed over time. What is the history of gSOAP? --- The gSOAP toolkit was first introduced in 1999 as a research project at the Florida State University for generic XML communications by establishing a type-safe data binding between XML schema types and C/C++ data types through automatic programming. A domain-specific C compiler tool was developed to generate source code that efficiently converts native C data structures to XML and back. The toolkit was further developed to support the SOAP web services messaging protocol, introduced at around the same time, hence the name "gSOAP" (generic XML and SOAP). Further development took place under ownership of Genivia Incorporated, which included the addition of new WSDL and XML schema processing capabilities in 2003 as well as the addition of WS-* Web services protocol capabilities, XML-RPC messaging, JSON, a stand-alone web server, and much more. See also [gSOAP on Wikipedia.](http://en.wikipedia.org/wiki/GSOAP) Where can I find the fact sheet and gSOAP documentation? --- The [gSOAP toolkit fact sheet.](factsheet.pdf) Read the [gSOAP documentation.](docs.html) Which software license is applicable when I use gSOAP? --- Genivia is pleased to offer the gSOAP software with the GNU GPLv2 license. A commercial end-user license agreement is available from Genivia upon request. The commercial end-user license agreement is a royalty-free software development license for the gSOAP toolkit with limited warranties and optional professional technical support and maintenance. Please note that the terms and conditions required by the GNU GPLv2 license of the **open source version of gSOAP** (available from SourceForge etc.) may not be compatible with your commercial end product's licensing and use. The GPLv2 open source license permits selling copies of your end product commercially developed with gSOAP **but only under the terms of the GNU GPLv2**. This means that you must make the source code of your end product available and you permit users to redistribute and modify the end product source code as described in the GPLv2. These requirements are the condition for including the GPL-covered code you received in a program of your own. The GPL v2 requirements may hamper certain proprietary software development scenarios. If you do not wish for your program to be released under the GPL (or under a GPL-compatible open source license), then contact Genivia to inquire about commercial licensing. Genivia offers a **commercial version of gSOAP with a commercial end-user license agreement (EULA)** that removes the GNU GPLv2 requirements, so that your end products will always remain closed. Please [contact Genivia](contact.html) for more details. Notes: 1. Genivia owns the copyright of its software and does not accept or include any third-party GPL code that is incompatible with its proprietary (closed source) licensing terms. 2. The gSOAP public license (derived from the MPL1.1 license) only covers the gSOAP runtime engine, the engine plug-ins, and the Apache and IIS modules. 3. The GNU Bison and Flex tools are used to generate source code for the soapcpp2 tool. The Bison/Flex-generated source code is not restricted by the GPL or LGPL terms. 4. Non-GPL third-party contributions are included in the `gsoap/extras` directory in the package and you are always free to use these contributions. Where can I find commercial licensing and software support for gSOAP? --- Please [contact us](contact.html) for licensing and support inquiries. Why should I use gSOAP? --- ### Comprehensive XML data binding The gSOAP toolkit offers [XML data binding tools](doc/databinding/html/index.html) for C and C++. The tools allow developers to write clean and type-safe code to manipulate large and complex XML-sourced data sets. You can serialize your C/C++ data in XML trees and **(cyclic) C/C++ structure-preserving** XML id-ref graphs. To understand what makes gSOAP tick, please see our [introduction to XML data bindings.](#bindings) ### Portable The toolkit generates portable C and C++ source code for C90 and up (C++11 etc.). The software runs on a wide range of OS platforms, including Windows Win32/Win64 (XP, Vista, Windows 7/8/10), MS-DOS, Cygwin, MinGW, Linux (RedHat, SuSE, etc.), 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. See also our [gSOAP fact sheet.](factsheet.pdf) ### Fast The toolkit generates efficient code to implement low-overhead Web services and fast client proxies. The serializers push and retrieve XML directly to and from sockets without the overhead of HTTP and XML stacks. ### Standardized The 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.](doc/xml-rpc-json/html/index.html) ### Interoperable Applications developed with gSOAP interoperate with other SOAP and RESTful XML stacks such as .NET WCF, Axis, PHP5, SOAP::Lite, SOAP4R, Weblogic, ZSI and many others. Further, XML data binding enables interoperable XML data processing in non-SOAP/REST environments. ### Widely deployable Services developed with gSOAP can be deployed with CGI/FastCGI and with the built-in fast HTTP/S stack. We recommend to use our [Apache](doc/apache/html/index.html) and [IIS](doc/isapi/html/index.html) modules for production-quality service deployment. ### Legacy reusable The toolkit can be leveraged for SaaS deployment of legacy C and C++ systems. All of the necessary gluing code and WSDL service descriptions are auto-generated. ### Stable The software is stable and mature, and is used for several years by companies world-wide to develop software products and services. Companies include the top 15 technology companies and most of the Fortune 500. ### Licensing [Contact Genivia](contact.html) to obtain commercial-use licenses. Otherwise, open source GPLv2 licensing is applicable to your project. For details, [please read this.](products.html#gsoap) Where can I find public forums to discuss gSOAP? --- Visit the active public [gSOAP forum at Yahoo! groups.](http://groups.yahoo.com/neo/groups/gsoap/info) Visit [Stackoverflow gSOAP tagged questions and answers.](http://stackoverflow.com/questions/tagged/gsoap) Where can I find examples of gSOAP? --- See [getting started](dev.html) to begin using gSOAP and see the [examples.](examples/calc/index.html) See our [tutorial.](tutorial.html) Many examples are included in the gSOAP package in `gsoap/samples`. Where can I find and cite technical articles about gSOAP? --- **We recommend citing the following paper(s) when referencing technical papers on gSOAP:** *[The gSOAP Toolkit for Web Services and Peer-To-Peer Computing Networks](http://www.cs.fsu.edu/~engelen/ccgrid.pdf)* by Robert A. van Engelen and Kyle Gallivan, in the proceedings of the 2nd IEEE International Symposium on Cluster Computing and the Grid (CCGrid 2002), pages 128-135, May 21-24, 2002, Berlin, Germany. *[A Framework for Service-Oriented Computing with C and C++ Web Service Components](http://portal.acm.org/citation.cfm?id=1361188)* by Robert van Engelen, ACM Transactions on Internet Technologies, Volume 8, Issue 3, Article 12, May 2008. *[Developing Web Services for C and C++](http://doi.ieeecomputersociety.org/10.1109/MIC.2003.1189189)* by Robert van Engelen, Gunjan Gupta, and Saurabh Pant, in IEEE Internet Computing Journal, March, 2003, pages 53-61. *[Pushing the SOAP Envelope with Web Services for Scientific Computing](http://www.cs.fsu.edu/~engelen/icws03.pdf)* by Robert van Engelen, in the proceedings of the International Conference on Web Services (ICWS), 2003, pages 346-354. **Other related technical papers:** *An Overview and Evaluation of Web Services Security Performance Optimizations* by Robert van Engelen and Wei Zhang, in the proceedings of the IEEE International Conference on Web Services (ICWS), 2008, pages 137-144. *High-Performance XML Parsing and Validation with Permutation Phrase Grammar Parsers* by Wei Zhang and Robert van Engelen, in the proceedings of the IEEE International Conference on Web Services (ICWS), 2008, pages 286-294. *Identifying Opportunities for Web Services Security Performance Optimizations* by Robert A. van Engelen and Wei Zhang, in the proceedings of the IEEE Congress on Services (SERVICES), 2008. *[The GSI plug-in for gSOAP: building cross-grid interoperable secure grid services](http://www.springerlink.com/content/2598221j5k353h62/)* by M. Cafaro, D. Lezzi, S. Fiore, G. Aloisio, and R. van Engelen, in the proceedings of the International Conference on Parallel Processing and Applied Mathematics (PPAM) 2007, workshop on Models, Algorithms and Methodologies for Grid-enabled Computing Environment (MAMGCE), Springer Verlag LNCS Volume 4967, pages 894-901, 2008. *[Toward Remote Object Coherence with Compiled Object Serialization for Distributed Computing with XML Web Services](http://www.cs.fsu.edu/~engelen/cpcpaper06.pdf)* by Robert van Engelen, Wei Zhang, and Madhusudhan Govindaraju, in the proceedings of Compilers for Parallel Computing (CPC), 2006, pages 441-455. *Benchmarking XML Processors for Applications in Grid Web Services* by M. Head, M. Govindaraju , R. van Engelen, and W. Zhang, in the proceedings of Supercomputing 2006. *[A Table-Driven XML Streaming Methodology for High-Performance Web Services](http://www.cs.fsu.edu/~engelen/icws2006tdx.pdf)* by Wei Zhang and Robert van Engelen, in the proceedings of IEEE International Conference on Web Services (ICWS), 2006, pages 197-206. *TDX: a High-Performance Table-Driven XML Parser* by Wei Zhang and Robert van Engelen, in the proceedings of the ACM SouthEast conference, 2006, pages 726-731. *[Exploring Remote Object Coherence in XML Web Services](http://www.cs.fsu.edu/~engelen/icws2006coh.pdf)* by Robert van Engelen, Madhusudhan Govindaraju, and Wei Zhang, in proceedings of IEEE International Conference on Web Services (ICWS), 2006, pages 249-256. *The GSI plug-in for gSOAP: Enhanced Security, Performance, and Reliability* by Giovanni Aloisio, Massimo Cafaro, Italo Epicoco, Daniele Lezzi, and Robert van Engelen, in the ITCC conference 2005, IEEE Press, Volume I, pages 304-309. *[Benchmark Suite for SOAP-based Communication in Grid Web Services](SACpaper.pdf)* by Michael R. Head, Madhusudhan Govindaraju, Aleksander Slominski, Pu Liu, Nayef Abu-Ghazaleh, Robert van Engelen, Kenneth Chiu, Michael J. Lewis, in the proceedings of ACM/IEEE Supercomputing (SC), 2005. *[Constructing Finite State Automata for High Performance XML Web Services](http://www.cs.fsu.edu/~engelen/ISWSpaper.pdf)* by Robert van Engelen, in the proceedings of the International Symposium on Web Services (ISWS), 2004, pages 975-981. *[Code Generation Techniques for Developing Web Services for Embedded Devices](http://www.cs.fsu.edu/~engelen/SACpaper.pdf)* by Robert van Engelen, in the proceedings of the 9th ACM Symposium on Applied Computing SAC, Nicosia, Cyprus, 2004, pages 854-861. *Toward Characterizing the Performance of SOAP Toolkits* by M. Govindaraju, A. Slominski, K. Chiu, P. Liu, R. van Engelen, and M. Lewis, in the proceedings of the 5th IEEE/ACM International Workshop on Grid Computing, pages 365-372, Pittsburgh, USA, 2004. *Secure Web Services with Globus GSI and gSOAP* by Giovanni Aloisio, Massimo Cafaro, Daniele Lezzi, and Robert van Engelen, in the proceedings of EUROPAR 2003. Where can I find an introduction to SOAP, WSDL and XML? --- The gSOAP toolkit automates most of the WSDL and SOAP/XML processing, but it is strongly recommended that users should have a basic understanding of these protocols to get started. A fairly basic [tutorial on WSDL](http://www.w3schools.com/webservices/ws_wsdl_intro.asp) (Web Services Description Language). A fairly basic [tutorial on SOAP](http://www.w3schools.com/webservices/ws_soap_intro.asp) (Simple Object Access Protocol or Services Oriented Access Protocol). Both WSDL and SOAP require an understanding of the XML syntax of elements and attributes, XML namespaces, XML schemas (XSD) and their role in XML validation. Also, WSDL and SOAP define and require XML schemas and XML namespaces. See the [XML tutorial.](http://www.w3schools.com/xml) Here are the links to the latest W3C recommended standards: [WSDL 1.1](http://www.w3.org/TR/wsdl) [WSDL 2.0](http://www.w3.org/TR/wsdl20/) [SOAP 1.1/1.2](http://www.w3.org/TR/soap/) I have been told that SOAP is too big and too complex, so should I use REST instead? --- First of all, SOAP is basically an envelope with an XML header and an XML body which does not add a lot of complexity. The envelope adds about 100 to 300 bytes to a message. The overhead is insignificant in practice. Second, a SOAP message is essentially XML. You have the benefit of strict validation of messages that use SOAP document/literal style. The other style, SOAP encoding instead of literal, supports accurate serialization of data in XML, including cyclic graphs using id-ref attributes that tag "XML objects as pointers". Third, SOAP does not require connection- or transport-level information embedded in HTTP URLs (as with REST) to invoke services because it is self contained. Fourth, SOAP has become a native communication protocol to many development platforms. Most SOAP toolkits have stablized along with the protocol. The claim that SOAP is for "big web services" misses the point that size is not a key factor in deciding on communication protocols, but how interoperable the protocol is and whether the protocol adheres to common standards for message exchange. These are key factors that gives us the assurance that the implementation is reliable and largely maintenance free due to the availability of stable libraries that only require a few lines of code to exchange data with "big" SOAP/XML web services. Also, the rate of development cost tends to rise faster as the size of the code base grows; longer development cycles have shown to correlate with a higher, non-linear growth in bug rates. Working with schema-based data structures such as XML offers a huge advantage in this context. Schemas provide type safety by content validation rules. XML data binding tools translate this safety to strongly typed code to manipulate XML-sourced data. In contrast, exchanging non-validated XML and JSON over open networks is vulnerable to security exploits. Non-validating SAX, DOM, or JSON libraries also require substantially more application logic, resulting in prolonged development and testing cycles. Most implementations communicate SOAP over HTTP with POST and GET anyway, similar to RESTful XML but with self-contained messages. The important difference to REST is that the SOAP protocol is stable, adheres to industry standards, and has many useful extensions such as MIME attachments, WS-Addressing, WS-Security, and WS-ReliableMessaging. The gSOAP toolkit supports both SOAP and RESTful XML messaging with its built-in XML data binding to process XML generally. How do I use gSOAP to develop a client for a WCF service? -- First, there are no assumptions on how the WCF service was developed. The general steps to develop a WCF service in C# are as follows. In addition, the gSOAP distribution package includes WCF examples in `gsoap/samples/wcf`. We will first discuss how a WCF service is created and then explain the steps to develop a gSOAP client for the service. It is also possible to create a gSOAP service and develop a WCF client for this service. ### Creating a WCF Service To create a new WCF service, open VS in administrator mode and create a WCF Service Application project. VS will automatically generate an interface file `IService1.cs`, a service class file `Service1.svc.cs`, a configuration file `Web.config` and some other related files. Add the *System.ServiceModel* reference by right clicking *Reference* of the project. Then add *using System.ServiceModel;* in the code file. The interface `IService1.cs` defines the interfaces of the functions provided by the service. For example: namespace WCF_sample_dataquery { [ServiceContract(Namespace = "http://WCF_sample_dataquery")] // Makes the interface become public in WCF service public interface IDataQueryService { [OperationContract] // Makes the function SearchByAmount the public member of the public interface in WCF service List<Product> SearchByAmount(int amount); [OperationContract] List<Product> SearchByOrigin(string origin); //... } } The service class `Service1.svc.cs` implements the interfaces defined in `IService1.cs`. For example: namespace WCF_sample_dataquery { public class DataQueryService : IDataQueryService // Implement IDataQueryService interface { public List<Product> SearchByAmount(int amount) { //... } public List<Product> SearchByOrigin(string origin) { //... } //... } } In the `Web.config` file set the basic http binding by adding the following content inside `<configuration>` labels. [xml] <system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <protocolMapping> <add binding="basicHttpBinding" scheme="http"/> </protocolMapping> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/> </system.serviceModel> Right-click the project name in *Solution Explorer*. Select *Properties* and modify the *Output* type to *Class Library*. Then build the WCF Service Application project. ### WCF Client for the WCF Service Before we dig into developing a gSOAP client for a WCF service, we will go through the process of creating a WCF client application for the WCF service (the steps are similar when developing a WCF client for a gSOAP service). The following assumes that Visual Studio 2010 or later is used. First, right click on the solution name in *Solution Explorer*. Create a Console Application by selecting *Add* / *Visual C#* / *Console Application*. Then add the service reference: right click *Service References* / *Add Service Reference*. Click the *Discover* button in the *Add Service Reference* window and VS will automatically find the address of the service file. Select *Go* to test the availability of the service file. If this succeeds it will show a message such as *"1 service(s) found at address 'http://localhost:NNNN/Service1.svc'"*. Click *OK* to add the reference. You must rebuild the service after modifying the code and settings it and also update the service reference in the client project. Edit the `Program.cs` file to implement your client-side logic. To start the service and run the client, right-click on the solution name in *Solution Explorer* then click *Properties* and select *Startup Project* in the left side of the pop-up window. Check *Multiple* startup projects. Select both the service and client project action with *Start* and move the service project at the top of the project table. This ensures that the service will be hosted first. Press *F5* or click *Start* to start the WCF service and client. ### gSOAP Client for the WCF Service When the WCF service runs, you can access its WSDL through its endpoint URL using the URL query `?wsdl`. For example, `http://localhost:NNNN/DataQueryService.svc?wsdl`. This WSDL is needed to implement a gSOAP client for the WCF service. We run wsdl2h on this WSDL to generate the C or C++ interface: [command] wsdl2h -o myclient.h http://localhost:NNNN/DataQueryService.svc?wsdl It is highly recommended to change the `ns1`, `ns2`, etc prefixes to something more maintainable for your code. To do so, open the generated `myclient.h` file and look for the *NOTE*. There is a list of prefixes and URIs, for example: ns1 = "http://schemas.microsoft.com/exchange/services/2006/messages" ns2 = "http://schemas.microsoft.com/exchange/services/2006/types" Copy these definitions with your own prefixes to typemap.dat, so that the prefixes are more meaningful and unique for each URI, such as: [command] ewsmsg = "http://schemas.microsoft.com/exchange/services/2006/messages" ewstyp = "http://schemas.microsoft.com/exchange/services/2006/types" Then rerun wsdl2h with the modified typemap.dat located in your local directory. If the modified typemap.dat is not in your local directory then use wsdl2h option `-t/path/to/gsoap/typemap.dat`. Run soapcpp2 to generate the data binding implementation and the C++ proxy class to access the WCF service: [command] soapcpp2 -j -CL -I/path/to/gsoap/import service.h See the list of source code files generated when running soapcpp2, which includes a .h and .cpp file with the proxy class. Use the generated proxy class in your main program. The proxy class .h file has more details. Also, you can use soapcpp2 option `-R` to generate a report with more information. If the WCF service returns an error [command] HTTP/1.1 415 Cannot process the message because the content type 'application/soap+xml; charset=utf-8; then please see the recommendations below to correct this problem. There is a problem with my gSOAP client connecting to a WCF service, which returns an HTTP error --- If the service returns the following error to your client: [command] HTTP/1.1 415 Cannot process the message because the content type 'application/soap+xml; charset=utf-8; then the gSOAP client uses SOAP 1.2 messaging when the service expects SOAP 1.1 which uses HTTP content type `text/xml`. SOAP 1.2 uses HTTP content type `application/soap+xml`. You can display these errors after making a failed call with `soap_print_fault(soap, stderr)` or `soap_stream_fault(soap, std::cerr)`. To resolve this problem, remove the line `#import "soap12.h"` from the interface header file generated by wsdl2h. You can also use soapcpp2 option `-1` to force SOAP 1.1 messaging: [command] soapcpp2 -1 -j -CL -I/path/to/gsoap/import service.h This generates a .nsmap file with updated SOAP protocol namespaces: {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL}, {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, So make sure to `#include` this nsmap file in your code in order to use the SOAP 1.1 namespace by default. The gSOAP engine accepts both SOAP 1.1 and SOAP 1.2 messages, which is the reason for the second namespace URI pattern in the nsmap that corresponds to SOAP 1.2 (or other versions). If the service returns a different HTTP error then you may want to check the endpoint URL of the service that you are connecting to and the SOAP action string (if any). These string can be provided with the client-side call: if (soap_call_ns__method(soap, "endpoint URL", "SOAP Action", ...) != SOAP_OK) soap_print_fault(soap, stderr); // error The endpoint URL string is an optional string to construct a proxy object and can also be passed to proxy methods: Proxy proxy("endpoint URL"); ... if (proxy.method("endpoint URL", "SOAP Action", ...) != SOAP_OK) proxy.soap_stream_fault(std::cerr); // error If the service returns an "HTTP 401 Unauthorized" error or "HTTP 407 Proxy Authentication Required" error, then use Basic or Digest authentication. For example, to enable HTTP Basic authentication (this MUST only be used over HTTPS to be safe!): soap.userid = "Zaphod"; soap.passwd = "Beeblebrox"; if (soap_call_ns__method(&soap, ...)) // call with basic auth credentials soap_print_fault(&soap, stderr); // error For proxy authentication you should set these: soap.proxy_userid = "Zaphod"; soap.proxy_passwd = "Beeblebrox"; HTTP Digest authentication requires setting up a credentials store, please see the [HTTP DA plugin](doc/httpda/html/httpda.html) for details. You can use NTLM authentication with Microsoft services by compiling your code and stdsoap2.cpp with `-DWITH_NTLM` to enable NTLM. Also link with the [libntlm](http://www.nongnu.org/libntlm) library. To use NTLM authentication: soap_call_ns__method(&soap, ...) != SOAP_OK) // try calling without credentials { if (soap.error == 401) // must authenticate { soap.userid = "Zaphod"; soap.passwd = "Beeblebrox"; soap.authrealm = "Ursa-Minor"; if (soap_call_ns__method(&soap, ...) != SOAP_OK) // call with credentials soap_print_fault(&soap, stderr); // error } } The first step of this two-step authentication process can be eliminated as follows: soap.userid = "Zaphod"; soap.passwd = "Beeblebrox"; soap.authrealm = "Ursa-Minor"; soap.ntlm_challenge = ""; // enable NTLM authentication if (soap_call_ns__method(&soap, ...) != SOAP_OK) // call with credentials soap_print_fault(&soap, stderr); // error Where can I find a good description of the Apache module, ISAPI extension, and WinInet plugin for gSOAP? --- See [Apache Module](doc/apache/html/index.html) for gSOAP in our Development Center. See [ISAPI Extension](doc/isapi/html/index.html) for gSOAP in our Development Center. See [WinInet Plugin](doc/wininet/html/index.html) for gSOAP in our Development Center. How do I increase the speed of XML processing and serialization? --- The default settings of the gSOAP runtime engine maximize portability and compatibility. The settings can be tweaked to optimize the performance as follows: Tweak the buffer size `SOAP_BUFLEN` by changing the `SOAP_BUFLEN` macro in `stdsoap2.h` (and compile your project with `stdsoap2.c` and `stdsoap2.cpp`, **DO NOT USE** `libgsoapXX.a` with the old buffer size). Test with buffer sizes 32768, 65536, 131072 for example. Use HTTP keep-alive `SOAP_IO_KEEPALIVE` at the client-side 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. Use HTTP chunked transfer `SOAP_IO_CHUNKED`. Do NOT use gzip compression, since the overhead of compression is typically higher than the bandwidth gains. Set the `SOAP_XML_TREE` flag to disable id-ref multi-ref object (de)serialization. This boosts performance significantly and works with SOAP document/literal style (i.e. no id-ref graph serialization). This flag is **not compatible with SOAP encoded style** that requires id-ref object serialization. Compile `stdsoap2.c` and `stdsoap2.cpp` with `-DWITH_NOIDREF` to improve performance by permanently disabling id-ref multi-ref object (de)serialization. Again, **this is not compatible with SOAP encoded style** that requires id-ref object serialization. Do NOT use DEBUG mode, since the overhead of logging is significant. I cannot deserialize polymorphic objects in my C-based service, but in C++ it works fine? --- Services developed in C++ with gSOAP support full polymorphism, including xsd:anyType. However, the C language limitations make it more difficult to map schema complexType extensions to the limited C types. In order to support polymorphism in C, we suggest to use advanced features such as the `int __type; void*` construct to serialize a pointer to an object of type X. This is done in your application code by setting `__type = SOAP_TYPE_X` and the `void*` pointer to the object (see documentation). Obviously, the deserializer automatially sets `__type` and `void*` according to the XML content and its `xsi:type` value which is required. When `xsi:type` values are not provided, such as for the base case of an XSD extension/restriction, you should match the content according to the element tag name by defining a type (struct or typedef) with the element name. See gSOAP documentation Section "Customizing Data Bindings With The typemap.dat File". Use the typemap.dat file for wsdl2h to automatically replace all occurences of a polymorphic type. I get a No deserializer found to deserialize error from an Axis server. What is the problem? --- Some toolkits, including Axis, require `xsi:type` attributes for each accessor for messages using the SOAP RPC encoding style. Use soapcpp2 option `-t` to automatically re-generate serialization code to produce typed messages. I suspect that gSOAP has a memory leak, because no memory is released? --- The gSOAP engine uses a memory management method to allocate and deallocate memory. The deallocation is performed with `soap_destroy()` followed by `soap_end()`. However, when you compile with `-DDEBUG` or `-DSOAP_MEM_DEBUG` then no memory is released until `soap_done()` is invoked. This ensures that the gSOAP engine can track all malloced data to verify leaks and double frees in debug mode. Use `-DSOAP_DEBUG` to use the normal debugging facilities without memory debugging. Note that some compilers have DEBUG enabled in the debug configuration, so this behavior should be expected unless you compile in release config. What is the data corruption in dynamic allocation error? --- When your application uses `soap_malloc()` to allocate a (temporary) chunk of data and the allocated size is exceeded, the gSOAP engine will detect this buffer overrun in `-DDEBUG` compiled mode. Check your code and/or enlarge the allocated buffer. The compiler produces an error for empty structs and classes that are present in the generated code. What should I do? --- Use `-DWITH_NOEMPTYSTRUCT` as a C/C++ compiler option to add dummy members automatically to the generated code (gSOAP version 2.7.9g or higher). I downloaded a new release, but now I get GSOAP VERSION MISMATCH IN LIBRARY: PLEASE REINSTALL PACKAGE? --- This error is caused by mixing old with new gSOAP versions of the generated code and gSOAP libraries. Make sure to include the latest `stdsoap2.h` and link with the latest `libgsoapXX.a` libraries (or use the `stdsoap2.c` or `stdsoap2.cpp` source code). I downloaded a new release, but now I get a link error for XXX_REQUIRE_lib_vYYY? --- See the item above. I get macro redefinition errors on my Windows platform, what should I do? --- When you get macro redefinitions, such as [command] warning C4005: 'AF_IPX' : macro redefinition then try arrange your include list such that `windows.h` is included after `stdsoap2.h`. Or define `_WINSOCKAPI_` first: #define _WINSOCKAPI_ // stops windows.h including winsock.h #include <windows.h> ... #include "soapH.h" // also includes "stdsoap2.h" The `stdsoap2.h` code includes `winsock2.h`, which clashes with `winsock.h` included by `windows.h`. Similar problems may occur when `stdafx.h` is included. If all else fails, revert back to older `winsock.h` by changing `stdsoap2.h`: #include <winsock.h> // was: <winsock2.h> How do I install gSOAP on HP-UX? --- If the configuration with `./configure` and installation with `make` fails, then please follow these recommendations. Install GNU m4 from [www.gnu.org/software/m4](http://www.gnu.org/software/m4) Install Flex from [flex.sourceforge.net](http://flex.sourceforge.net) If HTTP compression is required, then install zlib from [www.zlib.net](http://www.zlib.net) and make sure that `libz` is installed on a library path accessible to the compiler. If HTTPS and SSL for WS-Security are required, then install OpenSSL. When OpenSSL is NOT installed in the above steps, execute in the root dir of the gsoap package: [command] ./configure --disable-openssl With OpenSSL installed on your system, execute: [command] ./configure Edit `config.h`: set HAVE_REALLOC 1 /* #define realloc rpl_realloc commented out */ Also make sure that in `config.h` we have: #define HAVE_STRTOLL 0 #define HAVE_STRTOULL 0 Then execute: [command] make If there are errors when building the tests, then ignore these for now. Edit the Makefile to make sure that: LEXLIB = /usr/local/lib/libfl.a Then rebuild with: [command] make If there is a problem building wsdl2h, do this: [command] cd ../wsdl And edit the `Makefile` there: wsdl2h_DEPENDENCIES = wsdlC.cpp $(top_builddir)/gsoap/stdsoap2.cpp AM_LDFLAGS = $(INCLUDES) -DWITH_OPENSSL -L$(srcdir) SOAP_CCP_LIB_SSL = $(top_builddir)/gsoap/stdsoap2.cpp Then execute: [command] make cd ../.. make install-exec Now we have soapcpp2 and wsdl2h built and installed. Execute: [command] make install If all else fails, you can build the soapcpp2 and wsdl2h tools using the supplied `MakefileManual` files in the source directories. Before doing so, remove the old package and unpack again to start fresh. Then execute: [command] cd gsoap/src make -f MakefileManual soapcpp2 cd gsoap/wsdl make -f MakefileManual In your projects use `gsoap/stdsoap2.h` and `gsoap/stdsoap2.c` (or `gsoap/stdsoap2.cpp` for C++) directly instead of the `libgsoapXX.a` libraries (which are built from `stdsoap2.c` and `stdsoap2.cpp`). If `stdsoap2.c` or `stdsoap2.cpp` do not compile, modify `stdsoap2.h` for portability. For example, if `socklen_t` is not defined, change it to an `int` as in: #elif defined(__socklen_t_defined) || defined(_SOCKLEN_T) || defined(CYGWIN) \ || defined(FREEBSD) || defined(__FreeBSD__) || defined(OPENBSD) \ || defined(__QNX__) || defined(QNX) || defined(OS390) || defined(HP_UX) # define SOAP_SOCKLEN_T socklen_t To: #elif defined(__socklen_t_defined) || defined(_SOCKLEN_T) || defined(CYGWIN) \ || defined(FREEBSD) || defined(__FreeBSD__) || defined(OPENBSD) \ || defined(__QNX__) || defined(QNX) || defined(OS390) || defined(HP_UX) # define SOAP_SOCKLEN_T int Similar changes may be needed depending on HP-UX system versions. How do I build a universal PPC/Intel binary for MAC OS? --- To build a Mac OS X Universal Binary you have to run: [command] automake --ignore-deps ./configure CFLAGS="-arch ppc -arch i386" LDFLAGS="-arch ppc -arch i386" make clean make make install How do I build the libraries with libtool? --- In `configure.in` change `AC_PROG_RANLIB` to `AC_PROG_LIBTOOL`. In `gsoap/Makefile.am` replace the `.a` and the `_a` respectively by `.la` and `_la` in this file, so that you get: lib_LTLIBRARIES = libgsoap.la libgsoap++.la libgsoapck.la libgsoapck++.la libgsoapssl.la libgsoapssl++.la libgsoap_la_SOURCES = stdsoap2.c libgsoap_la_CFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) libgsoap___la_SOURCES = stdsoap2_cpp.cpp libgsoap___la_CXXFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) libgsoapck_la_SOURCES = stdsoap2_ck.c libgsoapck_la_CFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) -DWITH_COOKIES libgsoapck___la_SOURCES = stdsoap2_ck_cpp.cpp libgsoapck___la_CXXFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) -DWITH_COOKIES libgsoapssl_la_SOURCES = stdsoap2_ssl.c libgsoapssl_la_CFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) -DWITH_OPENSSL -DWITH_DOM -DWITH_GZIP libgsoapssl___la_SOURCES = stdsoap2_ssl_cpp.cpp libgsoapssl___la_CXXFLAGS = $(SOAPCPP2_DEBUG) $(SOAPCPP2_NONAMESPACES) -D$(platform) -DWITH_OPENSSL -DWITH_DOM -DWITH_GZIP After the modifications run [command] autoconf -f -i -v configure make make install Is gSOAP portable to NonStop Tandem? --- Yes. A software bridge for the engine to work on NonStop Tandem is included in the package. All generated code is platform-independent, so the soapcpp2/wsdl2h tools can be used on any platform to produce the client/server interface. Why do I get a Compliance Warning from soapcpp2? --- WS-I Basic Profile compliance warnings are meant to inform you about potential interoperability problems with other SOAP/XML Web services. The [WS-I Basic Profile publication](http://www.ws-i.org/Profiles/BasicProfile-1.0-2004-04-16.html) consists of a set of non-proprietary Web services specifications, along with clarifications and amendments to those specifications which promote interoperability. Compliance warnings for existing services should be ignored, because compliance requires changes to the service WSDL that would break other applications that depend on the service. You may consider these compliance issues for new services however, see the [Basic Compliance Report](http://www.cs.fsu.edu/~engelen/soapBP.html) for gSOAP. What is the difference between qualified element/attribute forms and unqualified forms? --- When a schema defines element forms to be qualified by default (`elementFormDefault="qualified"`), the header file includes a directive //gsoap ns schema elementForm: qualified Likewise, when the default is unqualified, you will find //gsoap ns schema elementForm: unqualified When an element form is qualified by default, elements in XML instances of the schema are required to be namespace qualified. Without going into too much detail, the XML basically looks like: [xml] <x:foo xmlns:x="urn:foobar"> <x:bar>bar is qualified</x:bar> </x:foo> or: [xml] <foo xmlns="urn:foobar"> <bar>bar is qualified</bar> </foo> When the element form is unqualified (as in SOAP RPC encoding), we would have: [xml] <x:foo xmlns:x="urn:foobar"> <bar>bar is unqualified</bar> </x:foo> Note that sometimes we can have multiple namespaces as in: [xml] <x:foo xmlns:x="urn:foo"> <y:bar xmlns:y="urn:bar"></y:bar> </x:foo> or: [xml] <x:foo xmlns:x="urn:foo" xmlns="urn:bar"> <bar></bar> </x:foo> In the last example the bar element belongs to the `urn:bar` namespace, because the default namespace is `urn:bar`. With Visual Studio .NET 2003 WSDL import, we could not successfully deserialize data from a multi-namespace situation when a response element contains an element of struct type in a second namespace. The individual members of the struct were ignored on the .NET side until the element form default 'qualified' was defined. How do I tune TCP/IP TIME_WAIT for systems with high connection rates? --- When a large number of connections in the `TIME_WAIT` state are observed, e.g. using the "netstat" command to monitor open TCP/IP connections, the system exhibits poor throughput possibly coupled with high CPU use or refusal to accept new connections by `soap_accept()`. The `TIME_WAIT` state is used to deal with possible problems related to unreliable or delayed packet delivery. TCP holds connections for a temporary waiting period (`TIME_WAIT`) to ensure that any delayed packets are caught and not treated as new connection requests. The size of `TIME_WAIT` is supposed to be twice the maximum segment lifetime or twice the time a packet can remain alive on a particular IP network. For some operating systems, this can be as high as 4 minutes. On busy systems, this can lead to a depletion of TCP port resources. Low throughput may occur due to many connections sitting in TIME_WAIT state. Set the `soap.accept_flags |= SO_LINGER` and `soap.linger_time = n` with integer `n` before calling `soap_accept()`. This works on most systems, but zapping the `TIME_WAIT` state is not always encouraged! If that does not work, then reduce the operating system setting for `TIME_WAIT` substantially to the operating system minimum of 15 or 30 seconds (depending on OS). For Windows: use regedit and create a `REG_DWORD` named `TcpTimedWaitDelay` under [command] HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TcpIp\Parameters Set it to a decimal value of 30 which is for 30 seconds - the minimum. For AIX: to see the current `TCP_TIMEWAIT` value, run the following command: [command] /usr/sbin/no a | grep tcp_timewait To set the `TCP_TIMEWAIT` values to 15 seconds, run the following command: [command] /usr/sbin/no o tcp_timewait =1 The `tcp_timewait` option is used to configure how long connections are kept in the timewait state. It is given in 15-second intervals, and the default is 1. - For Linux: set the `timeout_timewait` paramater using the following command: [command] /sbin/sysctl -w net.ipv4.vs.timeout_timewait=30 This will set `TME_WAIT` for 30 seconds. - For Solaris: set the `tcp_time_wait_interval` to 30000 milliseconds as follows: [command] /usr/sbin/ndd -set /dev/tcp tcp_time_wait_interval 30000 My gSOAP client receives an ECONNRESET from a server --- Set `soap.accept_flags |= SO_LINGER` and set `soap.linger = n` in the server code before calling `soap_accept()`. This forces the server to block on the close attempt until it is able to transmit the data or until it decides it is unable to deliver the information after a timeout period. The `soap.linger = n` value controls the timout period (the linger time resolution is system-dependent, consult the `setsockopt` manual page. However, according to some experts only zero and nonzero values matter). Why do I get a warning on a parameter with a type that does not correspond to the required unique type? --- SOAP RPC literal encoding requires the operation parameters to be described as top-level Schema elements in WSDL. Therefore, a service operation with parameter `x` of type `X` has an `<element name="x" type="X"/>` definition in the Schema of the service. A parameter `x` of type `Y` cannot be defined, since `x` is already bound to type `X`. If you must use SOAP RPC literal encoding, rename the parameter, e.g. `y` of type `Y`, or define new schema namespaces by qualifying the parameter names, e.g. `arg__x`, `arg__y`, etc. You can use document literal encoding to avoid this problem, or SOAP RPC encoding (not WS Basic Profile compliant). I get a link error in Visual Studio C++. What should I do? --- Visual Studio C++ differs from compilers such as GCC with respect to the C or C++ compilation mode based on file extensions, which means that: For C++ builds: change `.c` into `.cpp` extensions. For C++ builds: do not use soapcpp2 option `-c`. For C++ builds: link your application with `soapC.cpp`, `soapClient.cpp` (or `soapServer.cpp` for services), and `stdsoap2.cpp`. Check the actual-formal parameter passing (`soapStub.h` contains the prototypes of the generated stub functions). You need `winsock.dll` (`wsock32.lib`). To do this in Visual C++ for example, go to "Project", "settings", select the "Link" tab (the project file needs to be selected in the file view) and add "wsock32.lib" to the "Object/library modules" entry. I get a link error when compiling. What should I do? --- For C use soapcpp2 option `-c` to generate C code. Use only the gSOAP package's `.c` files. Link with `libgsoap.a` (`-lgsoap`) or use the lib's source `stdsoap2.c` (and `dom.c` when applicable). For C++ there is no need to change the gSOAP package's `.c` source files to files with `.cpp` extensions, but compilers may warn about deprecated behavior. For example, suppose we have a `myprog.cpp` C++ client that uses the WS-Addressing and WS-ReliableMessaging plugins and the `duration` custom serializer which are all C files: soapcpp2 -a -L -S -I $GSOAPHOME -I $GSOAPHOME/import myprog.h c++ -I $GSOAPHOME -o myprog myprog.cpp plugin/wsaapi.c plugin/wsrmapi.c custom/duration.c soapC.cpp soapClient.cpp -lgsoap++ All plugin sources are located in the `plugin` directory and should be compiled and linked with your C or C++ code. Custom types and serializers are located in the `custom` directory. When a serializer of a custom type is used the source file with the serializer implementation must be compiled and linked as well. The build fails when the Bison tool is invoked and produces a signal 13. What should I do? --- You need to install a newer version of m4 from [GNU m4](http://www.gnu.org/software/m4) and then check again. If the build then fails due to missing `libsigsegv`, install `libsigsegv`. My code segfaults. What should I do? --- First determine if the application crashes in the gSOAP code. Then verify the following: Make sure that the gSOAP run-time environment (struct soap) is initialized by calling `soap_init(&soap)`. A soap struct dynamically allocated with `soap_new()` is already initialized. When working with C++ applications, make sure that you don't include the wsdl2h-generated .h header file directly in your C++ sources. You must use the gSOAP-generated `soapH.h` file instead, which includes the proper class extensions with virtual serialization methods. The soapcpp2 tool adds serializers to classes, so it is important to use the classes redefined in `soapH.h` (via `soapStub.h`). If your project does not allow class redefinitions, use the `volatile` qualifier with your class definition in the `.h` file for soapcpp2. Make sure you don't pass the gSOAP run-time environment (struct soap) by value to your application functions. Always pass struct soap by reference or pointer, just like the internal gSOAP functions do. In case you need to make a copy of it, use `$soap_copy()`. Make sure all pointers that occur in the data structures that are passed as parameters to remote methods are initialized, i.e. pointers should be NULL or point to a valid object. If your application crashes in the serialization code while sending data, it is very likely that the serializer encountered an undefined pointer member in a struct or class to serialize to XML. Make sure the data to be serialized is properly set and contains valid data for all struct/class members (transient members are not serialized and can be undefined). Set struct/class pointer members to NULL when not in use. To ease this burden, use the `soap_default_T()` generated functions for structs `T` and `T::soap_default()` function members of classes. Make sure all class instances that are passed as parameters to remote methods are initialized, i.e. the virtual method tables (VMTs) must be set. Make sure that no two (or more) threads access the same gSOAP run-time environment (struct soap) concurrently, i.e. use separate soap struct run-time environments in threads. Remove all calls to `soap_destroy()` and `soap_end()` and rerun to check if the segfault results from gSOAP's garbage collect cleanup. If the segfault occurs in the `soap_destroy()` cleanup, remove all deallocation calls in the destructors to avoid duplicate deallocations (one by the destructor and one by gSOAP's cleanup). Compensate the elimination of deallocation calls by allocating data solely with `soap_malloc()` and `soap_new_Class()` routines in your code. Alternatively, you can use `soap_unlink(p)` in the class destructors to unlink the data pointed to by `p` from gSOAP's deallocation chain before deallocating it in the class destructor (see the gSOAP documentation on `soap_malloc()`, `soap_new_Class()`, and `soap_unlink()` in class methods). If the segfault occurs in the `soap_end()` cleanup, then it is likely that data is already deallocated with `free()` in your code and deallocated again in `soap_end()`. Use `soap_unlink(p)` to unlink the data pointed to by `p` from gSOAP's deallocation chain before freeing it up. When you use OpenSSL and/or Zlib, please compile **all source files** with `-DWITH_OPENSSL` and/or `-DWITH_GZIP` to ensure that the `struct soap` layout is identical in all places where it is used. If the crash occurs in the deserialzer while reading data, and you declared in the gSOAP specificication header file a SOAP array (or `__ptr` and `__size` pair) of an array of class instances, then it is strongly advised to use pointers to class instances instead using `T **__ptr` to point to an array of pointers to class `T` instances. Otherwise class instances might be copied in memory to collect them into arrays which on some platforms may fail. If your server application crashes after invoking a service operation while returning data to the client, then see the next FAQ item below. How can I allocate temporary data in service operations? --- Avoid returning stack-allocated objects from service operations, which is definitely not safe. To allocate temporary data in service operations, use the functions: void *soap_malloc(struct soap *soap, size_t n); // allocate n bytes ClassX *soap_new_classX(struct soap *soap); // one instance of ClassX ClassX *soap_new_classX(struct soap *soap, size_t n); // an array of n instances of ClassX This allocates memory on the heap that will be released upon calling `soap_destroy()` followed by `soap_end()`, such as after `soap_serve()`: soap_serve(&soap); soap_destroy(&soap); soap_end(&soap); An example service operation that allocates a temporary string: int ns__itoa(struct soap *soap, int i, char **a) { *a = (char*)soap_malloc(soap, 11); sprintf(*a, "%d", i); return SOAP_OK; } Note that you don't want to use local function variables to store values such as strings, because the values are allocated on the stack and deallocated when the function returns while serialization of the values takes place after return. This allocation with `soap_malloc()` can also be used to allocate strings for the SOAP Fault data structure, for example: int ns__mymethod(struct soap *soap, ...) { ... if (exception) { char *message = (char*)soap_malloc(soap, 1024); char *details = (char*)soap_malloc(soap, 1024); sprintf(message, ...); sprintf(details, ...); return soap_receiver_fault(soap, message, details); } ... } The time_t deserialization appears to be incorrect, because the time_t value is off by one or more hours. How can I fix this? --- Some systems do not support `timegm()` to convert time expressed in UCT to `time_t` values. Therefore, the gSOAP kernel uses `gettimeofday()` or `ftime()` with `mktime()` to deserialize `xsd:dateTime` values into `time_t`. As a result, when the timezone on the machine on which gSOAP runs is set incorrectly, this will cause the `time_t` value to be off by one or more hours. Unfortunately, the problem is more difficult with Solaris 8 and earlier Solaris versions, because Solaris does not implement the DST settings of `gettimeofday()` and `ftime()` correctly. My application recieves a Broken Pipe signal. What should I do? --- A "broken pipe" signal SIGPIPE is OS dependent. It is triggered when a peer closes a connection unexpectedly on Linux and Unix variants. When the signal is not caught, the application exits. To prevent this, use one of the following three methods: soap.accept_flags = SO_NOSIGPIPE; /* some systems accept this */ soap.socket_flags = MSG_NOSIGNAL; /* others need this */ signal(SIGPIPE, sigpipe_handler); /* and when the above are not supported, we use a sigpipe handler */ where the `sigpipe_handler` is defined as a no-op function: void sigpipe_handler(int x) { } I get a tag mismatch error and/or data appears to be missing when receiving SOAP/XML messages? --- Check that your gSOAP header file includes `//gsoap` directives to define XML namespaces. These namespace bindings will be added to a `.nsmap` file generated by the gSOAP compiler (or you can write your own `.nsmap` file). The gSOAP header file requires a one-to-one correspondence between namespace prefix and the namespace name. Therefore, a namespace name may not occur more than once in a `//gsoap ... service namespace` directive. My code appears to ignore data when receiving SOAP/XML messages. How can my code detect unrecognized elements at run time? --- The SOAP RPC encoding style allows optional elements to be ignored, even through the XML validator would flag this. As a side effect, a namespace mismatch and/or tag name mismatch will result in dropping the element. If the namespace and/or tag name are defined correctly, data will never be dropped at run time. To assist debugging and to catch dropped elements, set the `soap_set_imode(&soap, SOAP_XML_STRICT)` flag. This will enforce strict validation of messages. Another way to control the dropping of unrecognized elements is to define the `fignore` callback. For example: struct soap soap; soap_init(&soap); soap.fignore = mustmatch; // overwrite default callback ... soap_done(&soap); // reset callbacks ... int mustmatch(struct soap *soap, const char *tag) { return SOAP_TAG_MISMATCH; // every tag must be handled } The tag parameter contains the offending tag name. You can also selectively return a fault: int mustmatch(struct soap *soap, const char *tag) { if (soap_match_tag(soap, tag, "ns:login*")) // all tags in namespace "ns" that start with "login" are optional return SOAP_OK; return SOAP_TAG_MISMATCH; // every other tag must be understood (handled) } SOAP 1.1 allows the return parameter elements of a SOAP response to be anonymous. How can I tell gSOAP to use anonymous return parameter names? --- For gSOAP 2.1.11 and higher, specify the function prototype without parameter names. For earlier gSOAP releases, you can prefix the return parameter names with an underscore (`_`). For example: int ns__mymethod(..., int *_return); // single anonymous output parameter and int ns__mymethod(..., struct ns__mymethodResponse{int _return1; char *_return2; ...} *result); // multiple output paramers How can I tell gSOAP to ignore certain declarations of types in a header file so I can write class methods that use parameters of these types? --- You can provide the type declarations in the header file and use the `extern` qualifier or enclose the type declarations between `[` and `]` to make them "transient", i.e. non-serializable. For example: extern class ostream; // can't be (de)serialized so must be declared a transient type class ns__foo { public: char *s; struct soap *soap; // special field: already transient ns__foo(); [ ns__foo(const char *t); // transient constructor print(ostream &s); // transient method ] }; with e.g. the following implementation of `ns__foo`: ns__foo::ns__foo(const char *t) { s = (char*)soap_malloc(soap, strlen(t)+1); strcpy(s, t); } The `struct soap* soap` field in this class is a special field set by gSOAP's deserializers and the gSOAP-generated `soap_new_ns__foo()` function. How can I tell gSOAP to use primitive XSD schema types or SOAP-ENC schema types? --- Use `typedef` declarations for primitive types in the header file input to the compiler. This is important for SOAP RPC encoding style. For example, to declare a XSD schema string type, declare `typedef char *xsd__string;` and use the `xsd__string` type in remote method parameters and other compound data structures. See the documentation for more details on primitive XSD schema types and the section on doc/literal encoding. The declaration of SOAP-ENC schema types is similar. For example, `typedef char *SOAP_ENC__string` declares a SOAP-ENC:string schema type. How do I debug a gSOAP client? --- Compile `stdsoap2.cpp` (or `stdsoap2.c` for C) with compiler option `-DDEBUG` (`/DSOAP_DEBUG` in MSVC++) to enable logging. When you run your application, three files are created in the current directory: `SENT.log`, `RECV.log`, and `TEST.log`. All output messages are appended to `SENT.log`, all input messages are appended to `RECV.log`, and `TEST.log` contains various logging messages generated by the gSOAP runtime environment. Alternatively, you can use the example plugin code provided in the distribution package in `extras/plugin.h` to develop an application that can selectively log input and output messages. In addition, you can use a simple trick to inspect a client request message by leaving the endpoint URL empty ("" string). This will send the request message to stdout. The client application expect the response to be available from `stdin`. So, unless you provide a response message using redirect e.g. from a file or a service application using Unix pipes, you will have to terminate the client application. How do I debug a Web Service installed as a CGI application? --- First, see the answer above and then install the executable as a CGI application on your Web server. Create three empty files in the same directory: `SENT.log`, `RECV.log`, and `TEST.log`. They should have read and write permissions for "other" (i.e. for everyone). These files will log all accesses to the CGI application. Do not forget to remove them later and turn off debugging. Alternatively, to test the CGI server, create a file with the SOAP request message (for example by using the soapcpp2 auto-generated `.req.xml` messages) and use file redirect to input this message as standard input to the executable, which should display the response message. Does gSOAP support multi-threading and is it MT-safe? --- Yes, gSOAP 2.x is MT-safe and implements multi-threaded clients and servers. There are differences in the API's used in gSOAP 2.x compared to the very old gSOAP 1.X to support multi-threading. Section 3 of the gSOAP 2.x documentation details these differences. I wrote a client and service that exchange strings, but I get garbage or I get only one character communicated and not the entire string? --- Your function prototype is probably similar to `mymethod(char *in, char *out)`. The output parameter "out" is a pointer to a byte instead of a pointer to a string (output parameters must be pointers or references to a type). The correct way to do this is: `mymethod(char *in, char **out)` or `mymethod(char *in, char *&out)`. I wrote a client and service that exchange strings declared as char[N], but I get an array of N bytes in the payload? --- If you use a fixed-size array of chars, the array is (de)marshalled as an array of bytes and not a string. Always use `char*` for strings. Use soapcpp2 option `-b` to support fixed-size string arrays `char[N]`. I wrote a remote method declaration and the compiler gives a syntax error for parameter names that are keywords --- Use one or more trailing underscores in parameter names, type names, struct fields, class members, etc. to avoid name clashes with keywords. The trailing underscores in identifier names are invisible in the SOAP/XML payload. For example `mymethod(int &return_);` declares a remote method with output parameter `return_` which will be (de)serialized in XML as `return`. How do I write a remote method that has no input parameters? --- Just specify one (output) parameter. I have a remote method with a response struct that is also used as a type elsewhere in my header file, but now my WSDL is incomplete because the type is not defined in the WSDL (an element definition appears instead) --- A response struct/class is not a type but a placeholder or wrapper for the result parameters. So you cannot use this struct/class anywhere else in your type definitions, since it will be defined as a schema element rather than a schema type. For example: struct ns__data { ... }; int ns__example(..., struct ns__data *out); where the `ns__data` struct contains the result parameters of the method. The struct is translated into an element definition in the generated WSDL to support doc/lit style messaging. As you can see, this means that `ns__data` cannot be used as a type anywhere else in your header file. To work around this problem, use: struct ns__data { ... }; int ns__example(..., struct ns__exampleResponse { struct ns__data out; } *out); Now we have a type `ns__data` and a response struct for the method results. How do I write a remote method that has no output parameters? --- Specify an empty struct output parameter. For example: `ns__myMethod(..., struct ns__myMethodResponse { } &response)`. How can I use (wide character) strings for doc/literal encoding to (de)serialize any form of XML? --- Use the built-in `_XML` char-based string type or declare your own: typedef char *XML; // in C typedef std::string XML; // or in C++ or as wide strings: typedef wchar_t *XML; // in C typedef std::wstring XML; // or in C++ and use this `XML` type for mixed-content strings (strings that contain XML). How do I add SOAP Headers to my messages? --- Set the `soap.header` field of the runtime environment variable (soap struct) to point to a `struct SOAP_ENV__Header` structure: if (soap.header == NULL) { soap.header = soap_malloc(&soap, sizeof(struct SOAP_ENV__Header)); soap_default_SOAP_ENV__Header(&soap, soap.header) } The exact same can be accomplished with: soap_header(&soap); How do I use gSOAP with the ONVIF specifications? --- Use gSOAP 2.8.10 or greater. In the typemap.dat file that is used by wsdl2h, add the following if not already there: [command] # ONVIF recommended prefixes tds = "http://www.onvif.org/ver10/device/wsdl" tev = "http://www.onvif.org/ver10/events/wsdl" tls = "http://www.onvif.org/ver10/display/wsdl" tmd = "http://www.onvif.org/ver10/deviceIO/wsdl" timg = "http://www.onvif.org/ver20/imaging/wsdl" trt = "http://www.onvif.org/ver10/media/wsdl" tptz = "http://www.onvif.org/ver20/ptz/wsdl" trv = "http://www.onvif.org/ver10/receiver/wsdl" trc = "http://www.onvif.org/ver10/recording/wsdl" tse = "http://www.onvif.org/ver10/search/wsdl" trp = "http://www.onvif.org/ver10/replay/wsdl" tan = "http://www.onvif.org/ver20/analytics/wsdl" tad = "http://www.onvif.org/ver10/analyticsdevice/wsdl" tdn = "http://www.onvif.org/ver10/network/wsdl" tt = "http://www.onvif.org/ver10/schema" # OASIS recommended prefixes wsnt = "http://docs.oasis-open.org/wsn/b-2" wsntw = "http://docs.oasis-open.org/wsn/bw-2" wsrfbf = "http://docs.oasis-open.org/wsrf/bf-2" wsrfr = "http://docs.oasis-open.org/wsrf/r-2" wsrfrw = "http://docs.oasis-open.org/wsrf/rw-2" wstop = "http://docs.oasis-open.org/wsn/t-1" # WS-Discovery 1.0 remapping wsdd10__HelloType = | wsdd__HelloType wsdd10__ByeType = | wsdd__ByeType wsdd10__ProbeType = | wsdd__ProbeType wsdd10__ProbeMatchesType = | wsdd__ProbeMatchesType wsdd10__ProbeMatchType = | wsdd__ProbeMatchType wsdd10__ResolveType = | wsdd__ResolveType wsdd10__ResolveMatchesType = | wsdd__ResolveMatchesType wsdd10__ResolveMatchType = | wsdd__ResolveMatchType # SOAP-ENV mapping SOAP_ENV__Envelope = struct SOAP_ENV__Envelope { struct SOAP_ENV__Header *SOAP_ENV__Header; _XML SOAP_ENV__Body; }; | struct SOAP_ENV__Envelope SOAP_ENV__Header = | struct SOAP_ENV__Header SOAP_ENV__Fault = | struct SOAP_ENV__Fault SOAP_ENV__Detail = | struct SOAP_ENV__Detail SOAP_ENV__Code = | struct SOAP_ENV__Code SOAP_ENV__Subcode = | struct SOAP_ENV__Subcode SOAP_ENV__Reason = | struct SOAP_ENV__Reason At the command line prompt, run wsdl2h on the ONVIF WSDLs. For example, the device management and event specifications: [command] wsdl2h -P -x -o onvif.h http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl soapcpp2 -2 -I import onvif.h Note that the specifications are substantial in size. Option `wsdl2h -P` removes unnecessary class hierarchy dependences on the root type `xsd__anyType`. This option will reduce the code size. Option `wsdl2h -x` removes extensibility elements (`xsd:anyAttribute` attributes and `xsd:any` elements). If attribute and element extensions to a complexType are needed, then use the typemap.dat file to add these as additional optional members. For example, to extend `tt__AudioDecoderConfigurationOptionsExtension` complexType class with an element Address of type `tt:IPAddress`, then add to typemap.dat: [command] tt__AudioDecoderConfigurationOptionsExtension = $ tt__IPAddress Address; Option `soapcpp2 -2` forces SOAP 1.2, which is required by ONVIF. In some cases the wsdl2h conversion may not detect SOAP 1.2 and therefore we recommend this option. Compile the soapcpp2-generated code together with `custom/duration.c`. If WS-Discovery is used (e.g. with ONVIF remotediscovery), also include `plugin/wsddapi.h` in your code and compile `plugin/wsddapi.c` (see [WS-Discovery](doc/wsdd/html/wsdd_0.html) documentation. If it appears that multiple service operations are generated with the same name, such as `GetServices` and `GetServices_` then remove `http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl` from the command line list of URLs because this WSDL is already imported by another WSDL. Please note that wsdl2h 2.8.10 and earlier versions generate ns1, ns2, ns3, etc prefixes when multiple service bindings are given for service operations. This will be changed in gSOAP 2.8.11 and up. The change can be made in 2.8.10 and earlier versions by modifying `gsoap/wsdl/service.cpp` at line 70: void Definitions::analyze(const wsdl__definitions &definitions) { // Analyze WSDL and build Service information int binding_count = 0; // Determine number of relevant SOAP service bindings if (service_prefix) { for (vector<wsdl__binding>::const_iterator i = definitions.binding.begin(); i != definitions.binding.end(); ++i) { for (vector<wsdl__binding_operation>::const_iterator j = (*i).operation.begin(); j != (*i).operation.end(); ++j) { if ((*j).operationPtr() && (*j).input && (*j).input->soap__body_) { binding_count++; break; } } } } else binding_count = 1; // Put all operations under a single binding ... then rebuild wsdl2h. With this change, option `wsdl2h -Nns` reverts back to the old behavior. How do I use gSOAP with STIX, CYBOX, and TAXII? --- We recommend to add the following XML namespace bindings to typemap.dat: [command] # TAXII prefixes taxi_111 = "http://docs.oasis-open.org/cti/ns/taxii/xml/binding-1.1.1" tdq = "http://docs.oasis-open.org/cti/ns/taxii/default-query-1.1.1" # STIX prefixes campaign = "http://stix.mitre.org/Campaign-1" coa = "http://stix.mitre.org/CourseOfAction-1" et = "http://stix.mitre.org/ExploitTarget-1" incident = "http://stix.mitre.org/Incident-1" indicator = "http://stix.mitre.org/Indicator-2" stixCommon = "http://stix.mitre.org/common-1" stix = "http://stix.mitre.org/stix-1" stixVocabs = "http://stix.mitre.org/default_vocabularies-1" threat_actor = "http://stix.mitre.org/ThreatActor-1" ttp = "http://stix.mitre.org/TTP-1" report = "http://stix.mitre.org/Report-1" stix-ciqaddress = "http://stix.mitre.org/extensions/Address#CIQAddress3.0-1" capec = "http://stix.mitre.org/extensions/AP#CAPEC2.7-1" stix-ciq = "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1" xpil = "urn:oasis:names:tc:ciq:xpil:3" maec = "http://stix.mitre.org/extensions/Malware#MAEC4.1-1" simpleMarking = "http://data-marking.mitre.org/extensions/MarkingStructure#Simple-1" TOUMarking = "http://data-marking.mitre.org/extensions/MarkingStructure#Terms_Of_Use-1" tlpMarking = "http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1" genericStructuredCOA = "http://stix.mitre.org/extensions/StructuredCOA#Generic-1" genericTM = "http://stix.mitre.org/extensions/TestMechanism#Generic-1" ioc-tr = "http://schemas.mandiant.com/2010/ioc/TR/" ioc = "http://schemas.mandiant.com/2010/ioc" oval = "http://stix.mitre.org/extensions/TestMechanism#OVAL5.10-1" snortTM = "http://stix.mitre.org/extensions/TestMechanism#Snort-1" yaraTM = "http://stix.mitre.org/extensions/TestMechanism#YARA-1" stix-cvrf = "http://stix.mitre.org/extensions/Vulnerability#CVRF-1" # CYBOX prefixes cyboxCommon = "http://cybox.mitre.org/common-2" cybox = "http://cybox.mitre.org/cybox-2" cyboxVocabs = "http://cybox.mitre.org/default_vocabularies-2" APIObj = "http://cybox.mitre.org/objects#APIObject-2" ARPCacheObj = "http://cybox.mitre.org/objects#ARPCacheObject-1" ASObj = "http://cybox.mitre.org/objects#ASObject-1" AccountObj = "http://cybox.mitre.org/objects#AccountObject-2" AddressObj = "http://cybox.mitre.org/objects#AddressObject-2" ArchiveFileObj = "http://cybox.mitre.org/objects#ArchiveFileObject-1" ArtifactObj = "http://cybox.mitre.org/objects#ArtifactObject-2" CodeObj = "http://cybox.mitre.org/objects#CodeObject-2" CustomObj = "http://cybox.mitre.org/objects#CustomObject-1" DNSCacheObj = "http://cybox.mitre.org/objects#DNSCacheObject-2" DNSQueryObj = "http://cybox.mitre.org/objects#DNSQueryObject-2" DNSRecordObj = "http://cybox.mitre.org/objects#DNSRecordObject-2" DeviceObj = "http://cybox.mitre.org/objects#DeviceObject-2" DiskObj = "http://cybox.mitre.org/objects#DiskObject-2" DiskPartitionObj = "http://cybox.mitre.org/objects#DiskPartitionObject-2" DomainNameObj = "http://cybox.mitre.org/objects#DomainNameObject-1" EmailMessageObj = "http://cybox.mitre.org/objects#EmailMessageObject-2" FileObj = "http://cybox.mitre.org/objects#FileObject-2" GUIDialogboxObj = "http://cybox.mitre.org/objects#GUIDialogboxObject-2" GUIObj = "http://cybox.mitre.org/objects#GUIObject-2" GUIWindowObj = "http://cybox.mitre.org/objects#GUIWindowObject-2" HTTPSessionObj = "http://cybox.mitre.org/objects#HTTPSessionObject-2" HostnameObj = "http://cybox.mitre.org/objects#HostnameObject-1" ImageFileObj = "http://cybox.mitre.org/objects#ImageFileObject-1" LibraryObj = "http://cybox.mitre.org/objects#LibraryObject-2" LinkObj = "http://cybox.mitre.org/objects#LinkObject-1" LinuxPackageObj = "http://cybox.mitre.org/objects#LinuxPackageObject-2" MemoryObj = "http://cybox.mitre.org/objects#MemoryObject-2" MutexObj = "http://cybox.mitre.org/objects#MutexObject-2" NetworkConnectionObj = "http://cybox.mitre.org/objects#NetworkConnectionObject-2" NetworkFlowObj = "http://cybox.mitre.org/objects#NetworkFlowObject-2" NetworkPacketObj = "http://cybox.mitre.org/objects#PacketObject-2" NetworkRouteEntryObj = "http://cybox.mitre.org/objects#NetworkRouteEntryObject-2" NetworkRouteObj = "http://cybox.mitre.org/objects#NetworkRouteObject-2" NetworkSocketObj = "http://cybox.mitre.org/objects#NetworkSocketObject-2" NetworkSubnetObj = "http://cybox.mitre.org/objects#NetworkSubnetObject-2" PDFFileObj = "http://cybox.mitre.org/objects#PDFFileObject-1" PipeObj = "http://cybox.mitre.org/objects#PipeObject-2" PortObj = "http://cybox.mitre.org/objects#PortObject-2" ProcessObj = "http://cybox.mitre.org/objects#ProcessObject-2" ProductObj = "http://cybox.mitre.org/objects#ProductObject-2" SMSMessageObj = "http://cybox.mitre.org/objects#SMSMessageObject-1" SemaphoreObj = "http://cybox.mitre.org/objects#SemaphoreObject-2" SocketAddressObj = "http://cybox.mitre.org/objects#SocketAddressObject-1" SystemObj = "http://cybox.mitre.org/objects#SystemObject-2" URIObj = "http://cybox.mitre.org/objects#URIObject-2" URLHistoryObj = "http://cybox.mitre.org/objects#URLHistoryObject-1" UnixFileObj = "http://cybox.mitre.org/objects#UnixFileObject-2" UnixNetworkRouteEntryObj = "http://cybox.mitre.org/objects#UnixNetworkRouteEntryObject-2" UnixPipeObj = "http://cybox.mitre.org/objects#UnixPipeObject-2" UnixProcessObj = "http://cybox.mitre.org/objects#UnixProcessObject-2" UnixUserAccountObj = "http://cybox.mitre.org/objects#UnixUserAccountObject-2" UnixVolumeObj = "http://cybox.mitre.org/objects#UnixVolumeObject-2" UserAccountObj = "http://cybox.mitre.org/objects#UserAccountObject-2" UserSessionObj = "http://cybox.mitre.org/objects#UserSessionObject-2" VolumeObj = "http://cybox.mitre.org/objects#VolumeObject-2" WhoisObj = "http://cybox.mitre.org/objects#WhoisObject-2" WinComputerAccountObj = "http://cybox.mitre.org/objects#WinComputerAccountObject-2" WinCriticalSectionObj = "http://cybox.mitre.org/objects#WinCriticalSectionObject-2" WinDriverObj = "http://cybox.mitre.org/objects#WinDriverObject-3" WinEventLogObj = "http://cybox.mitre.org/objects#WinEventLogObject-2" WinEventObj = "http://cybox.mitre.org/objects#WinEventObject-2" WinExecutableFileObj = "http://cybox.mitre.org/objects#WinExecutableFileObject-2" WinFileObj = "http://cybox.mitre.org/objects#WinFileObject-2" WinFilemappingObj = "http://cybox.mitre.org/objects#WinFilemappingObject-1" WinHandleObj = "http://cybox.mitre.org/objects#WinHandleObject-2" WinHookObj = "http://cybox.mitre.org/objects#WinHookObject-1" WinKernelHookObj = "http://cybox.mitre.org/objects#WinKernelHookObject-2" WinKernelObj = "http://cybox.mitre.org/objects#WinKernelObject-2" WinMailslotObj = "http://cybox.mitre.org/objects#WinMailslotObject-2" WinMemoryPageRegionObj = "http://cybox.mitre.org/objects#WinMemoryPageRegionObject-2" WinMutexObj = "http://cybox.mitre.org/objects#WinMutexObject-2" WinNetworkRouteEntryObj = "http://cybox.mitre.org/objects#WinNetworkRouteEntryObject-2" WinNetworkShareObj = "http://cybox.mitre.org/objects#WinNetworkShareObject-2" WinPipeObj = "http://cybox.mitre.org/objects#WinPipeObject-2" WinPrefetchObj = "http://cybox.mitre.org/objects#WinPrefetchObject-2" WinProcessObj = "http://cybox.mitre.org/objects#WinProcessObject-2" WinRegistryKeyObj = "http://cybox.mitre.org/objects#WinRegistryKeyObject-2" WinSemaphoreObj = "http://cybox.mitre.org/objects#WinSemaphoreObject-2" WinServiceObj = "http://cybox.mitre.org/objects#WinServiceObject-2" WinSystemObj = "http://cybox.mitre.org/objects#WinSystemObject-2" WinSystemRestoreObj = "http://cybox.mitre.org/objects#WinSystemRestoreObject-2" WinTaskObj = "http://cybox.mitre.org/objects#WinTaskObject-2" WinThreadObj = "http://cybox.mitre.org/objects#WinThreadObject-2" WinUserAccountObj = "http://cybox.mitre.org/objects#WinUserAccountObject-2" WinVolumeObj = "http://cybox.mitre.org/objects#WinVolumeObject-2" WinWaitableTimerObj = "http://cybox.mitre.org/objects#WinWaitableTimerObject-2" X509CertificateObj = "http://cybox.mitre.org/objects#X509CertificateObject-2" To run wsdl2h on the specifications we recommend to use option `-u` to fold C unions into structs. Furthermore, soapcpp2 will complain about duplicate member names for schema attribute declarations that are reduced to fixed values. The only concern here is that you will need to make sure that the fixed values are used in XML messaging. How do I use gSOAP with the XLIFF 2.0 specification? --- Use gSOAP 2.8.10 or greater. In the typemap.dat file used by wsdl2h, add: [command] xliff = "urn:oasis:names:tc:xliff:document:2.0" xliff__priorityValue = typedef int xliff__priorityValue 1:10; Run wsdl2h on the XLIFF 2.0 schema. We recommend option `-u` to remove `union` types, making the code cleaner. You may also want to use option `-d` to replace XML strings with DOM nodes. [command] wsdl2h -u -o xliff2.h http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/schemas/xliff_core_2.0.xsd Then run soapcpp2 and compile with your code soapC.cpp that contains the serializers (which are declared in the generated soapStub.h and soapH.h): [command] soapcpp2 -0 -I gsoap/import xliff2.h c++ soapC.cpp ... Here is an example that creates an xliff 2.0 document: #include "soapH.h" #include "xliff.nsmap" // 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; } // 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; } ... // create a context soap *soap = soap_new1(SOAP_XML_INDENT); //create a XLIFF 2.0 doc _xliff__xliff *doc = soap_new__xliff__xliff(soap); doc->soap_default(soap); doc->version = "2.0"; doc->srcLang = "en"; doc->trgLang = "fr"; // add <file> _xliff__file *file = soap_new__xliff__file(soap); file->soap_default(soap); doc->file.push_back(file); file->id = "f1"; // add <file><notes> _xliff__notes *notes = soap_new__xliff__notes(soap); notes->soap_default(soap); file->notes = notes; // add <file><notes><note> _xliff__note *note = soap_new__xliff__note(soap); note->soap_default(soap); notes->note.push_back(note); note->id = soap_make_string(soap, "n1"); note->__mixed = (char*)"note for file."; // add <file><unit> _xliff__unit *unit = soap_new__xliff__unit(soap); unit->soap_default(soap); unit->id = "u1"; file->__size_file = 1; file->__union_file = soap_new___xliff__union_file(soap, 1); // array of 1 <unit> file->__union_file->soap_default(soap); file->__union_file->unit = unit; // add <file><unit><segment> _xliff__segment *segment = soap_new__xliff__segment(soap); segment->soap_default(soap); segment->id = soap_make_string(soap, "s1"); unit->__size_unit = 1; unit->__union_unit = soap_new___xliff__union_unit(soap, 1); // array of 1 <segment> unit->__union_unit->soap_default(soap); unit->__union_unit->segment = segment; // add <file><unit><segment><source> _xliff__source *source = soap_new__xliff__source(soap); source->soap_default(soap); source->__size_source = 1; source->__union_source = soap_new___xliff__union_source(soap, 1); // array of 1 <pc> source->__union_source->soap_default(soap); segment->source = source; // add <file><unit><segment><source><pc> _xliff__pc *pc1 = soap_new__xliff__pc(soap); pc1->soap_default(soap); pc1->id = "1"; pc1->__mixed = (char*)"Hello <mrk id=\"m1\" type=\"term\">World</mrk>!"; source->__union_source->pc = pc1; // add <file><unit><segment><target> _xliff__target *target = soap_new__xliff__target(soap); target->soap_default(soap); target->__size_target = 1; target->__union_target = soap_new___xliff__union_target(soap, 1); // array of 1 <pc> target->__union_target->soap_default(soap); segment->target = target; // add <file><unit><segment><target><pc> _xliff__pc *pc2 = soap_new__xliff__pc(soap); pc2->soap_default(soap); pc2->id = "1"; pc2->__mixed = (char*)"Bonjour le <mrk id=\"m1\" type=\"term\">Monde</mrk> !"; target->__union_target->pc = pc2; // write doc to std::cout soap->os = &std::cout; if (soap_write__xliff__xliff(soap, doc)) soap_print_fault(soap, stderr); soap->os = NULL; // cleanup soap_destroy(soap); soap_end(soap); soap_free(soap); How do I use gSOAP to develop a client for EWS Exchange Services? --- We recommend the following steps. **1.** Add the following lines to the typemap.dat file. This file is used by wsdl2h to bind the services: [command] ewsmsg = "http://schemas.microsoft.com/exchange/services/2006/messages" ewstyp = "http://schemas.microsoft.com/exchange/services/2006/types" ewsadr = "http://schemas.microsoft.com/exchange/2010/Autodiscover" [ //gsoap ewswsa schema namespace: http://schemas.microsoft.com/ws/2005/05/addressing/none mutable struct SOAP_ENV__Header { mustUnderstand char *ewswsa__Action; }; ] These additions to typemap.dat should only be used for EWS projects, so you may want to create a copy of typemap.dat for your project. The `SOAP_ENV__Header` addition is necessary to work around the error *SOAP 1.1 fault SOAP-ENV:MustUnderstand[no subcode] "The data in element 'Action' must be understood but cannot be processed"*, which is due to the use of an unknown Action header in the the SOAP Header returned by the EWS service. **2.** Run wsdl2h with option `-u` to disable unions and optionally use wsdl2h option `-c` to generate C code: [command] wsdl2h -u -t typemap.dat -o Services.h https://your-exchange-server/EWS/Exchange.asmx?wsdl The above command assumes that HTTPS is enabled for wsdl2h. If HTTPS is not enabled in wsdl2h and you have OpenSSL installed then rebuild wsdl2h with: [command] cd gsoap/wsdl make -f MakefileManual secure or you can download the following WSDL and XSD files from your EWS service: - `https://your-exchange-server/ews/Services.wsdl` - `https://your-exchange-server/ews/messages.xsd` - `https://your-exchange-server/ews/types.xsd` save them locally and then run: [command] wsdl2h -u -t typemap.dat Services.wsdl **3.** Run soapcpp2 to generate a proxy class for the EWS service (C++ only, e.g. no wsdl2h `-c` option was used): [command] soapcpp2 -C -j -x Services.h Or when working in C (wsdl2h option `-c` was used): [command] soapcpp2 -CL -x Services.h **4.** The EWS service requires authentication. The simplest way is to use HTTP Basic authentication over HTTPS. Also NTLM can be used, but NTLM alone is not sufficient to authenticate with the EWS service because with NTLM the user's credentials are not passed on to the backend services. To use HTTPS and authenticate, set the client-side SSL context, the userid and passwd: #include "soapExchangeServiceBindingProxy.h" // generated #include "ExchangeServiceBinding.nsmap" // generated soap_ssl_init(); // call this in main() just once ExchangeServiceBindingProxy EWS("https://outlook.office365.com/EWS/Exchange.asmx", SOAP_C_UTFSTRING|SOAP_IO_KEEPALIVE|SOAP_XML_NOTYPE); if (soap_ssl_client_context(EWS.soap, SOAP_SSL_SKIP_HOST_CHECK, NULL, NULL, "path/to/gsoap/cacerts.pem", NULL, NULL)) { EWS.soap_stream_fault(std::cerr); exit(1); } EWS.soap->userid = "your-full-email-address"; EWS.soap->passwd = "your-email-passwd"; // set EWS request server version _ewstyp__RequestServerVersion *serVer = soap_new__ewstyp__RequestServerVersion(EWS.soap); serVer->Version = ewstyp__ExchangeVersionType__Exchange2010_USCORESP2; // your Exchange server version EWS.soap_header(NULL, NULL, NULL, serVer, NULL, NULL); // set the service operation request parameters (if any) ewsmsg__GetPasswordExpirationDateType request; request.soap_default(); // the service operation response ewsmsg__GetPasswordExpirationDateResponse response; // invoke an operation, for example EWS GetPasswordExpirationDate if (EWS.GetPasswordExpirationDate(&request, response)) { EWS.soap_stream_fault(std::cerr); exit(1); } std::cout << ctime(&response.PasswordExpirationDate); // or use the safer ctime_r EWS.destroy(); Or when working in C (wsdl2h option `-c` was used): #include "soapH.h" // generated #include "ExchangeServiceBinding.nsmap" // generated soap_ssl_init(); // call this in main() just once struct soap *soap = soap_new1(SOAP_C_UTFSTRING|SOAP_IO_KEEPALIVE|SOAP_XML_NOTYPE); if (soap_ssl_client_context(soap, SOAP_SSL_SKIP_HOST_CHECK, NULL, NULL, "path/to/gsoap/cacerts.pem", NULL, NULL)) { soap_print_fault(soap, stderr); exit(1); } soap->userid = "your-full-email-address"; soap->passwd = "your-email-passwd"; // set EWS request server version _ewstyp__RequestServerVersion serVer; serVer.Version = ewstyp__ExchangeVersionType__Exchange2010_USCORESP2; // your Exchange server version soap_header(soap); soap->header->ewstyp__ServerVersionInfo = soap_malloc(soap, sizeof(struct _ewstyp__RequestServerVersion); soap_default__ewstyp__RequestServerVersion(soap, soap->header->ewstyp__ServerVersionInfo); soap->header->ewstyp__ServerVersionInfo->Version = ewstyp__ExchangeVersionType__Exchange2010_USCORESP2; // set the service operation request parameters (if any) struct ewsmsg__GetPasswordExpirationDateType request; soap_default_ewsmsg__GetPasswordExpirationDateType(); // the service operation response struct ewsmsg__GetPasswordExpirationDateResponse response; // invoke an operation, for example EWS GetPasswordExpirationDate if (soap_call___ewsmsg__GetPasswordExpirationDate(soap, "https://outlook.office365.com/EWS/Exchange.asmx", NULL, &request, &response)) { soap_print_fault(soap, stderr); exit(1); } printf("%s\n", ctime(&response.PasswordExpirationDate)); // or use the safer ctime_r soap_end(soap); // delete data soap_destroy(soap); // delete data soap_free(soap); // free context **5.** Compile the proxy C++ code (or soapClient.c in C) with stdsoap2.cpp (or stdsoap2.c in C) and soapC.cpp (or soapC.c in C). Link with the OpenSSL lib with `-lssl -lcrypto`. In order to support Unicode, the flag `SOAP_C_UTFSTRING` is used, which supports UTF-8 in regular 8-bit strings and you can convert between wide strings and 8-bit strings as follows: const char *s = soap_wchar2s(soap, L"wide_string"); // convert wide string to UTF-8 8-bit string s std::string str(s); // str is a UTF-8 encoded string wchar_t *w = NULL; soap_s2wchar(soap, s, &w, -1, -1, NULL); // convert UTF-8 8-bit string s to wide string std::wstring wstr(w); // wstr is a wide string Alternatively, you can use wide strings from the get-go. To do so, add the following line to typemap.dat before running wsdl2h: [command] xsd__string = | std::wstring; Or when working in C: [command] xsd__string = | wchar_t* [![To top](images/go-up.png) To top](resources.html)