| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions
- ** are met:
- ** 1. Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** 2. Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** 3. The name of the author may not be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ** SUCH DAMAGE.
- **
- ** There is more copyright information in the bottom half of this file.
- ** Please see it for more details. */
- #include "xmlrpc_config.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "abyss.h"
- #include "xmlrpc.h"
- #include "xmlrpc_server.h"
- #include "xmlrpc_int.h"
- #include "xmlrpc_server_abyss.h"
- #include "xmlrpc_server_abyss_int.h"
- /*=========================================================================
- ** die_if_fault_occurred
- **=========================================================================
- ** If certain kinds of out-of-memory errors occur during server setup,
- ** we want to quit and print an error.
- */
- static void die_if_fault_occurred(xmlrpc_env *env) {
- if (env->fault_occurred) {
- fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n",
- env->fault_string, env->fault_code);
- exit(1);
- }
- }
- /*=========================================================================
- ** send_xml_data
- **=========================================================================
- ** Blast some XML data back to the client.
- */
- static void
- send_xml_data (TSession * const r,
- char * const buffer,
- uint64 const len) {
- const char * const http_cookie = NULL;
- /* This used to set http_cookie to getenv("HTTP_COOKIE"), but
- that doesn't make any sense -- environment variables are not
- appropriate for this. So for now, cookie code is disabled.
- - Bryan 2004.10.03.
- */
- /* fwrite(buffer, sizeof(char), len, stderr); */
- /* XXX - Is it safe to chunk our response? */
- ResponseChunked(r);
- ResponseStatus(r, 200);
-
- if (http_cookie) {
- /* There's an auth cookie, so pass it back in the response. */
- char *cookie_response;
-
- cookie_response = malloc(10+strlen(http_cookie));
- sprintf(cookie_response, "auth=%s", http_cookie);
-
- /* Return abyss response. */
- ResponseAddField(r, "Set-Cookie", cookie_response);
- free(cookie_response);
- }
-
-
- ResponseContentType(r, "text/xml; charset=\"utf-8\"");
- ResponseContentLength(r, len);
-
- ResponseWrite(r);
-
- HTTPWrite(r, buffer, len);
- HTTPWriteEnd(r);
- }
- /*=========================================================================
- ** send_error
- **=========================================================================
- ** Send an error back to the client.
- */
- static void
- send_error(TSession * const abyssSessionP,
- unsigned int const status) {
- ResponseStatus(abyssSessionP, (uint16) status);
- ResponseError(abyssSessionP);
- }
- /*=========================================================================
- ** get_buffer_data
- **=========================================================================
- ** Extract some data from the TConn's underlying input buffer. Do not
- ** extract more than 'max'.
- */
- static void
- get_buffer_data(TSession * const r,
- int const max,
- char ** const out_start,
- int * const out_len) {
- /* Point to the start of our data. */
- *out_start = &r->conn->buffer[r->conn->bufferpos];
- /* Decide how much data to retrieve. */
- *out_len = r->conn->buffersize - r->conn->bufferpos;
- if (*out_len > max)
- *out_len = max;
- /* Update our buffer position. */
- r->conn->bufferpos += *out_len;
- }
- /*=========================================================================
- ** get_body
- **=========================================================================
- ** Slurp the body of the request into an xmlrpc_mem_block.
- */
- static void
- getBody(xmlrpc_env * const envP,
- TSession * const abyssSessionP,
- unsigned int const contentSize,
- xmlrpc_mem_block ** const bodyP) {
- /*----------------------------------------------------------------------------
- Get the entire body from the Abyss session and return it as the new
- memblock *bodyP.
- The first chunk of the body may already be in Abyss's buffer. We
- retrieve that before reading more.
- -----------------------------------------------------------------------------*/
- xmlrpc_mem_block * body;
- body = xmlrpc_mem_block_new(envP, 0);
- if (!envP->fault_occurred) {
- unsigned int bytesRead;
- char * chunkPtr;
- int chunkLen;
- bytesRead = 0;
- while (!envP->fault_occurred && bytesRead < contentSize) {
- get_buffer_data(abyssSessionP, contentSize - bytesRead,
- &chunkPtr, &chunkLen);
- bytesRead += chunkLen;
- XMLRPC_TYPED_MEM_BLOCK_APPEND(char, envP, body,
- chunkPtr, chunkLen);
-
- if (bytesRead < contentSize) {
- /* Get the next chunk of data from the connection into the
- buffer
- */
- abyss_bool succeeded;
-
- /* Reset our read buffer & flush data from previous reads. */
- ConnReadInit(abyssSessionP->conn);
-
- /* Read more network data into our buffer. If we encounter
- a timeout, exit immediately. We're very forgiving about
- the timeout here. We allow a full timeout per network
- read, which would allow somebody to keep a connection
- alive nearly indefinitely. But it's hard to do anything
- intelligent here without very complicated code.
- */
- succeeded = ConnRead(abyssSessionP->conn,
- abyssSessionP->server->timeout);
- if (!succeeded)
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for "
- "client to send its POST data");
- }
- }
- if (envP->fault_occurred)
- xmlrpc_mem_block_free(body);
- else
- *bodyP = body;
- }
- }
- static void
- storeCookies(TSession * const httpRequestP,
- unsigned int * const httpErrorP) {
- /*----------------------------------------------------------------------------
- Get the cookie settings from the HTTP headers and remember them for
- use in responses.
- -----------------------------------------------------------------------------*/
- const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
- if (cookie) {
- /*
- Setting the value in an environment variable doesn't make
- any sense. So for now, cookie code is disabled.
- -Bryan 04.10.03.
- setenv("HTTP_COOKIE", cookie, 1);
- */
- }
- /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */
- *httpErrorP = 0;
- }
- static void
- validateContentType(TSession * const httpRequestP,
- unsigned int * const httpErrorP) {
- /*----------------------------------------------------------------------------
- If the client didn't specify a content-type of "text/xml", return
- "400 Bad Request". We can't allow the client to default this header,
- because some firewall software may rely on all XML-RPC requests
- using the POST method and a content-type of "text/xml".
- -----------------------------------------------------------------------------*/
- const char * const content_type =
- RequestHeaderValue(httpRequestP, "content-type");
- if (content_type == NULL || strcmp(content_type, "text/xml") != 0)
- *httpErrorP = 400;
- else
- *httpErrorP = 0;
- }
- static void
- processContentLength(TSession * const httpRequestP,
- unsigned int * const inputLenP,
- unsigned int * const httpErrorP) {
- /*----------------------------------------------------------------------------
- Make sure the content length is present and non-zero. This is
- technically required by XML-RPC, but we only enforce it because we
- don't want to figure out how to safely handle HTTP < 1.1 requests
- without it. If the length is missing, return "411 Length Required".
- -----------------------------------------------------------------------------*/
- const char * const content_length =
- RequestHeaderValue(httpRequestP, "content-length");
- if (content_length == NULL)
- *httpErrorP = 411;
- else {
- int const contentLengthValue = atoi(content_length);
- if (contentLengthValue <= 0)
- *httpErrorP = 400;
- else {
- *httpErrorP = 0;
- *inputLenP = (unsigned int)contentLengthValue;
- }
- }
- }
- /****************************************************************************
- Abyss handlers (to be registered with and called by Abyss)
- ****************************************************************************/
- /* XXX - This variable is *not* currently threadsafe. Once the server has
- ** been started, it must be treated as read-only. */
- static xmlrpc_registry *global_registryP;
- static const char * trace_abyss;
- static void
- processCall(TSession * const abyssSessionP,
- int const inputLen) {
- /*----------------------------------------------------------------------------
- Handle an RPC request. This is an HTTP request that has the proper form
- to be one of our RPCs.
- -----------------------------------------------------------------------------*/
- xmlrpc_env env;
- if (trace_abyss)
- fprintf(stderr, "xmlrpc_server_abyss RPC2 handler processing RPC.\n");
- xmlrpc_env_init(&env);
- /* SECURITY: Make sure our content length is legal.
- XXX - We can cast 'inputLen' because we know it's >= 0, yes?
- */
- if ((size_t) inputLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
- xmlrpc_env_set_fault_formatted(
- &env, XMLRPC_LIMIT_EXCEEDED_ERROR,
- "XML-RPC request too large (%d bytes)", inputLen);
- else {
- xmlrpc_mem_block *body;
- /* Read XML data off the wire. */
- getBody(&env, abyssSessionP, inputLen, &body);
- if (!env.fault_occurred) {
- xmlrpc_mem_block * output;
- /* Process the RPC. */
- output = xmlrpc_registry_process_call(
- &env, global_registryP, NULL,
- XMLRPC_MEMBLOCK_CONTENTS(char, body),
- XMLRPC_MEMBLOCK_SIZE(char, body));
- if (!env.fault_occurred) {
- /* Send our the result. */
- send_xml_data(abyssSessionP,
- XMLRPC_MEMBLOCK_CONTENTS(char, output),
- XMLRPC_MEMBLOCK_SIZE(char, output));
-
- XMLRPC_MEMBLOCK_FREE(char, output);
- }
- XMLRPC_MEMBLOCK_FREE(char, body);
- }
- }
- if (env.fault_occurred) {
- if (env.fault_code == XMLRPC_TIMEOUT_ERROR)
- send_error(abyssSessionP, 408); /* 408 Request Timeout */
- else
- send_error(abyssSessionP, 500); /* 500 Internal Server Error */
- }
- xmlrpc_env_clean(&env);
- }
- /*=========================================================================
- ** xmlrpc_server_abyss_rpc2_handler
- **=========================================================================
- ** This handler processes all requests to '/RPC2'. See the header for
- ** more documentation.
- */
- xmlrpc_bool
- xmlrpc_server_abyss_rpc2_handler (TSession * const r) {
- xmlrpc_bool retval;
- if (trace_abyss)
- fprintf(stderr, "xmlrpc_server_abyss RPC2 handler called.\n");
- /* We handle only requests to /RPC2, the default XML-RPC URL.
- Everything else we pass through to other handlers.
- */
- if (strcmp(r->uri, "/RPC2") != 0)
- retval = FALSE;
- else {
- retval = TRUE;
- /* We understand only the POST HTTP method. For anything else, return
- "405 Method Not Allowed".
- */
- if (r->method != m_post)
- send_error(r, 405);
- else {
- unsigned int httpError;
- storeCookies(r, &httpError);
- if (httpError)
- send_error(r, httpError);
- else {
- unsigned int httpError;
- validateContentType(r, &httpError);
- if (httpError)
- send_error(r, httpError);
- else {
- unsigned int httpError;
- int inputLen;
- processContentLength(r, &inputLen, &httpError);
- if (httpError)
- send_error(r, httpError);
- processCall(r, inputLen);
- }
- }
- }
- }
- if (trace_abyss)
- fprintf(stderr, "xmlrpc_server_abyss RPC2 handler returning.\n");
- return retval;
- }
- /*=========================================================================
- ** xmlrpc_server_abyss_default_handler
- **=========================================================================
- ** This handler returns a 404 Not Found for all requests. See the header
- ** for more documentation.
- */
- xmlrpc_bool
- xmlrpc_server_abyss_default_handler (TSession * const r) {
- send_error(r, 404);
- return TRUE;
- }
- /**************************************************************************
- **
- ** The code below was adapted from the main.c file of the Abyss webserver
- ** project. In addition to the other copyrights on this file, the following
- ** code is also under this copyright:
- **
- ** Copyright (C) 2000 by Moez Mahfoudh <[email protected]>.
- ** All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions
- ** are met:
- ** 1. Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** 2. Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** 3. The name of the author may not be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ** SUCH DAMAGE.
- **
- **************************************************************************/
- #include <time.h>
- #include <fcntl.h>
- #ifdef _WIN32
- #include <io.h>
- #else
- /* Must check this
- #include <sys/io.h>
- */
- #endif /* _WIN32 */
- #ifdef _UNIX
- #include <sys/signal.h>
- #include <sys/wait.h>
- #include <grp.h>
- #endif
- #ifdef _UNIX
- static void
- sigterm(int const sig) {
- TraceExit("Signal %d received. Exiting...\n",sig);
- }
- #endif
- #ifdef _UNIX
- static void
- sigchld(int const sig ATTR_UNUSED) {
- /*----------------------------------------------------------------------------
- This is a signal handler for a SIGCHLD signal (which informs us that
- one of our child processes has terminated).
- We respond by reaping the zombie process.
- Implementation note: In some systems, just setting the signal handler
- to SIG_IGN (ignore signal) does this. In others, it doesn't.
- -----------------------------------------------------------------------------*/
- pid_t pid;
- int status;
-
- /* Reap defunct children until there aren't any more. */
- for (;;) {
- pid = waitpid( (pid_t) -1, &status, WNOHANG );
-
- /* none left */
- if (pid==0)
- break;
-
- if (pid<0) {
- /* because of ptrace */
- if (errno==EINTR)
- continue;
-
- break;
- }
- }
- }
- #endif /* _UNIX */
- static TServer globalSrv;
- /* When you use the old interface (xmlrpc_server_abyss_init(), etc.),
- this is the Abyss server to which they refer. Obviously, there can be
- only one Abyss server per program using this interface.
- */
- void
- xmlrpc_server_abyss_init(int const flags ATTR_UNUSED,
- const char * const config_file) {
- DateInit();
- MIMETypeInit();
- ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
-
- ConfReadServerFile(config_file, &globalSrv);
- xmlrpc_server_abyss_init_registry();
- /* Installs /RPC2 handler and default handler that use the
- built-in registry.
- */
- ServerInit(&globalSrv);
- }
- static void
- setupSignalHandlers(void) {
- #ifdef _UNIX
- struct sigaction mysigaction;
-
- sigemptyset(&mysigaction.sa_mask);
- mysigaction.sa_flags = 0;
- /* These signals abort the program, with tracing */
- mysigaction.sa_handler = sigterm;
- sigaction(SIGTERM, &mysigaction, NULL);
- sigaction(SIGINT, &mysigaction, NULL);
- sigaction(SIGHUP, &mysigaction, NULL);
- sigaction(SIGUSR1, &mysigaction, NULL);
- /* This signal indicates connection closed in the middle */
- mysigaction.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &mysigaction, NULL);
-
- /* This signal indicates a child process (request handler) has died */
- mysigaction.sa_handler = sigchld;
- sigaction(SIGCHLD, &mysigaction, NULL);
- #endif
- }
- static void
- runServer(TServer * const srvP,
- runfirstFn const runfirst,
- void * const runfirstArg) {
- setupSignalHandlers();
- #ifdef _UNIX
- /* Become a daemon */
- switch (fork()) {
- case 0:
- break;
- case -1:
- TraceExit("Unable to become a daemon");
- default:
- exit(0);
- };
-
- setsid();
- /* Change the current user if we are root */
- if (getuid()==0) {
- if (srvP->uid == (uid_t)-1)
- TraceExit("Can't run under root privileges. "
- "Please add a User option in your "
- "Abyss configuration file.");
- #ifdef HAVE_SETGROUPS
- if (setgroups(0,NULL)==(-1))
- TraceExit("Failed to setup the group.");
- if (srvP->gid != (gid_t)-1)
- if (setgid(srvP->gid)==(-1))
- TraceExit("Failed to change the group.");
- #endif
-
- if (setuid(srvP->uid) == -1)
- TraceExit("Failed to change the user.");
- };
-
- if (srvP->pidfile!=(-1)) {
- char z[16];
-
- sprintf(z,"%d",getpid());
- FileWrite(&srvP->pidfile,z,strlen(z));
- FileClose(&srvP->pidfile);
- };
- #endif
-
- /* We run the user supplied runfirst after forking, but before accepting
- connections (helpful when running with threads)
- */
- if (runfirst)
- runfirst(runfirstArg);
- ServerRun(srvP);
- /* We can't exist here because ServerRun doesn't return */
- XMLRPC_ASSERT(FALSE);
- }
- void
- xmlrpc_server_abyss_run_first(runfirstFn const runfirst,
- void * const runfirstArg) {
-
- runServer(&globalSrv, runfirst, runfirstArg);
- }
- void
- xmlrpc_server_abyss_run(void) {
- runServer(&globalSrv, NULL, NULL);
- }
- void
- xmlrpc_server_abyss_set_handlers(TServer * const srvP,
- xmlrpc_registry * const registryP) {
- /* Abyss ought to have a way to register with a handler an argument
- that gets passed to the handler every time it is called. That's
- where we should put the registry handle. But we don't find such
- a thing in Abyss, so we use the global variable 'global_registryP'.
- */
- global_registryP = registryP;
- trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
-
- ServerAddHandler(srvP, xmlrpc_server_abyss_rpc2_handler);
- ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler);
- }
- void
- xmlrpc_server_abyss(xmlrpc_env * const envP,
- const xmlrpc_server_abyss_parms * const parmsP,
- unsigned int const parm_size) {
-
- XMLRPC_ASSERT_ENV_OK(envP);
- if (parm_size < XMLRPC_APSIZE(registryP))
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_INTERNAL_ERROR,
- "You must specify members at least up through "
- "'registryP' in the server parameters argument. "
- "That would mean the parameter size would be >= %u "
- "but you specified a size of %u",
- XMLRPC_APSIZE(registryP), parm_size);
- else {
- TServer srv;
- runfirstFn runfirst;
- void * runfirstArg;
- DateInit();
- MIMETypeInit();
-
- ServerCreate(&srv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
-
- ConfReadServerFile(parmsP->config_file_name, &srv);
-
- xmlrpc_server_abyss_set_handlers(&srv, parmsP->registryP);
-
- ServerInit(&srv);
- if (parm_size >= XMLRPC_APSIZE(runfirst_arg)) {
- runfirst = parmsP->runfirst;
- runfirstArg = parmsP->runfirst_arg;
- } else {
- runfirst = NULL;
- runfirstArg = NULL;
- }
- runServer(&srv, runfirst, runfirstArg);
- }
- }
- /*=========================================================================
- ** XML-RPC Server Method Registry
- **=========================================================================
- ** A simple front-end to our method registry.
- */
- /* XXX - This variable is *not* currently threadsafe. Once the server has
- ** been started, it must be treated as read-only. */
- static xmlrpc_registry *builtin_registryP;
- void
- xmlrpc_server_abyss_init_registry(void) {
- /* This used to just create the registry and Caller would be
- responsible for adding the handlers that use it.
- But that isn't very modular -- the handlers and registry go
- together; there's no sense in using the built-in registry and
- not the built-in handlers because if you're custom building
- something, you can just make your own regular registry. So now
- we tie them together, and we don't export our handlers.
- */
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- builtin_registryP = xmlrpc_registry_new(&env);
- die_if_fault_occurred(&env);
- xmlrpc_env_clean(&env);
- xmlrpc_server_abyss_set_handlers(&globalSrv, builtin_registryP);
- }
- xmlrpc_registry *
- xmlrpc_server_abyss_registry(void) {
- /* This is highly deprecated. If you want to mess with a registry,
- make your own with xmlrpc_registry_new() -- don't mess with the
- internal one.
- */
- return builtin_registryP;
- }
- /* A quick & easy shorthand for adding a method. */
- void
- xmlrpc_server_abyss_add_method (char * const method_name,
- xmlrpc_method const method,
- void * const user_data) {
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name,
- method, user_data);
- die_if_fault_occurred(&env);
- xmlrpc_env_clean(&env);
- }
- void
- xmlrpc_server_abyss_add_method_w_doc (char * const method_name,
- xmlrpc_method const method,
- void * const user_data,
- char * const signature,
- char * const help) {
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- xmlrpc_registry_add_method_w_doc(
- &env, builtin_registryP, NULL, method_name,
- method, user_data, signature, help);
- die_if_fault_occurred(&env);
- xmlrpc_env_clean(&env);
- }
|