XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Building XML-RPC Clients in C
by Joe Johnston | Pages: 1, 2, 3, 4

Listing 11 demonstrates how to deal with structs. Much like arrays, you can iterate over key-value pairs in structs. The function xmlrpc_struct_size returns the number of key-value pairs available. A call to xmlrpc_get_key_and_value will point the two passed-in pointers to xmlrpc_value pointers at the n-th key-value pair. Although keys are almost always strings, I err on the side of caution here by asking print_values to display the key's value.

Listing 11: xmlrpc_debug.c, part 10


   188  void get_struct(xmlrpc_env* env, xmlrpc_value* in){
   189    int i, size = 0;
   190    xmlrpc_value *key, *value;
   191  
   192    size = xmlrpc_struct_size(env, in);
   193    die_if_fault_occurred(env);
   194  
   195    for(i=0; i < size; i++){
   196      xmlrpc_struct_get_key_and_value(env,
   197                                      in,
   198                                      i,
   199                                      &key,
   200                                      &value);
   201      die_if_fault_occurred(env);
   202  
   203      printf("\tkey: ");
   204      print_values(env, key);
   205      printf("\tvalue: ");
   206      print_values(env, value);
   207    }
   208  }
   209  

The program concludes with Listing 12. This is a routine that conveniently catches errors. It was also ripped in whole from the example code in the XML-RPC C library.

Listing 12: xmlrpc_debug.c, part 11


   210  void die_if_fault_occurred (xmlrpc_env *env){
   211      
   212      if (env->fault_occurred) {
   213          fprintf(stderr, "XML-RPC Fault: %s (%d)\n",
   214                  env->fault_string, env->fault_code);
   215          exit(1);
   216      }
   217  }

The Makefile

Resources

Binary Data to Go: Using XML-RPC to Serve Up Charts on the Fly

XML-RPC Home Page

Libwww: the W3C Sample Code Library

Once the source code is ready, you'll want to compile it. There are a lot of shared libraries that need to be linked into any XML-RPC client program. Eric Kidd's documentation suggests that you initialize your variables like this:

  $ CLIENT_CFLAGS=`xmlrpc-c-config libwww-client --cflags`
  $ CLIENT_LIBS=`xmlrpc-c-config libwww-client --libs`

I have simply expanded these so that I can track down missing library errors more easily. Listing 13 shows the barebones Makefile used to compile this debug client. All warnings are turned on and it should compile without warnings under gcc.

Listing 13: Makefile


     1  CLIENT_CFLAGS=-I/usr/include
     2  CLIENT_LIBS=-L/usr/lib -lxmlrpc_client \
     3  -lwwwxml -lxmltok -lxmlparse -lwwwzip  \
     4  -lwwwinit -lwwwapp -lmd5 -lwwwhtml -lwwwtelnet \
     5  -lwwwnews -lwwwhttp -lwwwmime -lwwwgopher -lwwwftp \
     6  -lwwwfile -lwwwdir -lwwwcache -lwwwstream -lwwwmux \
     7  -lwwwtrans -lwwwcore -lwwwutils -ldl -lz \
     8  -lxmlrpc -lxmlrpc_xmlparse -lxmlrpc_xmltok -Wl,--rpath -Wl,/usr/lib
     9  
    10  CFLAGS=-Wall -ansi -pedantic -g
    11  
    12  debug:
    13          gcc $(CFLAGS) $(CLIENT_CFLAGS) -o \
                xmlrpc_debug xmlrpc_debug.c $(CLIENT_LIBS)

A Simple Perl Server

The test harness for the debug client is a simple Perl XML-RPC server. It returns sample data of various formats. Like all Frontier::Daemon programs, it runs as a single-threaded HTTP server, listening, in this case, to TCP port 3080. The remote procedures this server handles are given in the methods hash, which is passed to Frontier::Daemon during initialization. Because these functions are so simple, anonymous subroutines are used instead of creating named subroutines and passing references to them. Normally, the Frontier::RPC2 library is good about guessing how to encode Perl scalars, but base64 strings need manual intervention. Line 26 in Listing 14 below shows this in action.

Listing 14: Perl Server


     1  #!/usr/bin/perl --
     2  # just return sample data
     3  
     4  use strict;
     5  use Frontier::Daemon;
     6  use MIME::Base64;
     7  
     8  use constant PORT       => 3080;
     9  use constant SERVER_URL => 'http://localhost:'.PORT.'/RPC2';
    10  
    11  print "Starting: ", SERVER_URL, "\n";
    12  my $coder = Frontier::RPC2->new;
    13  Frontier::Daemon->new(
    14                        methods => {
    15     str    => sub{ return "AB "x512 },
    16     int    => sub{ return 12345 },
    17     double => sub{ return 1.234 },
    18     array  => sub{ return [(0..128)] },
    19     struct => sub{ return {
    20                              key1 => 1,
    21                              key2 => "value2",
    22                              key3 => 4.56,
    23                              }
    24                     },
    25     base64 => sub{ return
    26                        $coder->base64(
    27                        encode_base64('I love Lucy')
    28                                       )
    29                     },
    30  
    31     mixed  => sub {
    32                        return [
    33                                { key1 => 1.0 },
    34                                { key2 => 2.0 },
    35                                { key3 => 'three'},
    36                               ];
    37                     },
    38                                   },
    39  
    40                        LocalPort => PORT,
    41                        Reuse     => 1,
    42                       );

What's Next?

This code should give the aspiring C XML-RPC programmer a good starting point for building a real application. It's hard to beat a C program for execution speed. A program similar to the debug client shown here, but written in Perl or Python, will run five to ten times slower. Of course, the Perl or Python script is five to ten times faster to write. You can save either CPU time or programmer time, but not both. Happy hacking.


Joe Johnston is an independent contractor and freelance writer. A graduate of the University of Massachusetts in Boston with a B.A. in computer science, he is a teacher, a Web designer, and an author of articles for the Perl Journal and other publications. Joe coauthored O'Reilly's Programming Web Services with XML_RPC. He can be emailed at jjohn@cs.umb.edu.


O'Reilly & Associates recently released (June 2001) Programming Web Services with XML-RPC.