Program 5: gSOAP "HelloClient5"

Description

Being able to create both a client and server so easily in C# is nice, but the use of C# is restricted to the Windows environment. For other environments, I will use the gSOAP Toolkit. It produces, given a WSDL file, all the code necessary to connect to the web service.

Install gSOAP

To install gSOAP version 2.7.13, first download gsoap_2.7.13.tar.gz to a temporary directory, e.g. /tmp/gsoap

Then, do the following, replacing /tmp/gsoap with your directory:

Extract gsoap:
$ cd /tmp/gsoap
$ gzip -dc < gsoap_2.7.13.tar.gz | tar -xf -
$ cd gsoap_2.7.13
Configure and build
$ ./configure --prefix=/usr
$ make
Install (must be root user)
# make install

Files

Upon installation, gsoap produces the following files: (assuming --prefix=/usr)

gSOAP Executables
/usr/bin/soapcpp2
/usr/bin/wsdl2h
gSOAP C Headers
/usr/include/stdsoap2.h
gSOAP Libraries
/usr/lib/libgsoap.a
/usr/lib/libgsoapck.a
/usr/lib/libgsoapssl.a
/usr/lib/libgsoap++.a
/usr/lib/libgsoapck++.a
/usr/lib/libgsoapssl++.a
gSOAP pkg-config Files
/usr/lib/pkgconfig/gsoap.pc
/usr/lib/pkgconfig/gsoapck.pc
/usr/lib/pkgconfig/gsoapssl.pc
/usr/lib/pkgconfig/gsoap++.pc
/usr/lib/pkgconfig/gsoapck++.pc
/usr/lib/pkgconfig/gsoapssl++.pc
gSOAP Other Files
/usr/share/gsoap/*

Using gSOAP

First off, if we want to make a client for the HelloService, we will need to get a hold of HelloService.wsdl. For a WCF web service, we can get this by typing in the URL of the service with a "?wsdl" suffix. For example, http://localhost:8000/HelloService?wsdl. From this WSDL file, gSOAP can generate all of the necessary code for communicating with the server.

gSOAP, once installed, provides us with two tools: wsdl2h and soapcpp2. We will use both of them.

To demonstrate the use of gSOAP, I will first go into a new directory, with just the WSDL file.
$ cd /tmp/client
$ ls -l
HelloService.wsdl
The wsdl2h tool takes a .wsdl file (e.g. HelloService.wsdl), processes it, and spits out a .h (e.g., HelloService.h) file. This file will be immediately passed on to soapcpp2.
$ wsdl2h -c -s HelloService.wsdl 
$ ls -l
HelloService.h
HelloService.wsdl
The soapcpp2 tool takes the .h file (e.g. HelloService.h), processes it, and spits out several files.
$ soapcpp2 -c -C -L HelloService.h
$ ls -l
BasicHttpBinding_USCOREHelloService.GetHello.req.xml
BasicHttpBinding_USCOREHelloService.GetHello.res.xml
BasicHttpBinding_USCOREHelloService.nsmap
HelloService.h 
HelloService.wsdl 
soapC.c
soapClient.c
soapH.h
soapStub.h 
Now create a file called HelloClient5.c with the following:
#include "BasicHttpBinding_USCOREHelloService.nsmap"
#include <stdio.h>

const char* GetHello(struct soap *soap)
{
    struct _ns3__GetHello         msgInput;
    struct _ns3__GetHelloResponse msgOutput;
    if(soap_call___ns1__GetHello(soap,0,0,&msgInput,&msgOutput)!=SOAP_OK) {
      soap_print_fault(soap,stderr);
      return 0;
    } else {
      return msgOutput.GetHelloResult;
    }
}
int main()
{
    const char *str;
    struct soap *soap = soap_new();

    str = GetHello(soap);
    printf("The server said : %s\n", str);

    return 0;
}
And a Makefile with the following:
CC=cc
LDFLAGS=`pkg-config gsoap --libs`
HelloClient5 : HelloClient5.o soapC.o soapClient.o
	${CC} -o HelloClient5 HelloClient5.o soapC.o soapClient.o ${LDFLAGS}
HelloClient5.o : HelloClient5.c
	${CC} -c HelloClient5.c 
soapC.o : soapC.c
	${CC} -c soapC.c -ansi
soapClient.o : soapClient.c
	${CC} -c soapClient.c -ansi
clean : 
	rm -f test.o soapC.o soapClient.o
update :
	wsdl2h -c -s HelloService.wsdl
	soapcpp2 -c -C -L HelloService.h
Now, if everything went according to plan, you can make and run your client.
$ make
$ ./HelloClient5
The server said : hello

Analysis

Here's an inside look of the conversation between the HelloClient and HelloService.

HelloClient's Request:
POST /HelloService HTTP/1.1
Host: door.mvpsi.com:8000
User-Agent: gSOAP/2.7
Content-Type: text/xml; charset=utf-8
Content-Length: 504
Connection: close
SOAPAction: "http://petio.org/2009/07/22/HelloService/HelloService/GetHello"

<?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:ser="http://schemas.microsoft.com/2003/10/Serialization/" 
  xmlns:tns="http://tempuri.org/" 
  xmlns:m="http://petio.org/2009/07/22/HelloService">
  <SOAP-ENV:Body>
    <m:GetHello></m:GetHello>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HelloService's Response:
HTTP/1.1 200 OK
Content-Length: 218
Content-Type: text/xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 04 Aug 2009 22:14:23 GMT
Connection: close

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetHelloResponse xmlns="http://petio.org/2009/07/22/HelloService">
      <GetHelloResult>hello</GetHelloResult>
    </GetHelloResponse>
  </s:Body>
</s:Envelope>

(The above XML was formatted for this example)

Files

HelloService.wsdl
The WSDL file obtained from http://localhost:8000/HelloService?wsdl
HelloService.h
The header file generated from wsdl2h
soapC.c
One of the files produced by soapcpp2.
soapClient.c
One of the files produced by soapcpp2.
soapH.h
One of the files produced by soapcpp2.
soapStub.h
One of the files produced by soapcpp2.
HelloClient5.c
The main piece of code for our client. Must be linked with soapC.o, soapClient.o, and libgsoap.a
Makefile
The Makefile for the HelloClient5 project.