1 /* Copyright information is at the end of the file */
3 #include "xmlrpc_config.h"
16 # include <sys/wait.h>
20 #include "mallocvar.h"
21 #include "xmlrpc-c/abyss.h"
23 #include "xmlrpc-c/base.h"
24 #include "xmlrpc-c/server.h"
25 #include "xmlrpc-c/base_int.h"
26 #include "xmlrpc-c/string_int.h"
27 #include "xmlrpc-c/server_abyss.h"
30 /*=========================================================================
31 ** die_if_fault_occurred
32 **=========================================================================
33 ** If certain kinds of out-of-memory errors occur during server setup,
34 ** we want to quit and print an error.
37 static void die_if_fault_occurred(xmlrpc_env *env) {
38 if (env->fault_occurred) {
39 fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n",
40 env->fault_string, env->fault_code);
48 addAuthCookie(xmlrpc_env * const envP,
49 TSession * const abyssSessionP,
50 const char * const authCookie) {
52 const char * cookieResponse;
54 xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie);
56 if (cookieResponse == xmlrpc_strsol)
57 xmlrpc_faultf(envP, "Insufficient memory to generate cookie "
60 ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse);
62 xmlrpc_strfree(cookieResponse);
69 sendXmlData(xmlrpc_env * const envP,
70 TSession * const abyssSessionP,
71 const char * const body,
74 /*----------------------------------------------------------------------------
75 Generate an HTTP response containing body 'body' of length 'len'
78 This is meant to run in the context of an Abyss URI handler for
79 Abyss session 'abyssSessionP'.
80 -----------------------------------------------------------------------------*/
81 const char * http_cookie = NULL;
82 /* This used to set http_cookie to getenv("HTTP_COOKIE"), but
83 that doesn't make any sense -- environment variables are not
84 appropriate for this. So for now, cookie code is disabled.
88 /* Various bugs before Xmlrpc-c 1.05 caused the response to be not
89 chunked in the most basic case, but chunked if the client explicitly
90 requested keepalive. I think it's better not to chunk, because
91 it's simpler, so I removed this in 1.05. I don't know what the
92 purpose of chunking would be, and an original comment suggests
93 the author wasn't sure chunking was a good idea.
95 In 1.06 we added the user option to chunk.
98 ResponseChunked(abyssSessionP);
100 ResponseStatus(abyssSessionP, 200);
103 /* There's an auth cookie, so pass it back in the response. */
104 addAuthCookie(envP, abyssSessionP, http_cookie);
106 if ((size_t)(uint32_t)len != len)
107 xmlrpc_faultf(envP, "XML-RPC method generated a response too "
108 "large for Abyss to send");
110 uint32_t const abyssLen = (uint32_t)len;
112 ResponseContentType(abyssSessionP, "text/xml; charset=\"utf-8\"");
113 ResponseContentLength(abyssSessionP, abyssLen);
115 ResponseWriteStart(abyssSessionP);
116 ResponseWriteBody(abyssSessionP, body, abyssLen);
117 ResponseWriteEnd(abyssSessionP);
124 sendError(TSession * const abyssSessionP,
125 unsigned int const status) {
126 /*----------------------------------------------------------------------------
127 Send an error response back to the client.
129 -----------------------------------------------------------------------------*/
130 ResponseStatus(abyssSessionP, (uint16_t) status);
131 ResponseError(abyssSessionP);
137 traceChunkRead(TSession * const abyssSessionP) {
139 fprintf(stderr, "XML-RPC handler got a chunk of %u bytes\n",
140 (unsigned int)SessionReadDataAvail(abyssSessionP));
146 refillBufferFromConnection(xmlrpc_env * const envP,
147 TSession * const abyssSessionP,
148 const char * const trace) {
149 /*----------------------------------------------------------------------------
150 Get the next chunk of data from the connection into the buffer.
151 -----------------------------------------------------------------------------*/
152 abyss_bool succeeded;
154 succeeded = SessionRefillBuffer(abyssSessionP);
157 xmlrpc_env_set_fault_formatted(
158 envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for "
159 "client to send its POST data");
162 traceChunkRead(abyssSessionP);
169 getBody(xmlrpc_env * const envP,
170 TSession * const abyssSessionP,
171 size_t const contentSize,
172 const char * const trace,
173 xmlrpc_mem_block ** const bodyP) {
174 /*----------------------------------------------------------------------------
175 Get the entire body, which is of size 'contentSize' bytes, from the
176 Abyss session and return it as the new memblock *bodyP.
178 The first chunk of the body may already be in Abyss's buffer. We
179 retrieve that before reading more.
180 -----------------------------------------------------------------------------*/
181 xmlrpc_mem_block * body;
184 fprintf(stderr, "XML-RPC handler processing body. "
185 "Content Size = %u bytes\n", (unsigned)contentSize);
187 body = xmlrpc_mem_block_new(envP, 0);
188 if (!envP->fault_occurred) {
190 const char * chunkPtr;
195 while (!envP->fault_occurred && bytesRead < contentSize) {
196 SessionGetReadData(abyssSessionP, contentSize - bytesRead,
197 &chunkPtr, &chunkLen);
198 bytesRead += chunkLen;
200 assert(bytesRead <= contentSize);
202 XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen);
203 if (bytesRead < contentSize)
204 refillBufferFromConnection(envP, abyssSessionP, trace);
206 if (envP->fault_occurred)
207 xmlrpc_mem_block_free(body);
216 storeCookies(TSession * const httpRequestP,
217 unsigned int * const httpErrorP) {
218 /*----------------------------------------------------------------------------
219 Get the cookie settings from the HTTP headers and remember them for
221 -----------------------------------------------------------------------------*/
222 const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
225 Setting the value in an environment variable doesn't make
226 any sense. So for now, cookie code is disabled.
229 setenv("HTTP_COOKIE", cookie, 1);
232 /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */
241 validateContentType(TSession * const httpRequestP,
242 unsigned int * const httpErrorP) {
243 /*----------------------------------------------------------------------------
244 If the client didn't specify a content-type of "text/xml", return
245 "400 Bad Request". We can't allow the client to default this header,
246 because some firewall software may rely on all XML-RPC requests
247 using the POST method and a content-type of "text/xml".
248 -----------------------------------------------------------------------------*/
249 const char * const content_type =
250 RequestHeaderValue(httpRequestP, "content-type");
252 if (content_type == NULL)
255 const char * const sempos = strchr(content_type, ';');
256 unsigned int baselen;
257 /* Length of the base portion of the content type, e.g.
258 "text/xml" int "text/xml;charset=utf-8"
262 baselen = sempos - content_type;
264 baselen = strlen(content_type);
266 if (!xmlrpc_strneq(content_type, "text/xml", baselen))
276 processContentLength(TSession * const httpRequestP,
277 size_t * const inputLenP,
278 unsigned int * const httpErrorP) {
279 /*----------------------------------------------------------------------------
280 Make sure the content length is present and non-zero. This is
281 technically required by XML-RPC, but we only enforce it because we
282 don't want to figure out how to safely handle HTTP < 1.1 requests
283 without it. If the length is missing, return "411 Length Required".
284 -----------------------------------------------------------------------------*/
285 const char * const content_length =
286 RequestHeaderValue(httpRequestP, "content-length");
288 if (content_length == NULL)
291 if (content_length[0] == '\0')
294 unsigned long contentLengthValue;
297 contentLengthValue = strtoul(content_length, &tail, 10);
300 /* There's non-numeric crap in the length */
302 else if (contentLengthValue < 1)
304 else if ((unsigned long)(size_t)contentLengthValue
305 != contentLengthValue)
309 *inputLenP = (size_t)contentLengthValue;
318 traceHandlerCalled(TSession * const abyssSessionP) {
320 const char * methodDesc;
321 const TRequestInfo * requestInfoP;
323 fprintf(stderr, "xmlrpc_server_abyss URI path handler called.\n");
325 SessionGetRequestInfo(abyssSessionP, &requestInfoP);
327 fprintf(stderr, "URI = '%s'\n", requestInfoP->uri);
329 switch (requestInfoP->method) {
330 case m_unknown: methodDesc = "unknown"; break;
331 case m_get: methodDesc = "get"; break;
332 case m_put: methodDesc = "put"; break;
333 case m_head: methodDesc = "head"; break;
334 case m_post: methodDesc = "post"; break;
335 case m_delete: methodDesc = "delete"; break;
336 case m_trace: methodDesc = "trace"; break;
337 case m_options: methodDesc = "m_options"; break;
338 default: methodDesc = "?";
340 fprintf(stderr, "HTTP method = '%s'\n", methodDesc);
342 if (requestInfoP->query)
343 fprintf(stderr, "query (component of URL)='%s'\n",
344 requestInfoP->query);
346 fprintf(stderr, "URL has no query component\n");
352 processCall(TSession * const abyssSessionP,
353 size_t const contentSize,
354 xmlrpc_registry * const registryP,
355 bool const wantChunk,
356 const char * const trace) {
357 /*----------------------------------------------------------------------------
358 Handle an RPC request. This is an HTTP request that has the proper form
359 to be one of our RPCs.
361 Its content length is 'contentSize' bytes.
362 -----------------------------------------------------------------------------*/
367 "xmlrpc_server_abyss URI path handler processing RPC.\n");
369 xmlrpc_env_init(&env);
371 if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
372 xmlrpc_env_set_fault_formatted(
373 &env, XMLRPC_LIMIT_EXCEEDED_ERROR,
374 "XML-RPC request too large (%d bytes)", contentSize);
376 xmlrpc_mem_block *body;
377 /* Read XML data off the wire. */
378 getBody(&env, abyssSessionP, contentSize, trace, &body);
379 if (!env.fault_occurred) {
380 xmlrpc_mem_block * output;
381 /* Process the RPC. */
382 output = xmlrpc_registry_process_call(
383 &env, registryP, NULL,
384 XMLRPC_MEMBLOCK_CONTENTS(char, body),
385 XMLRPC_MEMBLOCK_SIZE(char, body));
386 if (!env.fault_occurred) {
387 /* Send out the result. */
388 sendXmlData(&env, abyssSessionP,
389 XMLRPC_MEMBLOCK_CONTENTS(char, output),
390 XMLRPC_MEMBLOCK_SIZE(char, output),
393 XMLRPC_MEMBLOCK_FREE(char, output);
395 XMLRPC_MEMBLOCK_FREE(char, body);
398 if (env.fault_occurred) {
399 if (env.fault_code == XMLRPC_TIMEOUT_ERROR)
400 sendError(abyssSessionP, 408); /* 408 Request Timeout */
402 sendError(abyssSessionP, 500); /* 500 Internal Server Error */
405 xmlrpc_env_clean(&env);
410 /****************************************************************************
411 Abyss handlers (to be registered with and called by Abyss)
412 ****************************************************************************/
414 static const char * trace_abyss;
418 struct uriHandlerXmlrpc {
419 /*----------------------------------------------------------------------------
420 This is the part of an Abyss HTTP request handler (aka URI handler)
421 that is specific to the Xmlrpc-c handler.
422 -----------------------------------------------------------------------------*/
423 xmlrpc_registry * registryP;
424 const char * uriPath; /* malloc'ed */
426 /* The handler should chunk its response whenever possible */
432 termUriHandler(void * const arg) {
434 struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = arg;
436 xmlrpc_strfree(uriHandlerXmlrpcP->uriPath);
437 free(uriHandlerXmlrpcP);
443 handleXmlrpcReq(URIHandler2 * const this,
444 TSession * const abyssSessionP,
445 abyss_bool * const handledP) {
446 /*----------------------------------------------------------------------------
447 Our job is to look at this HTTP request that the Abyss server is
448 trying to process and see if we can handle it. If it's an XML-RPC
449 call for this XML-RPC server, we handle it. If it's not, we refuse
450 it and Abyss can try some other handler.
452 Our return code is TRUE to mean we handled it; FALSE to mean we didn't.
454 Note that failing the request counts as handling it, and not handling
455 it does not mean we failed it.
457 This is an Abyss HTTP Request handler -- type URIHandler2.
458 -----------------------------------------------------------------------------*/
459 struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = this->userdata;
461 const TRequestInfo * requestInfoP;
464 traceHandlerCalled(abyssSessionP);
466 SessionGetRequestInfo(abyssSessionP, &requestInfoP);
468 /* Note that requestInfoP->uri is not the whole URI. It is just
469 the "file name" part of it.
471 if (strcmp(requestInfoP->uri, uriHandlerXmlrpcP->uriPath) != 0)
472 /* It's for the path (e.g. "/RPC2") that we're supposed to
479 /* We understand only the POST HTTP method. For anything else, return
480 "405 Method Not Allowed".
482 if (requestInfoP->method != m_post)
483 sendError(abyssSessionP, 405);
485 unsigned int httpError;
486 storeCookies(abyssSessionP, &httpError);
488 sendError(abyssSessionP, httpError);
490 unsigned int httpError;
491 validateContentType(abyssSessionP, &httpError);
493 sendError(abyssSessionP, httpError);
495 unsigned int httpError;
498 processContentLength(abyssSessionP,
499 &contentSize, &httpError);
501 sendError(abyssSessionP, httpError);
503 processCall(abyssSessionP, contentSize,
504 uriHandlerXmlrpcP->registryP,
505 uriHandlerXmlrpcP->chunkResponse,
512 fprintf(stderr, "xmlrpc_server_abyss URI path handler returning.\n");
517 /*=========================================================================
518 ** xmlrpc_server_abyss_default_handler
519 **=========================================================================
520 ** This handler returns a 404 Not Found for all requests. See the header
521 ** for more documentation.
525 xmlrpc_server_abyss_default_handler(TSession * const sessionP) {
528 fprintf(stderr, "xmlrpc_server_abyss default handler called.\n");
530 sendError(sessionP, 404);
538 sigchld(int const signalClass ATTR_UNUSED) {
539 /*----------------------------------------------------------------------------
540 This is a signal handler for a SIGCHLD signal (which informs us that
541 one of our child processes has terminated).
543 The only child processes we have are those that belong to the Abyss
544 server (and then only if the Abyss server was configured to use
545 forking as a threading mechanism), so we respond by passing the
546 signal on to the Abyss server.
547 -----------------------------------------------------------------------------*/
552 assert(signalClass == SIGCHLD);
555 childrenLeft = true; /* initial assumption */
557 /* Reap defunct children until there aren't any more. */
558 while (childrenLeft && !error) {
562 pid = waitpid((pid_t) -1, &status, WNOHANG);
565 childrenLeft = false;
567 /* because of ptrace */
571 ServerHandleSigchld(pid);
577 struct signalHandlers {
578 struct sigaction pipe;
579 struct sigaction chld;
585 setupSignalHandlers(struct signalHandlers * const oldHandlersP) {
587 struct sigaction mysigaction;
589 sigemptyset(&mysigaction.sa_mask);
590 mysigaction.sa_flags = 0;
592 /* This signal indicates connection closed in the middle */
593 mysigaction.sa_handler = SIG_IGN;
594 sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe);
596 /* This signal indicates a child process (request handler) has died */
597 mysigaction.sa_handler = sigchld;
598 sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld);
605 restoreSignalHandlers(struct signalHandlers const oldHandlers) {
608 sigaction(SIGPIPE, &oldHandlers.pipe, NULL);
609 sigaction(SIGCHLD, &oldHandlers.chld, NULL);
617 runServerDaemon(TServer * const serverP,
618 runfirstFn const runfirst,
619 void * const runfirstArg) {
621 struct signalHandlers oldHandlers;
623 setupSignalHandlers(&oldHandlers);
625 ServerUseSigchld(serverP);
627 ServerDaemonize(serverP);
629 /* We run the user supplied runfirst after forking, but before accepting
630 connections (helpful when running with threads)
633 runfirst(runfirstArg);
637 restoreSignalHandlers(oldHandlers);
643 setHandler(xmlrpc_env * const envP,
644 TServer * const srvP,
645 const char * const uriPath,
646 xmlrpc_registry * const registryP,
647 bool const chunkResponse) {
649 struct uriHandlerXmlrpc * uriHandlerXmlrpcP;
650 URIHandler2 uriHandler;
653 trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
655 MALLOCVAR_NOFAIL(uriHandlerXmlrpcP);
657 uriHandlerXmlrpcP->registryP = registryP;
658 uriHandlerXmlrpcP->uriPath = strdup(uriPath);
659 uriHandlerXmlrpcP->chunkResponse = chunkResponse;
661 uriHandler.handleReq2 = handleXmlrpcReq;
662 uriHandler.handleReq1 = NULL;
663 uriHandler.userdata = uriHandlerXmlrpcP;
664 uriHandler.init = NULL;
665 uriHandler.term = &termUriHandler;
667 ServerAddHandler2(srvP, &uriHandler, &success);
670 xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request "
671 "handler. ServerAddHandler2() failed.");
673 if (envP->fault_occurred)
674 free(uriHandlerXmlrpcP);
680 xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP,
681 TServer * const srvP,
682 const char * const uriPath,
683 xmlrpc_registry * const registryP) {
685 setHandler(envP, srvP, uriPath, registryP, false);
691 setHandlers(TServer * const srvP,
692 const char * const uriPath,
693 xmlrpc_registry * const registryP,
694 bool const chunkResponse) {
698 xmlrpc_env_init(&env);
700 trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
702 setHandler(&env, srvP, uriPath, registryP, chunkResponse);
704 if (env.fault_occurred)
707 ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler);
709 xmlrpc_env_clean(&env);
715 xmlrpc_server_abyss_set_handlers2(TServer * const srvP,
716 const char * const uriPath,
717 xmlrpc_registry * const registryP) {
719 setHandlers(srvP, uriPath, registryP, false);
725 xmlrpc_server_abyss_set_handlers(TServer * const srvP,
726 xmlrpc_registry * const registryP) {
728 setHandlers(srvP, "/RPC2", registryP, false);
734 oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED,
735 const xmlrpc_server_abyss_parms * const parmsP,
736 unsigned int const parmSize) {
737 /*----------------------------------------------------------------------------
738 This is the old deprecated interface, where the caller of the
739 xmlrpc_server_abyss API supplies an Abyss configuration file and
740 we use it to daemonize (fork into the background, chdir, set uid, etc.)
741 and run the Abyss server.
743 The new preferred interface, implemented by normalLevelAbyssRun(),
744 instead lets Caller set up the process environment himself and pass
745 Abyss parameters in memory. That's a more conventional and
747 -----------------------------------------------------------------------------*/
754 ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
756 ConfReadServerFile(parmsP->config_file_name, &server);
758 setHandlers(&server, "/RPC2", parmsP->registryP, false);
762 if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) {
763 runfirst = parmsP->runfirst;
764 runfirstArg = parmsP->runfirst_arg;
769 runServerDaemon(&server, runfirst, runfirstArg);
777 setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP,
778 unsigned int const parmSize,
779 TServer * const serverP) {
781 /* The following ought to be parameters on ServerCreate(), but it
782 looks like plugging them straight into the TServer structure is
783 the only way to set them.
786 if (parmSize >= XMLRPC_APSIZE(keepalive_timeout) &&
787 parmsP->keepalive_timeout > 0)
788 ServerSetKeepaliveTimeout(serverP, parmsP->keepalive_timeout);
789 if (parmSize >= XMLRPC_APSIZE(keepalive_max_conn) &&
790 parmsP->keepalive_max_conn > 0)
791 ServerSetKeepaliveMaxConn(serverP, parmsP->keepalive_max_conn);
792 if (parmSize >= XMLRPC_APSIZE(timeout) &&
794 ServerSetTimeout(serverP, parmsP->timeout);
795 if (parmSize >= XMLRPC_APSIZE(dont_advertise))
796 ServerSetAdvertise(serverP, !parmsP->dont_advertise);
802 extractServerCreateParms(
803 xmlrpc_env * const envP,
804 const xmlrpc_server_abyss_parms * const parmsP,
805 unsigned int const parmSize,
806 abyss_bool * const socketBoundP,
807 unsigned int * const portNumberP,
808 TOsSocket * const socketFdP,
809 const char ** const logFileNameP) {
812 if (parmSize >= XMLRPC_APSIZE(socket_bound))
813 *socketBoundP = parmsP->socket_bound;
815 *socketBoundP = FALSE;
818 if (parmSize < XMLRPC_APSIZE(socket_handle))
819 xmlrpc_faultf(envP, "socket_bound is true, but server parameter "
820 "structure does not contain socket_handle (it's too "
823 *socketFdP = parmsP->socket_handle;
825 if (parmSize >= XMLRPC_APSIZE(port_number))
826 *portNumberP = parmsP->port_number;
830 if (*portNumberP > 0xffff)
832 "TCP port number %u exceeds the maximum possible "
833 "TCP port number (65535)",
836 if (!envP->fault_occurred) {
837 if (parmSize >= XMLRPC_APSIZE(log_file_name) &&
838 parmsP->log_file_name)
839 *logFileNameP = strdup(parmsP->log_file_name);
841 *logFileNameP = NULL;
848 createServerBoundSocket(xmlrpc_env * const envP,
849 TOsSocket const socketFd,
850 const char * const logFileName,
851 TServer * const serverP,
852 TSocket ** const socketPP) {
857 SocketUnixCreateFd(socketFd, &socketP);
860 xmlrpc_faultf(envP, "Unable to create Abyss socket out of "
861 "file descriptor %d.", socketFd);
863 ServerCreateSocket2(serverP, socketP, &error);
865 xmlrpc_faultf(envP, "Abyss failed to create server. %s",
867 xmlrpc_strfree(error);
871 ServerSetName(serverP, "XmlRpcServer");
874 ServerSetLogFileName(serverP, logFileName);
876 if (envP->fault_occurred)
877 SocketDestroy(socketP);
884 createServer(xmlrpc_env * const envP,
885 const xmlrpc_server_abyss_parms * const parmsP,
886 unsigned int const parmSize,
887 TServer * const serverP,
888 TSocket ** const socketPP) {
889 /*----------------------------------------------------------------------------
890 Create a bare server. It will need further setup before it is ready
892 -----------------------------------------------------------------------------*/
893 abyss_bool socketBound;
894 unsigned int portNumber;
896 const char * logFileName;
898 extractServerCreateParms(envP, parmsP, parmSize,
899 &socketBound, &portNumber, &socketFd,
902 if (!envP->fault_occurred) {
904 createServerBoundSocket(envP, socketFd, logFileName,
907 ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS,
913 xmlrpc_strfree(logFileName);
920 chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP,
921 unsigned int const parmSize) {
924 parmSize >= XMLRPC_APSIZE(chunk_response) &&
925 parmsP->chunk_response;
931 uriPathParm(const xmlrpc_server_abyss_parms * const parmsP,
932 unsigned int const parmSize) {
934 const char * uriPath;
936 if (parmSize >= XMLRPC_APSIZE(uri_path) && parmsP->uri_path)
937 uriPath = parmsP->uri_path;
946 static xmlrpc_server_shutdown_fn shutdownAbyss;
949 shutdownAbyss(xmlrpc_env * const envP,
950 void * const context,
951 const char * const comment ATTR_UNUSED) {
952 /*----------------------------------------------------------------------------
953 Tell Abyss to wrap up whatever it's doing and shut down.
955 This is a server shutdown function to be registered in the method
956 registry, for use by the 'system.shutdown' system method.
958 After we return, Abyss will finish up the system.shutdown and any
959 other connections that are in progress, then the call to
960 ServerRun() etc. will return. But Abyss may be stuck waiting for
961 something, such as the next HTTP connection. In that case, until it
962 gets what it's waiting for, it won't even know it's supposed t shut
963 down. In particular, a caller of system.shutdown may have to execute
964 one more RPC in order for the shutdown to happen.
965 -----------------------------------------------------------------------------*/
966 TServer * const serverP = context;
968 xmlrpc_env_init(envP);
970 ServerTerminate(serverP);
976 normalLevelAbyssRun(xmlrpc_env * const envP,
977 const xmlrpc_server_abyss_parms * const parmsP,
978 unsigned int const parmSize) {
985 createServer(envP, parmsP, parmSize, &server, &socketP);
987 if (!envP->fault_occurred) {
988 struct signalHandlers oldHandlers;
990 setAdditionalServerParms(parmsP, parmSize, &server);
992 setHandlers(&server, uriPathParm(parmsP, parmSize), parmsP->registryP,
993 chunkResponseParm(parmsP, parmSize));
997 setupSignalHandlers(&oldHandlers);
999 ServerUseSigchld(&server);
1002 /* Too much of a security risk. In 1.07, there is a server
1003 parameter to enable this.
1005 xmlrpc_registry_set_shutdown(parmsP->registryP,
1006 &shutdownAbyss, &server);
1010 restoreSignalHandlers(oldHandlers);
1012 ServerFree(&server);
1015 SocketDestroy(socketP);
1022 xmlrpc_server_abyss(xmlrpc_env * const envP,
1023 const xmlrpc_server_abyss_parms * const parmsP,
1024 unsigned int const parmSize) {
1026 XMLRPC_ASSERT_ENV_OK(envP);
1028 if (parmSize < XMLRPC_APSIZE(registryP))
1030 "You must specify members at least up through "
1031 "'registryP' in the server parameters argument. "
1032 "That would mean the parameter size would be >= %lu "
1033 "but you specified a size of %u",
1034 XMLRPC_APSIZE(registryP), parmSize);
1036 if (parmsP->config_file_name)
1037 oldHighLevelAbyssRun(envP, parmsP, parmSize);
1039 normalLevelAbyssRun(envP, parmsP, parmSize);
1045 /*=========================================================================
1046 XML-RPC Server Method Registry
1048 This is an old deprecated form of the server facilities that uses
1050 =========================================================================*/
1052 /* These global variables must be treated as read-only after the
1056 static TServer globalSrv;
1057 /* When you use the old interface (xmlrpc_server_abyss_init(), etc.),
1058 this is the Abyss server to which they refer. Obviously, there can be
1059 only one Abyss server per program using this interface.
1062 static xmlrpc_registry * builtin_registryP;
1067 xmlrpc_server_abyss_init_registry(void) {
1069 /* This used to just create the registry and Caller would be
1070 responsible for adding the handlers that use it.
1072 But that isn't very modular -- the handlers and registry go
1073 together; there's no sense in using the built-in registry and
1074 not the built-in handlers because if you're custom building
1075 something, you can just make your own regular registry. So now
1076 we tie them together, and we don't export our handlers.
1080 xmlrpc_env_init(&env);
1081 builtin_registryP = xmlrpc_registry_new(&env);
1082 die_if_fault_occurred(&env);
1083 xmlrpc_env_clean(&env);
1085 setHandlers(&globalSrv, "/RPC2", builtin_registryP, false);
1091 xmlrpc_server_abyss_registry(void) {
1093 /* This is highly deprecated. If you want to mess with a registry,
1094 make your own with xmlrpc_registry_new() -- don't mess with the
1097 return builtin_registryP;
1102 /* A quick & easy shorthand for adding a method. */
1104 xmlrpc_server_abyss_add_method(char * const method_name,
1105 xmlrpc_method const method,
1106 void * const user_data) {
1109 xmlrpc_env_init(&env);
1110 xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name,
1112 die_if_fault_occurred(&env);
1113 xmlrpc_env_clean(&env);
1119 xmlrpc_server_abyss_add_method_w_doc(char * const method_name,
1120 xmlrpc_method const method,
1121 void * const user_data,
1122 char * const signature,
1123 char * const help) {
1126 xmlrpc_env_init(&env);
1127 xmlrpc_registry_add_method_w_doc(
1128 &env, builtin_registryP, NULL, method_name,
1129 method, user_data, signature, help);
1130 die_if_fault_occurred(&env);
1131 xmlrpc_env_clean(&env);
1137 xmlrpc_server_abyss_init(int const flags ATTR_UNUSED,
1138 const char * const config_file) {
1143 ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
1145 ConfReadServerFile(config_file, &globalSrv);
1147 xmlrpc_server_abyss_init_registry();
1148 /* Installs /RPC2 handler and default handler that use the
1152 ServerInit(&globalSrv);
1158 xmlrpc_server_abyss_run_first(runfirstFn const runfirst,
1159 void * const runfirstArg) {
1161 runServerDaemon(&globalSrv, runfirst, runfirstArg);
1167 xmlrpc_server_abyss_run(void) {
1168 runServerDaemon(&globalSrv, NULL, NULL);
1174 ** Copyright (C) 2001 by First Peer, Inc. All rights reserved.
1176 ** Redistribution and use in source and binary forms, with or without
1177 ** modification, are permitted provided that the following conditions
1179 ** 1. Redistributions of source code must retain the above copyright
1180 ** notice, this list of conditions and the following disclaimer.
1181 ** 2. Redistributions in binary form must reproduce the above copyright
1182 ** notice, this list of conditions and the following disclaimer in the
1183 ** documentation and/or other materials provided with the distribution.
1184 ** 3. The name of the author may not be used to endorse or promote products
1185 ** derived from this software without specific prior written permission.
1187 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1188 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1189 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1190 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1191 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1192 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1193 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1194 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1195 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1196 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1199 ** There is more copyright information in the bottom half of this file.
1200 ** Please see it for more details.