Tuesday, 29 March 2011

All things mod_gsoap

Well, the documentation in gsoap itself and even the internet is non existent for using gsoap as an apache module. Hopefully, this entry might make it a little less painful for those wanting to give it a go.

I have built this on Ubuntu 10.10 but this example is using SLES11. It really shouldn't matter much as long as you have a proper development toolchain installed on your flavour of distro. You may have to explicitly add a -fPIC to the build, but we'll come to that later.
I've also done this on AIX 5.3L

I always find that the best way to try anything like this out is to build all components from scratch so you know exactly what you are looking at. For the purpose of this exercise, you need to download a recent version of apache http server and gSOAP.
We are going to build these under a testuser account (/home/testuser) but substitute your own if you like.

cd /home/testuser
mkdir apachegsoap
cd apachegsoap
tar -xjf httpd-2.2.17.tar.bz2
cd httpd-2.2.17
./configure --prefix=/home/testuser/apachegsoap --with-mpm=worker --enable-mods-shared=most

There are all sorts of ways of configuring apache, but I am sticking to a simplistic model just to show you how mod_gsoap works.

make -j4; make install (or whatever your machine supports)

Now, we are going to build gsoap.

cd ..
tar -xzf gsoap_2.8.1.tar.gz
cd gsoap-2.8

./configure --prefix=/home/testuser/apachegsoap --enable-debug --disable-samples CFLAGS=-fPIC CXXFLAGS=-fPIC
make; make install

We now need to build mod_gsoap and have it installed in the apache modules directory. It's probably a good idea (but not necessary) to copy the header file to your include directory to make module building easier later on. This is as simple as :-

cd gsoap/mod_gsoap/mod_gsoap-0.6/apache_20
/home/testuser/apachegsoap/bin/apxs -a -i -c -I /home/testuser/apachegsoap/include mod_gsoap.c
cp apache_gsoap.h /home/testuser/apachegsoap/include

This adds the LoadModule directive for mod_gsoap to /home/testuser/apachegsoap/conf/httpd.conf and we will look at what other configuration we need to do after we build our example service.
We are going to use the calculator example that comes with gsoap to build a service under apache and call it from the gsoap client. mod_gsoap works by dynamically loading your own gsoap module and calling the appropriate entry points from there. We need to modify calcserver.c to use the mod_gsoap hooks instead of having a main().

cd gsoap/samples/calc

Remove the main() function entirely and replace with :-

#include "apache_gsoap.h"

The easiest way of building our own module is to use apxs again, but first, we must use the gsoap toolkit to generate our stubs and headers.

/home/testuser/apachegsoap/bin/soapcpp2 -c calc.h
/home/testuser/apachegsoap/bin/apxs -a -c calcserver.c soapC.c soapServer.c -lgsoap

If you have installed anything in some other directories, you will need to add appropriate -I and -L directives for the above. Because we didn't tell apxs to install the shared library (-i), it will reside in a seperate .libs directory where you are now.
viz. /home/testuser/apachegsoap/gsoap-2.8/gsoap/samples/calc/.libs
That is good enough for our purposes. You will also notice that we have linked in the libgsoap.a archive which is necessary. gsoap does not build as a shared library by default and I won't go into detail here about how to do this.

To build the test client, we first need to modify the endpoint it will talk to. This will be our new apache instance. I would recommend for testing that we change the Listen directive in httpd.conf to use something like 9080 instead of the default port 80 to save us having to start the service with a priviledged user. Edit calcclient.c and change the server definition to :-

const char server[] = "http://localhost:9080/soap";

Building it is just a matter of :-

gcc -I /whome/testuser/apachegsoap/include -L /whome/testuser/apachegsoap/lib -o calcclient calcclient.c soapC.c soapClient.c -lgsoap

Now we have our calcserver.so, we can go ahead and setup our httpd.conf to finalise our test service. We are going to add to the end

<IfModule mod_gsoap.c>
<Location /soap>
SetHandler gsoap_handler
SOAPLibrary /home/testuser/apachegsoap/gsoap-2.8/gsoap/samples/calc/.libs/calcserver.so
Order allow,deny
Allow from all

This is a very open configuration and is only here for ease of use for the example.

Remember, the LoadModule directive was already added earlier. We are now in a position to start up our service and give it a test.

/home/testuser/apachegsoap/bin/apacectl start

You should now be able to point your browser to http://localhost:9080 and get the default index page with It works! displayed.
If this is all in order, we should now be able to execute of calcclient test program and get some results.

/home/testuser/apachegsoap/gsoap-2.8/gsoap/samples/calc/calcclient add 2 5
result = 7

You now have a starting point to writing your own soap modules!!

However, it would be cruel of me to write this and not give a quick pointer on how to debug the thing. We really need to stop the service and start it up in single threaded mode so we can attach to it using a debugger. You can either use gdb on the command line, ddd or any other front end to your particular debugger. I'll use gdb for this example.

/home/testuser/apachegsoap/bin/apacectl stop
/home/testuser/apachegsoap/bin/httpd -X -f /home/testuser/apachegsoap/conf/httpd.conf &

Now, using the pid reported back from this, attach to it with gdb :-

gdb /home/testuser/apachegsoap/bin/httpd 25487

You will see a load of symbols loading, include mod_gsoap.so. Set a breakpoint on the soap_serve call (the main entry point), say yes to accepting a pending breakpoint, continue and then execute our calcclient from another window.

(gdb) b soap_serve
Function "soap_serve" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (soap_serve) pending.
(gdb) c

When you execute the calcclient, you should get gdb stopping at that breakpoint. Off you go!

[Switching to Thread 0x7f3fbd209950 (LWP 25493)]

Breakpoint 1, 0x00007f3fb059e398 in soap_serve () from /home/testuser/apachegsoap/gsoap-2.8/gsoap/samples/calc/.libs/calcserver.so
Current language: auto; currently asm
(gdb) n
Single stepping until exit from function soap_serve,
which has no line number information.
0x00007f3fb05a5eec in apache_default_soap_serve () from /home/testuser/apachegsoap/gsoap-2.8/gsoap/samples/calc/.libs/calcserver.so

If you do this under an installed instance of apache running as user wwwrun or something, you will have to execute the debugger as that user. Just use something like :-

sudo -u wwwrun gdb /usr/sbin/httpd2-worker 25487

instead.I hope that people find this short tutorial informative as it is maddening getting this to work the first time. The documentation on it is woeful, which is a shame, as the standard of documentation for gSOAP in general is excellent. The mod_gsoap module itself is lacking in several areas but, hopefully, I'll be able to post something here in the near future which will show you how to use it for more production like environments.