Program 6: csoap "HelloClient6"

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 might decide to use the csoap library. csoap is licensed under the LGPLv2 License, meaning we can link it to our programs without violating copyright. Using csoap, we are able to connect to a given Web Service, and communicate with it via SOAP. As I write this, the newest version of csoap is 1.1.0.

Dependencies

csoap depends on libxml2.

Install csoap

To install csoap version 1.1.0, first download libsoap-1.1.0.tar.gz to a temporary directory, e.g. /tmp/csoap

For example, to download csoap using Wget:
$ mkdir /tmp/csoap
$ cd /tmp/csoap
$ wget http://prdownloads.sourceforge.net/csoap/libsoap-1.1.0.tar.gz
Extract csoap:
$ tar -xf libsoap-1.1.0.tar.gz
Configure && Make
$ cd /tmp/csoap/libsoap-1.1.0
$ ./configure --prefix=/usr
$ make
Install (must be root user)
# make install

Files

Upon installation, csoap produces the following files:

Executables
/usr/bin/csoap-config
/usr/bin/soapclient
C Headers
/usr/include/libcsoap-1.1/libcsoap/*
/usr/include/nanohttp-1.1/nanohttp/*
Libraries
/usr/lib/pkgconfig/libcsoap.pc
/usr/lib/libcsoap.la
/usr/lib/libcsoap.so
/usr/lib/libcsoap.a
/usr/lib/libnanohttp.la
/usr/lib/libnanohttp.so
/usr/lib/libnanohttp.a

Using csoap-config

csoap installs a config script csoap-config, that you can use to dynamically ask for commandline flags to pass to the compiler when using csoap.

To find which version of csoap is installed:
$ csoap-config --version
1.1.0
To find where csoap was installed (the prefix which was used):
$ csoap-config --prefix
/usr
To get the proper commandline switches for linking to csoap libraries:
$ csoap-config --libs
-L/usr/lib -lcsoap -lnanohttp -L/usr/lib -lxml2 -lz -lm
To get the proper commandline switches for including csoap C headers:
$ csoap-config --cflags
-I/usr/include/libcsoap-1.1 -I/usr/include/nanohttp-1.1 -I/usr/include/libxml2 -pthread

Using libcsoap to make a SOAP client

Sure, you could read the official documentation, but the examples given are full of typos. Do it my way, instead.

Create a project directory:
$ mkdir /tmp/client
$ cd /tmp/client
Create a Makefile:
HelloClient6 : HelloClient6.o
	gcc `csoap-config --libs` -o HelloClient6 HelloClient6.o
HelloClient6.o : HelloClient6.c
	gcc `csoap-config --cflags` -c HelloClient6.c
Create HelloClient6.c
#include <stdio.h>
#include <libcsoap/soap-client.h>

static char *url = "http://localhost:8000/HelloService";
static char *urn = "http://petio.org/2009/07/22/HelloService";
static char *method = "GetHello";
static char *action = "http://petio.org/2009/07/22/HelloService/HelloService/GetHello";

void err_soap(herror_t err);

int main(int argc, char *argv[])
{
    herror_t err;
    SoapCtx *request;
    SoapCtx *response;

    /* ----------------------------------- */
    /*    Initialize SOAP Client           */
    /* ----------------------------------- */
    err = soap_client_init_args(argc,argv);
    if(err!=H_OK) 
    { 
        err_soap(err); 
        return 1; 
    }

    /* ----------------------------------- */
    /*    Create "request" envelope        */
    /* ----------------------------------- */
    err = soap_ctx_new_with_method(urn,method,&request);
    if(err!=H_OK) 
    {
        err_soap(err);
        soap_client_destroy();
        return 1;
    }

    /* ----------------------------------- */
    /*    Show "request" envelope          */
    /* ----------------------------------- */
    printf("-------- Request --------\n");
    xmlDocFormatDump(stdout, request->env->root->doc,1);
    printf("-------------------------\n");

    /* ----------------------------------- */
    /*    Trade for "response" envelope    */
    /* ----------------------------------- */
    err = soap_client_invoke(request,&response,url,action);
    if(err!=H_OK) 
    {
        err_soap(err);
        soap_ctx_free(request);
        soap_client_destroy();
        return 1;
    }

    /* ----------------------------------- */
    /*    Show "response" envelope          */
    /* ----------------------------------- */
    printf("-------- Response --------\n");
    xmlDocFormatDump(stdout, response->env->root->doc,1);
    printf("-------------------------\n");

    /* ----------------------------------- */
    /*    Destroy SOAP Client              */
    /* ----------------------------------- */
    soap_ctx_free(request);
    soap_ctx_free(response);
    soap_client_destroy();

    return 0;
}

void err_soap(herror_t err)
{
    if(err==H_OK) return;
    printf("%s():%s [%d]\n",herror_func(err),
                            herror_message(err),
                            herror_code(err));
    herror_release(err);
}
Run make
$ make
Your directory should now look like this:
$ ls
Makefile HelloClient6 HelloClient6.c HelloClient6.o
Run HelloClient6
$ ./HelloClient6 
-------- Request --------
<?xml version="1.0"?>
<s:Envelope 
  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
  s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
  <s:Header/> 
  <s:Body>  
    <m:GetHello xmlns:m="http://petio.org/2009/07/22/HelloService"> </m:GetHello> 
  </s:Body>
</s:Envelope>
-------------------------
-------- Response --------
<?xml version="1.0"?>
<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 has been formatted for this page)

Feedback

I personally dislike outdated documentation. If anything here seems wrong, or perhaps did not work for you, please email me (jay@petio.org) and tell me so I can update it. Thanks!