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.
The 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).
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:
A complete example of an XML-RPC server program that uses libxmlrpc_server_abyss is here.
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.
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 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_handlers(). 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_handlers()'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, 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.
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.
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.
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().
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.
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.
void
xmlrpc_server_abyss_set_handler(TServer * const srvP,
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.
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);
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_handler() above, except that instead of setting up a handler that executes the RPC using an Xmlrpc-c method registry, it sets up a handler that calls a subroutine you supply to do that execution. 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.
xmlProcessor is your XML processor, described above. xmlProcessorArg is the argument that the Abyss server passes to your XML processor as processorArg.
xmlProcessorMaxStackSize is the maximum number of bytes of stack space xmlProcessor will use. It is unspecified what happens if xmlProcessor attempts to use more.
callXml is the XML-RPC call (which is XML) in UTF-8. It is not NUL-terminated. callXmlLen is its length in bytes.
abyssSessionP is the handle of the Abyss session over which the XML-RPC call arrived. You can use this with libxmlrpc_abyss's SessionGetRequestInfo() to get HTTP information, and SessionGetChannelInfo() to get transport level information (typically, the IP address and TCP port of the XML-RPC caller). However, you are generally not allowed to manipulate the session; libxmlrpc_server_abyss owns it.
For an example of using xmlrpc_server_abyss_set_handler2(), 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_handler2() 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_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.
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).
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.
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.
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.
This is the simplest way to run an XML-RPC server. It consists of a single library subroutine: 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.
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.
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.
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.
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.
parmP 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. You must set members at least up through registryP.
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 client program you write today, whether you compile it today or then, to work properly with that future library.
You must supply at least 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.
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().
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().
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 (HTTP request) when the process receives the signal, it will finish that connection.
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, 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.
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().
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.
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().
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;
} 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.
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.
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).
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.
This is the TCP port number on which the server will listen and accept connections for RPCs. If this member isn't present (according to parmSize), it defaults to 8080.
If socket_bound is true, port_number is meaningless.
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. False (zero) means you are not providing any socket; instead, you are providing a TCP port number and the server will create and bind a socket itself. ("bind" means assign an address to the socket -- the address with which clients will address it. This means primarily a TCP port number, but can also include an IP address or something entirely different for a non-TCP socket).
When you specify true for socket_bound, you must supply a proper value for socket_fd and port is meaningless. Conversely, when you specify false for socket_bound, you must supply a proper value for port and socket_fd is meaningless.
The default is false.
This option was new in Xmlrpc-c 1.04 (November 2005). Before that, xmlrpc_server_abyss() always created its own socket.
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).
One reason you would want to supply a socket, as opposed to just letting the server create one (see socket_bound) is if 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.
This option was new in Xmlrpc-c 1.04 (November 2005). Before that, xmlrpc_server_abyss() always created its own socket.
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".
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.
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 sees the connection close.
A value of zero requests the default.
The default is 15 seconds.
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.
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.
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, your program 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.
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.
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. 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.
These are meaningless (they're for the config file style interface).
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 even in current Xmlrpc-c.
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.
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:
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.
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.
Set Abyss' ABYSS_TRACE_CONN environment variable to 1 to cause Abyss to print to Standard Error the raw HTTP requests and responses. (New in Xmlrpc-c 1.03, June 2005, for requests only; responses added in Xmlrpc-c 1.05 (March 2006)).
If you need even lower level tracing, Abyss' ABYSS_TRACE_SOCKET environment variable traces the individual socket service calls (e.g. shows you the data returned by a call to the Unix C library'es recv() function).