libxmlrpc_server_abyss

This chapter describes the functions in the libxmlrpc_server_abyss function library, which is part of XML-RPC For C/C++ (Xmlrpc-c). Also see General Library Information - C

The libxmlrpc_server_abyss library provides functions for use in a program that is an XML-RPC server based on the Abyss HTTP server.

When using libxmlrpc_server_abyss, you must also use the libxmlrpc library. It contains additional facilities that an XML-RPC server needs but are general to XML-RPC and not specific to XML-RPC servers. Besides, the libxmlrpc_server_abyss library routines depend on it.

Similarly, you will need the libxmlrpc_server library. It contains functions for XML-RPC servers that are not specific to Abyss-based servers. And libxmlrpc_server_abyss library routines depend on it.

Finally, you will need Abyss itself, which is in the library libxmlrpc_abyss, which is part of Xmlrpc-c.

Chapter Contents

The <xmlrpc-c/xmlrpc_server_abyss.h> header file declares the interface to libxmlrpc_server_abyss.

You'll have to figure out where on your system this file lives and how to make your compiler look there for it. Or use xmlrpc-c-config.

Because the libxmlrpc, libxmlrpc_server, and libxmlrpc_abyss libraries are prerequisites, you'll also need their header files (xmlrpc.h, xmlrpc_server.h, and xmlrpc_abyss.h).

Linking The Library

The classic Unix name for the file containing the libxmlrpc_server_abyss library is libxmlrpc_server_abyss.a or libxmlrpc_server_abyss.so. The classic linker option to cause the library to be linked into your program is -l xmlrpc_server_abyss. These are hints; you'll have to modify this according to conventions of your particular platform. You'll also have to figure out where the library resides and how to make your linker look there for it.

You can use xmlrpc-c-config, specifying the "abyss-server" feature, to find out what libraries to link. This is designed to be used in a build program such as a make file. When properly installed, it tells exactly how to link on your particular system.

The following libraries are prerequisites of libxmlrpc_server_abyss, so you'll need to link them in too:

And remember that some static linkers care about the order in which you specify the libraries, with the prerequisite libraries having to come after the prerequiring library. xmlrpc-c-config is a good way to make sure you link all the prerequisites in the right order.

Example

A complete example of an XML-RPC server program that uses libxmlrpc_server_abyss is here.

About Abyss

Abyss is a general purpose HTTP server program. Because the most common use of HTTP is in web servers, Abyss is usually called a web server program. It is in the same class as the more famous Apache HTTP server program. It is much simpler than Apache, though.

Since XML-RPC is implemented over HTTP, all you need for an XML-RPC server is an Abyss server with a handler attached that knows how to execute an XML-RPC call. libxmlrpc_server's method registry provides all the logic you need to execute an XML-RPC call, so all you have to do is hook that up to Abyss. libxmlrpc_server_abyss gives the facilities to make that connection.

Styles Of Abyss-Based Server Programs

There are lots of ways you can build an XML-RPC server based on an Abyss HTTP server.

The most basic (but not easiest) is not to use any Xmlrpc-c XML-RPC facilities at all. Write your own Abyss request handler which takes an XML document from Abyss, interprets it as an XML-RPC call, and returns to Abyss an XML response. Register that request handler with Abyss using Abyss function calls. Create and start up your Abyss server using Abyss function calls.

The next step up in convenience would be to have your Abyss request handler use Xmlrpc-c's XML encoding and decoding tools to free you from having to know the XML-RPC protocol, and other libxmlrpc facilities to process the data easily.

The next step up would be to use an Xmlrpc-c method registry. Instead of writing your own Abyss request handler, call xmlrpc_server_abyss_set_handlers2(). That installs a request handler for your URI path (usually "/RPC2") that executes an XML-RPC call. Abyss delivers all HTTP requests for that URI path to that handler. To tell the handler what methods to execute, you build a method registry and identify it in xmlrpc_server_abyss_set_handlers2()'s arguments. (The Abyss server thus created rejects requests for any other URI path). Now you don't have to know how to write an Abyss request handler, but you still have to know other parts of the Abyss API.

The next step up would be to have Xmlrpc-c handle the details of the Abyss API as well. To do that, create a xmlrpc_server_abyss_t object with xmlrpc_server_abyss_create() and invoke the various methods of that object. The object sets up the Abyss server to execute XML-RPC methods using the method registry you supply. You never see Abyss itself.

What you give up for that convenience is that the xmlrpc_server_abyss_t object is not capable of exploiting many of the features of Abyss. For example, you can't have the server do any kind of authentication using this style.

One level up from that is to have the xmlrpc_server_abyss_t object under the covers as well. You just run xmlrpc_server_abyss(). It creates the xmlrpc_server_abyss_t object and runs the server. It returns when the server terminates. Because you have no handle for the server object, you can't control it from outside; in particular, you can't shut it down from another thread or signal handler.

There is another style in which you don't build a method registry separately, but rather use libxmlrpc_server_abyss facilities to add individual methods to a server instance. I don't recommend this style. It used to be (before Xmlrpc-c 1.01 - January 2005) the only one, so continues to exist for backward compatibility, but I find it to be more complex than the newer xmlrpc_server_abyss() style.

Running Your Own Abyss Server

If in your program you create your own Abyss server (ServerCreate()) using facilities of libxmlrpc_abyss, you can turn it into an XML-RPC server by using the facilities described in this section.

See the libxmlrpc_abyss manual for information on the basic Abyss interface, which your program must also use.

xmlrpc_server_abyss_set_handlers2()


void
xmlrpc_server_abyss_set_handlers2(TServer *         const srvP,
                                  const char *      const uriPath,
                                  xmlrpc_registry * const registryP);


This function adds to the Abyss server identified by srvP a request handler for the URI path uriPath. This handler executes a POST request as an XML-RPC call as defined by the method registry identified by registryP. It rejects requests with other HTTP methods for this URI path with an HTTP "Method Not Allowed" (code 405) failure.

"URI path" means the part of a Uniform Resource Identifier known as the "abs_path" in the URI spec (RFC 2396). In the example URI http://www.google.com/index.html, /index.html is the URI path.

In an HTTP POST request, the URI path becomes part of the POST header.

The customary URI path for an XML-RPC server is "/RPC2".

You must not call this twice for the same Abyss server.

This function also adds a default request handler, which handles requests to every URI path other than the specified. All that handler does is fail the request with an HTTP "file not found" (code 404) error.

You normally call this once per server. If you call it a second time, it adds another handler, later in Abyss' search order, for exactly the same requests, so it has no effect.

This function was new in Xmlrpc-c 1.06 (June 2006). With older Xmlrpc-c, use xmlrpc_server_abyss_set_handlers() or xmlrpc_server_abyss_set_handler().

Example

This is just a fragment showing the interface to xmlrpc_server_abyss_set_handlers2(). You'd have to add a bunch more Abyss library calls to make a complete server.


    #include <xmlrpc.h>
    #include <xmlrpc_server.h>
    #include <xmlrpc_server_abyss.h>
    #include <xmlrpc_abyss.h>

    xmlrpc_registry * registryP;
    xmlrpc_env env;
    TServer abyssServer;

    xmlrpc_env_init(&env);

    registryP = xmlrpc_registry_new(&env);

    xmlrpc_registry_add_method(
        &env, registryP, NULL, "sample.add", &sample_add, NULL);

    ServerCreate(&abyssServer, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);

    xmlrpc_server_abyss_set_handlers2(&abyssServer,
                                      "/RPC2",
                                      registryP);

For a complete example, see the program xmlrpc_loop_server in the examples directory of the Xmlrpc-c source tree.

xmlrpc_server_abyss_set_handlers()


void
xmlrpc_server_abyss_set_handlers(TServer *         const srvP,
                                 xmlrpc_registry * const registryP);


This is the same as xmlrpc_server_abyss_set_handlers2() except that the URI path is always "RPC2".

This function exists for backward compatibility. You should use xmlrpc_server_abyss_set_handlers2() instead if possible.

xmlrpc_server_abyss_set_handler()


void
xmlrpc_server_abyss_set_handler(xmlrpc_env *      const envP,
                                TServer *         const srvP,
                                const char *      const uriPath,
                                xmlrpc_registry * const registryP);

This is like xmlrpc_server_abyss_set_handlers2() (note that one is plural and other not), above, except that it does not set up a default handler. That means you can set up one of your own or let Abyss' default handling (basic serving of web pages) work.

You can use xmlrpc_server_abyss_set_default_handler() to set up the same default URI handler that xmlrpc_server_abyss_set_handlers2() does.

Also, you can call it as many times as you want and add handlers for as many URI paths as you want.

So this gives you lower level control.

One thing you can do with this function is have separate logical servers by registering handles for multiple URI paths, each with its own method registry. Of course, they could share a registry too.

Example

Refer to the example of xmlrpc_server_abyss_set_handlers2() above. The following is an example of how the last part of that example could be different to use xmlrpc_server_abyss_set_handler().



    xmlrpc_server_abyss_set_handler(
        &env, &abyssServer, "/RPC3", registryP);


xmlrpc_server_abyss_set_handler3()


void
xmlrpc_server_abyss_set_handler3(
    xmlrpc_env *                              envP,
    TServer *                                 srvP,
    const xmlrpc_server_abyss_handler_parms * parmsP,
    unsigned int                              parmSize);

This is like xmlrpc_server_abyss_set_handler() above, except that it gives you more options via lower level control.

Rather than the handler executing an XML-RPC call as it sees fit, you supply the a subroutine to execute the call. Xmlrpc-c takes care of all the HTTP stuff and passes the XML-RPC call (XML) to your subroutine. You parse the XML, interpret the XML-RPC, do the requested computation, and generate the XML-RPC response (XML). You can of course use Xmlrpc-c facilities to assist in interpreting and generating the XML-RPC messages.

parmsP points to a structure containing various options. parmSize is the size in bytes of that structure. More precisely, it is the amount of the structure that you have filled with meaningful information. The definition of this structure is below.

For parmSize, use the XMLRPC_AHPSIZE macro as in the example. This macro gives the size of the xmlrpc_server_abyss_handler_parms structure up through the member you name. Name the last member in the structure that you set. You must set every member up through that one, but for every member after it, xmlrpc_server_abyss_set_hanlder3() will assume a default.

The reason it's important to use XMLRPC_AHPSIZE instead of just setting all the members and using sizeof(struct xmlrpc_server_abyss_handler_parms) is forward compatibility. Future versions of libxmlrpc_server_abyss_set_handler3 might add new members, and you want the server program you write today, whether you compile it today or then, to work properly with that future library.

You must supply at least the xml_processor, xml_processor_arg, and xml_processor_max_stack parameters.

For an example of using xmlrpc_server_abyss_set_handler3(), see libxmlrpc_server_abyss++ source code. That library uses an XML processor that executes an XML-RPC using the C++ version of a method registry (libxmlrpc_server++) rather than the C version (libxmlrpc_server).

xmlrpc_server_abyss_set_handler3() does not set up an Abyss default URI handler. So you should normally call xmlrpc_server_abyss_set_default_handler() too.

xmlrpc_server_abyss_set_handler3() was new in Xmlrpc-c Release 1.25 (December 2010). Before that, you can use xmlrpc_server_abyss_set_handler2() and if you need more control than that, you have to abandon libxmlrpc_server_abyss altogether and have your own code do the things it does.

Handler parameters

This section describes the parameters in the xmlrpc_server_abyss_handler_parms struct, which comprises the parameters of a xmlrpc_server_abyss_set_handler3() call.

Synopsis:


typedef void
xmlrpc_call_processor(xmlrpc_env *        envP,
                      void *              processorArg,
                      const char *        callXml,
                      size_t              callXmlLen,
                      TSession *          abyssSessionP,
                      xmlrpc_mem_block ** responseXmlPP);


typedef struct {
    xmlrpc_call_processor * xml_processor;
    void *                  xml_processor_arg;
    size_t                  xml_processor_max_stack;
    const char *            uri_path;
    xmlrpc_bool             chunk_response;
    const char *            allow_origin;
        /* NULL means don't answer HTTP access control query */
    xmlrpc_bool             access_ctl_expires;
    unsigned int            access_ctl_max_age;
} xmlrpc_server_abyss_handler_parms;


xml_processor is your XML processor, described above. xml_processor_arg is the argument that the Abyss server passes to your XML processor.

xml_processor_max_stack is the maximum number of bytes of stack space your XML processor will use. It is unspecified what happens if it attempts to use more.

The rest of the parameters have the same meaning as the identically named server parameters.

xmlrpc_server_abyss_set_handler2()


typedef void
xmlrpc_call_processor(xmlrpc_env *        const envP,
                      void *              const processorArg,
                      const char *        const callXml,
                      size_t              const callXmlLen,
                      TSession *          const abyssSessionP,
                      xmlrpc_mem_block ** const responseXmlPP);

void
xmlrpc_server_abyss_set_handler2(
    TServer *         const srvP,
    const char *      const uriPath,
    xmlrpc_call_processor   xmlProcessor,
    void *            const xmlProcessorArg,
    size_t            const xmlProcessorMaxStackSize,
    xmlrpc_bool       const chunkResponse);

This is like xmlrpc_server_abyss_set_handler3() above, except that it doesn't give you as many options. It is obsolete.

xmlProcessor, xmlProcessorArg, and xmlProcessorMaxStackSize are equivalent to the xml_processor, xml_processor_arg, and xml_processor_stack_size parameters, respectively, of xmlrpc_server_abyss_set_handler3().

xmlrpc_server_abyss_set_handler2() was new in Xmlrpc-c Release 1.19 (June 2009). Before that, the only way you can have your own XML processor is to abandon libxmlrpc_server_abyss altogether and have your own code do the things it does.

xmlrpc_server_abyss_set_default_handler()

This function sets up an Abyss default URI handler suitable for an XML-RPC server. An Abyss default URI handler is the handler that handles HTTP requests that no other handler registered with Abyss claims.

Typically, you'll register one handler for a POST of URI http://RPC2 using one of the other libxmlrpc_server_abyss subroutines and no one has any business sending any other kind of request to the server. So the default URI handler that xmlrpc_server_abyss_set_default_handler() registers is one that rejects the request with a 404 HTTP error response with a message stating that the server is an XML-RPC server.

xmlrpc_server_abyss_set_handlers() and xmlrpc_server_abyss_set_handlers2() register this same default URI handler for you, so you don't need to call this subroutine too.

xmlrpc_server_abyss_set_default_handler() was new in Xmlrpc-c Release 1.19 (June 2009).

xmlrpc_server_abyss_run()

This is an old, deprecated interface. It is a utility extension to Abyss' ServerRun(). It sets up some signal handlers and daemonizes the process before calling ServerRun().

It's deprecated because this is not a healthy way to organize a system. Setting up signal handlers and daemonizing have nothing to do with XML-RPC or any essential purpose of Xmlrpc-c. Furthermore, daemonizing should really be done by an entirely separate program.

If you have an old program that uses xmlrpc_server_abyss_run() and want to update it, see Daemonizing for discussion of how you should get your program daemonized, and use plain ServerRun(). Or check out the easier Abyss under the covers alternative and remove all the Abyss calls from your program.

Method Function Services

Within an XML-RPC method function, you can get information from the Abyss server about the circumstances of the XML-RPC call, using certain Abyss functions.

SessionGetRequestInfo can give you some information about the HTTP headers that came with the call, while SessionGetChannelInfo() can tell you how the call got to you. In particular, SessionGetChannelInfo() typically tells you the IP address and TCP port number of the HTTP client, and therefore the XML-RPC client.

In order to use these Abyss services, your XML-RPC method function must know the handle of the Abyss session that is handling the RPC. Abyss supplies that to your method function as the callInfo argument. I.e. callInfo is a TSession *. See How To Write A Method Function.

Example:


    static xmlrpc_value *
    demo_noop(xmlrpc_env *   const envP, 
              xmlrpc_value * const paramArrayP,
              void *         const serverInfo,
              void *         const channelInfo) {
        
        TSession * const abyssSessionP = channelInfo;
        struct abyss_unix_chaninfo * channelInfoP;
        struct sockaddr_in * sockAddrInP;
        unsigned char * ipAddr;  /* 4 byte array */
    
        SessionGetChannelInfo(abyssSessionP, (void*)&channelInfoP);
    
        sockAddrInP = (struct sockaddr_in *) &channelInfoP->peerAddr;
    
        ipAddr = (unsigned char *)&sockAddrInP->sin_addr.s_addr;
    
        printf("RPC is from IP address %u.%u.%u.%u\n",
               ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
    
        return xmlrpc_nil_new(envP);
    }
    
    xmlrpc_registry_add_method2(
        &env, registryP, "demo.noop", &demo_noop, NULL, NULL, NULL);

For a complete example, see the program xmlrpc_loop_server in the examples directory of the Xmlrpc-c source tree.

Having Abyss Under The Covers

This section describes Xmlrpc-c facilities for running an Abyss server without your program actually seeing any Abyss interfaces. This means you don't have any flexibility in the configuration of the Abyss server (other than that you still get to supply the "abyss.conf" Abyss configuration file), but it saves you having to learn anything about the Abyss API.

There are two versions of this facility: one that's easier to learn and less code, and one that lets you do more.

The simpler one is the anonymous server facility. You can run a server with a single library call (to xmlrpc_server_abyss()), but because you don't get a handle for the server, you can't terminate it from outside (i.e. from a signal handler or a separate thread). The only way to terminate the server is have it execute an RPC that terminates it.

In the less simple version, you create a server object separately from running it. You have a handle for the server object, which you can use in a signal handler or another thread to terminate the server.

Anonymous Server

This is the simplest way to run an XML-RPC server. It consists of a single library subroutine: xmlrpc_server_abyss().

xmlrpc_server_abyss()


void
xmlrpc_server_abyss(xmlrpc_env *                const envP,
                    xmlrpc_server_abyss_parms * const parmP,
                    unsigned int                const parmSize);

This function runs an Abyss server, which functions as a complete XML-RPC server.

This is equivalent to the following sequence:

This is designed to be run as the only thread in a process, and owning the entire environment (e.g. not in a library). If you want to run an XML-RPC server as part of a larger process, you should use an explicit xmlrpc_server_abyss_t object.

Example:

This is just a fragment showing how to call xmlrpc_server_abyss(). This example is a complete program that uses xmlrpc_server_abyss().


#include <xmlrpc.h>
#include <xmlrpc_server.h>
#include <xmlrpc_server_abyss.h>

    xmlrpc_server_abyss_parms serverparm;
    xmlrpc_registry * registryP;
    xmlrpc_env env;

    xmlrpc_env_init(&env);

    registryP = xmlrpc_registry_new(&env);

    xmlrpc_registry_add_method(
        &env, registryP, NULL, "sample.add", &sample_add, NULL);

    serverparm.config_file_name = NULL;
    serverparm.registryP = registryP;
    serverparm.port_number = 8080;
    serverparm.log_file_name = "/tmp/xmlrpc_log";

    printf("Starting XML-RPC server...\n");

    xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));


The parmP and parmSize arguments are the same as those of xmlrpc_server_abyss_create.

But: note that there are two styles of providing parameters: an old deprectaed one, and a new preferred one. Before Xmlrpc-c Version 1.02 (April 2005), the old style is the only one available.

xmlrpc_server_abyss() was new in Xmlrpc-c 1.01.

Explicit xmlrpc_server_abyss_t object

This is an explicit object oriented interface where you have a visible xmlrpc_server_abyss_t object. You have access to methods of that object that not only run the server, but terminate it as well.

This entire facility (the visible xmlrpc_server_abyss_t object) was new in Xmlrpc-c 1.14 (March 2008). Before that, you must use the anonymous server facility.

Example:


    xmlrpc_server_abyss_parms serverparm;
    xmlrpc_registry * registryP;
    xmlrpc_env env;
    xmlrpc_server_abyss_t * serverP;
    xmlrpc_server_abyss_sig * oldHandlersP;

    xmlrpc_env_init(&env);

    xmlrpc_server_abyss_global_init(&env);

    registryP = xmlrpc_registry_new(&env);

    xmlrpc_registry_add_method(
        &env, registryP, NULL, "sample.add", &sample_add, NULL);

    serverparm.config_file_name = NULL;
    serverparm.registryP = registryP;
    serverparm.port_number = 8080;
    serverparm.log_file_name = "/tmp/xmlrpc_log";

    xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(registryP),
                               &serverP);

    xmlrpc_server_abyss_setup_sig(&env, serverP, &oldHandlersP);

    printf("Starting XML-RPC server...\n");

    xmlrpc_server_abyss_run_server(&env, &serverP);

    xmlrpc_server_abyss_restore_sig(oldHandlersP);

    free(oldHandlersP);

    xmlrpc_server_abyss_destroy(serverP);

    xmlrpc_server_abyss_global_term(&env);

In the example above, we assume every function succeeds, because it makes the code easier to read. In real life, you will want to check the env variable after each function call.

A buildable, working example like that above is in the Xmlrpc-c source distribution, in the examples directory with the name interrupted_server.

xmlrpc_server_abyss_global_init()

Example:


    xmlrpc_server_abyss_global_init(&env);

Prototype:


    void
    xmlrpc_server_abyss_global_init(xmlrpc_env * const envP);

This is libxmlrpc_server_abyss's global initialization function.

See Global Constants for an explanation of why you need these and how to use them.

This is required only if you use explicit xmlrpc_server_abyss_t objects.

xmlrpc_server_abyss_global_term()

Example:


    xmlrpc_server_abyss_global_term();

Prototype:


    void
    xmlrpc_server_abyss_global_term(void);

This is libxmlrpc_server_abyss's global termination function.

See Global Constants for an explanation of why you need these and how to use them.

xmlrpc_server_abyss_create()

This is a constructor for the xmlrpc_server_abyss_t object class. The object it creates doesn't perform any server functions by itself; you must call its xmlrpc_server_abyss_run_server method to run the server.

Prototype:


    void
    xmlrpc_server_abyss_create(
        xmlrpc_env *                      const envP,
        const xmlrpc_server_abyss_parms * const parmsP,
        unsigned int                      const parmSize,
        xmlrpc_server_abyss_t **          const serverPP);

See the example above.

envP is an error environment variable pointer.

parmsP is a pointer to a structure that contains the parameters of the server. parmSize is the size in bytes of that structure. More precisely, it is the amount of the structure that you have filled with meaningful information. The definition of this structure is below.

For parmSize, use the XMLRPC_APSIZE macro as in the example. This macro gives the size of the xmlrpc_server_abyss_parms structure up through the member you name. Name the last member in the structure that you set. You must set every member up through that one, but for every member after it, xmlrpc_server_abyss() will assume a default.

The reason it's important to use XMLRPC_APSIZE instead of just setting all the members and using sizeof(struct xmlrpc_server_abyss_parms) is forward compatibility. Future versions of libxmlrpc_server_abyss might add new members, and you want the server program you write today, whether you compile it today or then, to work properly with that future library.

You must supply at least the config_file_name parameter (just set it to NULL) and the registryP parameter. All the rest default if your parmSize indicates they are not present.

The function returns as *serverPP the handle for the newly created server object (assuming the function succeeds). Use this handle as an argument to the other functions that serve as methods of this object.

xmlrpc_server_abyss_destroy()

This is the object destructor. It destroys an xmlrpc_server_abyss_t object.

Do not call this while any other method is running. That means you cannot call it while the server is running; you must terminate the server first, to make xmlrpc_server_abyss_run_server() return.

Prototype:


void
    xmlrpc_server_abyss_destroy(xmlrpc_server_abyss_t * const serverP);

serverP is the handle of the object you are destroying, returned by xmlrpc_server_abyss_create().

xmlrpc_server_abyss_run_server()

This function runs the server. It is the heart of your server program.

The server listens on the TCP port you specified when you created the xmlrpc_server_abyss_t object and responds to HTTP requests (which are normally XML-RPC requests) ad infinitum. xmlrpc_server_abyss_run_server() returns when the server terminates. It handles multiple requests simultaneously.

The server executes HTTP requests with the same handlers that xmlrpc_server_abyss_set_handlers2() installs. See the documentation of that function for details on how the server implements HTTP requests. The handlers use the method registry you supply via xmlrpc_server_abyss() arguments.

Because the server can execute multiple RPCs at the same time in separate threads, it is important that the method functions in your registry be thread safe. If your methods have to be called serially, use a lower level style of Abyss server where you control execution of RPCs more directly instead. For example, use a style in which you create your own Abyss server object (using libxmlrpc_abyss) and call the Abyss function ServerRunOnce() in a loop (like the xmlrpc_loop_server example program in the Xmlrpc-c source tree).

Abyss' "server root" directory is the current directory.

The function returns when the server terminates.

Prototype:


void
    xmlrpc_server_abyss_run_server(xmlrpc_env *            const envP,
                                   xmlrpc_server_abyss_t * const serverP);

envP is an error environment variable pointer.

serverP is the handle of the server you are running, returned by xmlrpc_server_abyss_create().

xmlrpc_server_abyss_terminate()

This function causes a server that is running to terminate, and to terminate immediately if it starts running in the future.

Prototype:


void
    xmlrpc_server_abyss_terminate(xmlrpc_env *            const envP,
                                  xmlrpc_server_abyss_t * const serverP);

envP is an error environment variable pointer.

serverP is the handle of the server you are terminating, returned by xmlrpc_server_abyss_create().

Because a program that starts a server running does not regain control as long as the server is running, this is meant to be called from a separate thread or signal handler.

If you have a signal handler that calls xmlrpc_server_abyss_terminate() and the process receives a signal while the server is running, the server will terminate (xmlrpc_server_abyss_run_server() will return) soon after the signal handler returns. If the server is processing an RPC when the process receives the signal, it will not terminate until it is done with that RPC.

You can also call this from an XML-RPC method function, as long as that function is running in the same process that waits for and accepts new connections. If, on the other hand, you are running Abyss in a mode in which it processes connections in the background and you have a system in which it does that by way of a Unix fork (which is unusual in modern times), a xmlrpc_server_abyss_terminate() from inside an XML-RPC method function has no effect.

If you are running the server in a mode in which it processes connections in the background (i.e. in separate threads or processes), xmlrpc_server_abyss_terminate() affects only the foreground thread that waits for and dispatches RPCs. Any background thread that is executing an RPC continues normally to completion in its own time.

This function was new in Xmlrpc-c 1.14 (March 2008). Before that, the only way to terminate a server is to execute a system.shutdown RPC.

xmlrpc_server_abyss_reset_terminate()

This function resets the termination state of a server. While a server is in the terminated state (as set by xmlrpc_server_abyss_terminate(), it will terminate at its next opportunity if it is running and if you run it in the future, it will terminate immediately. This function resets that state so that the server will not terminate.

There probably is no practical way to use this to take back a previous termination request so that the server keeps running; it's intended use is with a server that has already terminated (by request), when you want to run it again.

Prototype:


void
    xmlrpc_server_abyss_reset_terminate(xmlrpc_env *            const envP,
                                        xmlrpc_server_abyss_t * const serverP);

envP is an error environment variable pointer.

serverP is the handle of the server you are resetting, returned by xmlrpc_server_abyss_create().

xmlrpc_server_abyss_setup_sig()

This function helps you set up signal handling as the xmlrpc_server_abyss_t object requires.

Prototype:


void
    xmlrpc_server_abyss_setup_sig(
        xmlrpc_env *               const envP,
        xmlrpc_server_abyss_t *    const serverP,
        xmlrpc_server_abyss_sig ** const oldHandlersPP);

envP is an error environment variable pointer.

serverP is the handle of the server you want to notify of signal arrival, returned by xmlrpc_server_abyss_create(). This object must continue to exist as long as the signal handlers are in place, so call xmlrpc_server_abyss_restore_sig() before you destroy it.

The function returns as *oldHandlersPP a pointer to a description of the state of signal handling before the call. You can use this later with xmlrpc_server_abyss_restore_sig() to put it back the way it was. This points to newly malloc'ed storage. You must free it when you are done with it.

xmlrpc_server_abyss_restore_sig()

This function restores the state of signal handling to what it was before you called xmlrpc_server_abyss_setup_sig().

Strictly speaking, you need to make sure that the signal handling state just before you call xmlrpc_server_abyss_restore_sig() is the same as it was just after you called xmlrpc_server_abyss_setup_sig(), or you may get unexpected results. I.e. you need to manage signal handling state in a stack fashion.

Prototype:


    void
    xmlrpc_server_abyss_restore_sig(
        const xmlrpc_server_abyss_sig * const oldHandlersP);

oldHandlersP is the pointer returned by your call to xmlrpc_server_abyss_setup_sig().

xmlrpc_server_abyss_t Parameters

This section describes the parameters in the xmlrpc_server_abyss_parms struct, which comprises the parameters of a xmlrpc_server_abyss_t object. You use this structure with xmlrpc_server_abyss_create() and xmlrpc_server_abyss().

Synopsis:


typedef struct {
    const char *            config_file_name;
    xmlrpc_registry *       registryP;
    runfirstFn              runfirst;
    void *                  runfirst_arg;
    unsigned int            port_number;
    const char *            log_file_name;
    unsigned int            keepalive_timeout;
    unsigned int            keepalive_max_conn;
    unsigned int            timeout;
    xmlrpc_bool             dont_advertise;
    xmlrpc_bool             socket_bound;
    xmlrpc_socket           socket_handle;
    const char *            uri_path;
    xmlrpc_bool             chunk_response;
    xmlrpc_bool             enable_shutdown;
    const char *            allow_origin;
    xmlrpc_bool             access_ctl_expires;
    unsigned int            access_ctl_max_age;
    const struct sockaddr * sockaddr_p;
    socklen_t               sockaddrlen
    unsigned int            max_conn;
    unsigned int            max_conn_backlog;
    size_t                  max_rpc_mem;
} xmlrpc_server_abyss_parms;


There are two styles of providing parameters possible with struct xmlrpc_server_abyss_parms(): an old deprecated one, and a new preferred one. We describe the preferred one here. The deprecated one is described below.

config_file_name

Set this to NULL. That is what specifies that you're using the preferred style instead of the deprecated "config file"one.

This parameter is required.

registryP

This is a handle for a method registry. This registry is what determines what XML-RPC methods are defined by the server, i.e. it is the meat of the XML-RPC server. Use the libxmlrpc_server library to build a method registry appropriate for your server. This is a mandatory option (parmSize must be large enough to include it).

Any registration of a shutdown function in this registry has no effect. This oddity is an artifact of the evolution of Xmlrpc-c. The only thing that controls shutdown is the enable_shutdown parameter. If you want to effectively register a shutdown function, use a lower level interface (not xmlrpc_server_abyss) in which you supply your own Abyss server.

On a Unix system, where xmlrpc_server_abyss() starts the server in a new process, the server gets a copy of the registry, so nothing you do to it after xmlrpc_server_abyss() returns affects the server. (On other systems, xmlrpc_server_abyss() never returns, so the issue is moot).

This parameter is required.

port_number

This is the TCP port number on which the server will listen and accept connections for RPCs. See Server Address Parameters for details.

If you specify a reserved port number, the program must have the privilege required to bind it (on a Unix-like system, you typically must have superuser privilege to accept connections to a port number less than 1024).

socket_bound

This boolean parameter is true (nonzero) to indicate that you are providing an already bound stream socket on which the server is to listen for connections from clients. See Server Address Parameters for details.

When you specify true for socket_bound, you must supply a proper value for socket_fd.

This option was new in Xmlrpc-c 1.04 (November 2005). Before that, xmlrpc_server_abyss() always created its own socket.

socket_fd

This option identifies the socket on which the server is to listen for connections from clients (on a Unix system, it identifies it by file descriptor).

This is meaningful only when socket_bound is true.

The socket you supply must be a stream socket, and must be bound and ready to listen (in particular, it cannot be already listening or connected).

This option was new in Xmlrpc-c 1.04 (November 2005). Before that, xmlrpc_server_abyss() always created its own socket.

sockaddr_p

This option indicates the full address (e.g. IP address and TCP port number) on which the server will listen and accept connections for RPCs. See Server Address Parameters for details.

The value is a pointer to a conventional POSIX socket address structure.

When you specify sockaddr_p, you must also specify sockaddrlen, the size in bytes of the structure pointed to.

This option also incidentally specifies the network protocol to use, because libxmlrpc_server_abyss infers that from the socket address family. This works because it happens that every known network protocol uses addresses of a specific family not used by any other protocol; for example only an IP Version 4 network uses IP Version 4 network addresses.

This option was new in Xmlrpc-c 1.30 (March 2012).

sockaddrlen

This option goes with sockaddrlen.

This option was new in Xmlrpc-c 1.30 (March 2012).

uri_path

This names the URI path of the XML-RPC server. For example, if a client will make an XML-RPC call using the URL "http://www.google.com/RPC2", the URI path is "/RPC2". The Abyss server will process as an XML-RPC call anything POSTed to that URI path and reject requests to any other URI path.

The default (effective if this member isn't present or is NULL) is "/RPC2".

For more information on what a URI path is, see xmlrpc_server_abyss_set_handlers2().

This parameter was new in Xmlrpc-c 1.06 (June 2006). Before that, the URI path is always "/RPC2".

max_conn

This is the maximum number of simultaneous TCP connections the server will maintain. When there are already this many, the server will not accept additional TCP connections from the operating system

In the simplest case, a TCP connection is an RPC, which means this is the maximum number of clients that can simultaneously perform RPCs. However the client and server may agree to perform multiple RPCs on a single connection and to facilitate that, to keep a TCP connection open in anticipation of a future RPC. See keepalive_timeout and keepalive_max_conn.

While the server is not accepting connections because of this limit, the operating system still accepts TCP connections on the server's behalf and queues them. See max_conn_backlog.

A value of zero requests the default.

The default is 15.

This option was new in Xmlrpc-c 1.32 (September 2012).

max_conn_backlog

This is the maximum number of TCP connections the operating system will accept on the server's behalf without the server accepting them from the operating system. The server accepts TCP connections (presumably intended to be RPCs) and queues them for the server to accept when it is ready. If the number queued reaches this limit, the operating system refuses, via the TCP protocol, any additional connection attempts.

Because the server actively executes RPCs on connections it has accepted from the operating system, but not on those in the operating system backlog, you can generally get better throughput with a high max_conn than with a high max_conn_backlog. But if your server is overloaded, having too many RPCs executing at once can cause thrashing, in which case a lower max_conn improves performance and a high max_conn_backlog makes sure you don't lose RPCs. But note that max_conn_backlog is effective only at accomodating bursts of RPCs. If the RPCs arrive at a sustained rate higher than the server can handle, a larger queue only hurts.

A value of zero requests the default.

The default is 15.

This option was new in Xmlrpc-c 1.32 (September 2012).

max_rpc_mem

This is the maximum amount of memory, in bytes, the server can use to process an RPC. But it counts only certain uses of memory: those that are unpredictable, especially those under control of the client. The purpose of this limit is to prevent a client from using more than its share of the server's memory and thereby deny service to other clients.

There are lots of other uses of memory that are not controlled by this limit, but they are all insignificant.

A value of zero requests the default.

The default is no limit.

This option was new in Xmlrpc-c 1.44 (December 2015).

keepalive_timeout

After the server has received an XML-RPC call and sent the response, it keeps the HTTP connection open for a while so that the client may send another XML-RPC call without starting up a new connection, thus saving time and resources.

This parameter is the maximum time in seconds that the server allows a connection to be open between RPCs. If the client does not send another call or close the connection within this period, the server closes the connection.

This is also the maximum time the server allows a connection to be open before the first data arrives from the client. If a client connects and then doesn't start sending HTTP headers soon enough, it sees the connection close.

A value of zero requests the default.

The default is 15 seconds.

keepalive_max_conn

This is the maximum number of RPCs that the server will execute on a single connection. Once the server has responded to this many, it closes the connection and the client must create a new connection to do any more.

A value of zero requests the default.

The default is 30.

timeout

This is the maximum time in seconds the server will wait for the client to do anything while processing an RPC. This does not apply to waiting between RPCs (see keepalive_timeout).

A value of zero requests the default.

The default is 15 seconds.

enable_shutdown

This logical value says that the server should shut down when a client executes a system.shutdown system method.

The default is false, so that a system.shutdown call always fails, with a fault string indicating that there is no way to shut down this server.

If you set this to true, any client that can execute an RPC on this server can shut it down.

Note that if you use a lower level interface (not xmlrpc_server_abyss()), in which you supply your own Abyss server, you can set your own shutdown handler in the XML-RPC method registry (this is a special setting, not the registration of the system.shutdown method - see xmlrpc_set_shutdown) and your shutdown handler can decide whether to comply with a system.shutdown request. It might do it based on the IP address of the client, for example. But with xmlrpc_server_abyss(), your only choices are system.shutdown for everybody or system.shutdown for nobody.

If you create a xmlrpc_server_abyss_t with a registry in which you have set a shutdown function, that setting has no effect. The shutdown function does not get called.

This parameter did not exist before Xmlrpc-c 1.07 (October 2006). Before that, system.shutdown never succeeds.

dont_advertise

The server has a feature wherein it can tell querents things about itself, such as what methods is knows. The feature is called "introspection." See System Methods. By default, the feature is available, but if you set dont_advertise to nonzero, it isn't. In that case, the introspection methods do not exist to a client.

Supplying the information for introspection is a separate matter. If you allow introspection, but don't supply any information when you create your registry, the client can execute the method, but won't get any information. Similarly, if you supply introspection method, but set dont_advertise true, the information you supplied will be useless.

chunk_response

This logical value says that the server should chunk responses, in the HTTP sense, if possible. By default, the server never chunks a response.

Chunking is an HTTP concept in which the HTTP server sends a response in pieces, each piece preceded by an indication of its size. When an HTTP server sends a chunked response, it doesn't have to say at the beginning of the response how big the whole response is. So it might compute the response as it sends it, not knowing until it reaches the end how big it is.

While this function makes the server chunk the response, the server in all cases includes the required content-length header, per XML-RPC.

When you use this option, the server is not a legal XML-RPC server. That's because an XML-RPC server must be an HTTP server and also include a content-length header in every response, but an HTTP server cannot include a content-length header in a chunked response.

It's hard to see how chunking could be useful in XML-RPC, because not only is a response usually pretty small, but the XML-RPC standard requires a content-length header at the beginning of the response that gives the whole response's size. And of course, being nonstandard XML-RPC, the client might not be able to handle it. (An Xmlrpc-c client can, though).

This parameter was new in Xmlrpc-c 1.06 (June 2006). In Xmlrpc-c 1.05, the response is never chunked, and before that sometimes it is and sometimes it isn't, folowing a strange and inexplicable policy partly based on whether the server is keeping alive the connection.

allow_origin

This option is part of HTTP access control, which is a feature that helps with the security exposure of cross-site scripting. This is the problem where a user on network node C browses a web site on server S and S sends a script for C to execute. The script says to perform an RPC on Xmlrpc-c server X. The Xmlrpc-c server may accord that request special privilege because it comes from C, without knowing that the user at C doesn't really know he's making the request. To solve this problem, the browser on C may just refuse to honor any requests in any script to perform an RPC anywhere, but this also shuts out legitimate scripting. So HTTP provides the browser on C a way to ask X if it would be OK to perform an RPC from a third party and if X says there's no cross-scripting security exposure if it does, then and only then the client honors the request from S's script to perform an RPC on X.

If you don't specify allow_origin or specify it as a null pointer, the Abyss server, when asked, refuses to OK any cross-scripting. Specifically, it does not include any of the HTTP access control header fields in its response to an HTTP Options method request (or any other request).

If you specify non-null allow_origin, the server includes an Access-Control-Allow-Origin field in its responses. The value of the parameter is the verbatim value for the HTTP header field value, so look at HTTP specifications for details. Briefly, it is a list of third party servers whose scripts the client should trust to perform RPCs on this server. The most useful value is "*", which means all third party servers.

When the server includes an Access-Control-Allow-Origin field in its response, it also includes an Access-Control-Allow-Methods header saying the client should allow the POST method (all XML-RPC calls use the POST method), and Access-Control-Allow-Headers headers that tell the client to allow Content-Type and Content-Length headers, two headers that are essential to any XML-RPC call.

This parameter was new in Xmlrpc-c 1.25 (December 2010). Before that, the server fails any attempt to get option information, responding with a 405 Method Not Allowed error to any Options request and never includes HTTP access control header fields in any other response. Before Xmlrpc-c 1.39 (September 2014), the server does not send the Access-Control-Allow-Headers headers.

access_control_expires

This option is part of HTTP access control and has effect only when allow_origin is non-null.

The option value is logical and indicates that the permissions the server gives for third party RPCs expires after a certain time -- the client should request permission again if it wants to perform third party RPCs after that. If the value is true, the Abyss server includes in its response to an HTTP request an Access-Control-Max-Age header field. Otherwise, the server does not include such a header field.

access_control_max_age controls the expiration period.

Default is false.

This parameter was new in Xmlrpc-c 1.25 (December 2010) along with all HTTP access control participation.

access_control_max_age

This option is part of HTTP access control and has effect only when allow_origin is non-null.

This option is meaningless when access_control_expires is false.

The value of this option is the time in seconds that permissions the server gives out are good. The server includes this information in its Access-Control-Max-Age HTTP header field in response to an HTTP request.

This parameter was new in Xmlrpc-c 1.25 (December 2010) along with all HTTP access control participation.

log_file_name

This names the file that Abyss will use for a log file. If this member isn't present (according to parmSize) or is null, Abyss won't have a log file.

runfirst, runfirst_arg

These are meaningless (they're for the config file style interface).

Server Address Parameters

libxmlrpc_server_abyss gives you various ways to determine what the address of your server will be, i.e. on what IP address and TCP port it will listen for connections from clients. You choose one via server parameters.

The server listens continually for connections attempted to the given address, which causes the operating system to accept connections (up to some limit) and queue them. When you subsequently call the relevant methods, the server processes those connections.

Note that all the server parameters we mention here are optional; when you create a server object, you say how long your server parameter structure is and that determines which parameters you have specified.

In the simplest method, you specify nothing in the parameters, and the server defaults to listening on all IP Version 4 network interfaces (i.e. as every IP Version 4 address the system has), TCP Port 8080.

If you don't want to use Port 8080, specify a different port number with the port_number server parameter. A zero value is the same as not specifying the parameter; there is no way to specify Port 0.

If you want to limit your server to one IP address (one network interface) or put it on an IP Version 6 network, specify a sockaddr_p parameter. Its value indicates a conventional POSIX socket address structure. You must always accompany a sockaddr_p parameter with sockaddrlen.

This is a tricky data structure and we won't go into detail on how to use it here because that trickiness is not specific to Xmlrpc-c. If you know how to code a program using a POSIX bind() call, you can code one using sockaddr_p and sockaddrlen.

When you specify sockaddr_p, any port_number parameter you specify is meaningless.

A null pointer for sockaddr_p is the same as not specifying it.

Finally, you can take the choice of address out of libxmlrpc_server_abyss's hands completely and just supply a POSIX socket of your own, which is already bound to the desired address. To do that, specify the file descriptor of the socket with a socket_fd parameter and specify the socket_bound server parameter flag.

One reason you would want to supply a socket, as opposed to just letting the server create one, is that you want the server to listen on a reserved port and don't want your program to have the privilege necessary to bind a reserved port. In that case, you can have a privileged program bind the port, drop privileges, and then run your program.

When you specify socket_bound, any sockaddr_p or port_number parameter you specify is meaningless.

Server Termination

xmlrpc_server_abyss() or xmlrpc_server_abyss_run_server() returns when the server terminates. The server terminates when it executes an RPC of the system.shutdown system method or when you call the xmlrpc_server_abyss_t object's xmlrpc_server_abyss_terminate() method.

For more information on using system.shutdown, see the enable_shutdown server parameter.

xmlrpc_server_abyss_terminate() is usable only when you use an explicit xmlrpc_server_abyss_t object, which became possible in Xmlrpc-c 1.14 (March 2008).

Before Xmlrpc-c 1.06 (June 2006), the server does not implement system.shutdown and there is no way to shut down the server, so xmlrpc_server_abyss() never returns (except if it fails to start the server at all). And before Xmlrpc-c 1.14 (March 2008), system.shutdown can't actually interrupt anything the server is doing -- the server won't notice it is supposed to terminate as long as it is asleep waiting for an RPC. So you normally have to call it twice -- once to request shutdown, and once to wake up the master thread so it notices the request.

The same is true on Windows until Xmlrpc-c 1.25 (December 2010).

Signals

There are some signals that affect the proper operation of an Abyss server. Because signals are process-global entities, libxmlrpc_server_abyss cannot take care of these for you. However, the library does provide convenience functions that do what most programs want and saves you a lot of work.

One important class of signals is SIGPIPE. By default, a Unix operating system sends a SIGPIPE signal to your process when it attempts to write to a socket that has been closed from the other end. By default, that signal then causes the OS to terminate your process. Writing to sockets is how an Abyss server sends responses to clients, so this means if a client hangs up on you, you die. Therefore, you almost certainly want to tell the OS not to send these signals. The way you do that is rather messy: you call a system function that ostensibly tells the OS to ignore signals of class SIGPIPE, but it really tells the OS to handle closed sockets in a whole different way that doesn't involve signals.

xmlrpc_server_abyss_setup_sig() does that.

Another important class is SIGCHLD. Some versions of libxmlrpc_abyss generate servers that fork a new process to handle each HTTP request. This is not the usual way (normally, it uses POSIX or Windows threads), but some systems need it. On such a system, when one of these processes dies, the OS sends a SIGCHLD signal to the Abyss dispatcher process, which is the process from which you called xmlrpc_server_abyss_run_server().

Abyss generally needs to know that this signal arrived, so (if you have a forking Abyss) you need to set up a signal handler for SIGCHLD signals and have it call ServerHandleSigchld(). You also must call xmlrpc_server_abyss_use_sigchld() before you run the Abyss server to declare that your program intends to deliver those signals thusly. If you don't have the signal handler, and therefore don't call xmlrpc_server_abyss_use_sigchld(), Abyss will make do with polling occasionally to see who is still alive. This hurts performance and resource usage, so you should work that way only if signals just don't work in your environment.

The SIGCHLD handler must reap the dead child; that's not part of ServerHandleSigchld()'s responsibilities.

Note that it's OK to pass all the SIGCHLD signals to Abyss, whether they are for an Abyss child or not. Abyss ignores SIGCHLD signals from a processes that don't belong to it. xmlrpc_server_abyss_setup_sig() takes care of all that for you.

Bear in mind that signal behavior is global. What you set up for the benefit of Abyss may affect non-Abyss code in the same process.

There is no such thing as a signal on Windows, so you don't need to worry about them. On Windows, xmlrpc_server_abyss_setup_sig() does nothing.

But xmlrpc_server_abyss_setup_sig() is not for everyone. If your process receives SIGCHLD signals that don't belong to Abyss, and needs to see them, you can't use xmlrpc_server_abyss_setup_sig() because it would swallow up all SIGCHLD signals. You must set up your own signal handlers as described above in that case.

Daemonizing

You probably want your XML-RPC server to run as a daemon, quite independent of the process that started it running. xmlrpc_server_abyss() does nothing to separate the server from the process that invoked it, so you'll want to take care of that before calling it. In fact, while it's customary for Unix server programs to daemonize themselves, it's actually a lot more sensible for the entire server program to be oblivious to its process context. A separate program should create the daemon and have it execute the server program.

Whether you use a separate general purpose daemon program to launch your XML-RPC server program or you have your XML-RPC server program daemonize itself before calling xmlrpc_server_abyss(), here are some things you should think about resetting for the server:

Deprecated "config file" Style Interface

The deprecated style is higher level than the preferred one. You supply an Abyss configuration file and the library routine parses it for parameters, forks a new process, and sets up the process environment for the Abyss server (including for example setting the userid) in addition to actually executing the server.

The preferred style is down at the level that a program that uses the libxmlrpc_server_abyss API probably is. You supply all parameters in data structures in memory. The library function runs the Abyss server, but expects you to have set up the process environment beforehand.

You choose the deprecated style by setting config_file_name in the parameter structure to non-null.

On Unix, xmlrpc_server_abyss() creates a new process for the server, separated in the usual ways from the process that created it so that it can continue as an independent process. (This separation is sometimes called "backgrounding" or "daemonizing"). xmlrpc_server_abyss() returns after starting the server, and your program can then exit. On other platforms, this function performs the server functions itself, and never returns.

config_file_name is the filename of an Abyss configuration file. Use Abyss documentation to learn the full format of this file. Here is an example of a working Abyss configuration file we have used in examples:

Port 8080
LogFile /tmp/xmlrpc_abyss.log
PidFile /tmp/abyss.pid

runfirst is a function that xmlrpc_server_abyss() runs in the server process before starting the Abyss server. You can use this to set up the server process in ways that you can't from the parent process. runfirst_arg is an argument (opaque to Xmlrpc-c) that gets passed to runfirst.

The runfirst function is a convenient way to add to the function of libxmlrpc_server_abyss, but if you have a program sophisticated enough to need it, you might find you really need to assume the job of building the server process yourself and not use xmlrpc_server_abyss() at all. This style of server is described here.

Wire Protocol

This section gives some information on the protocol that the XML-RPC server follows in its communication with clients.

The most basic fact is, of course, that the protocol is XML-RPC. However, that protocol is ambiguous in a number of ways, so more needs to be said. Also, Xmlrpc-c deviates in some ways where you are better off not following the XML-RPC spec verbatim.

In addition to what is stated here, a server you build using libxmlrpc_server_abyss employs protocol interpretations and deviations implemented by libxmlrpc, because libxmlrpc_server_abyss uses libxmlrpc. For example, the meaning of the various data types and extensions for types such as 64 bit integer is determined by libxmlrpc .

HTTP Content Type

In HTTP, a document (request or response) has a "content type," which it declares with a content-type HTTP header field. In XML-RPC, that content type is text/xml, and must be declared.

But libxmlrpc_server_abyss doesn't pay any attention to content type in calls it receives. It assumes the content is an XML-RPC call, which in HTTP terms implies it is text/xml, regardless of what the content-type header field says, or if it is present at all. This way, an incorrectly implemented client (and we have seen one, which declares content type text/plain) will work.

Before Xmlrpc-c 1.25 (December 2010), the server fails any call that does not declare a content type of text/xml.

Notes

This section contains special topics of interest to users of the facilities described above.

HTTP Authentication

HTTP authentication is the concept of the XML-RPC client, as an HTTP client, identifying and authenticating itself to the XML-RPC server, as an HTTP server, using features of the HTTP protocol.

libxmlrpc_server_abyss provides no facilities for doing any of that.

This is a typical drawback of using the simple Abyss server. The world of HTTP is much larger than Abyss knows or could be expected to know in future verisons. For this reason, many people use a plugin to a more serious HTTP server (like Apache) to do XML-RPC serving. Xmlrpc-c does provide some facilities that are useful for creating or working with such a plugin. libxmlrpc_server_cgi helps you make an XML-RPC server out of CGI programs. libxmlrpc_server contains method registry services. libxmlrpc.html provides facilities for parsing and generating the XML for XML-RPC calls and responses.

Debugging

The trace facilities described here write messages to the Standard Error file descriptor via the Standard Error stream of the standard C library (stderr). So make sure you have one. Many server processes don't (they explicitly close the one that the system setup code provides).

If you set the XMLRPC_TRACE_ABYSS environment variable to 1, libxmlrpc_server_abyss's Abyss request handler prints a message to Standard Error each time Abyss calls it.

You can also use the XMLRPC_TRACE_XML environment variable to trace the handler's calls to the libxmlrpc_server registry.

You can trace inside the Abyss server using environment variables that control libxmlrpc_abyss.