initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_server_abyss.c
1 /* Copyright information is at the end of the file */
2
3 #include "xmlrpc_config.h"
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <time.h>
11 #include <fcntl.h>
12 #ifdef _WIN32
13 #  include <io.h>
14 #else
15 #  include <signal.h>
16 #  include <sys/wait.h>
17 #  include <grp.h>
18 #endif
19
20 #include "mallocvar.h"
21 #include "xmlrpc-c/abyss.h"
22
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"
28
29
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.
35 */
36
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);
41         exit(1);
42     }
43 }
44
45
46
47 static void
48 addAuthCookie(xmlrpc_env * const envP,
49               TSession *   const abyssSessionP,
50               const char * const authCookie) {
51
52     const char * cookieResponse;
53     
54     xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie);
55     
56     if (cookieResponse == xmlrpc_strsol)
57         xmlrpc_faultf(envP, "Insufficient memory to generate cookie "
58                       "response header.");
59     else {
60         ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse);
61     
62         xmlrpc_strfree(cookieResponse);
63     }
64 }   
65     
66
67
68 static void 
69 sendXmlData(xmlrpc_env * const envP,
70             TSession *   const abyssSessionP, 
71             const char * const body, 
72             size_t       const len,
73             bool         const chunked) {
74 /*----------------------------------------------------------------------------
75    Generate an HTTP response containing body 'body' of length 'len'
76    characters.
77
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.
85            - Bryan 2004.10.03.
86         */
87
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.
94
95        In 1.06 we added the user option to chunk.
96     */
97     if (chunked)
98         ResponseChunked(abyssSessionP);
99
100     ResponseStatus(abyssSessionP, 200);
101
102     if (http_cookie)
103         /* There's an auth cookie, so pass it back in the response. */
104         addAuthCookie(envP, abyssSessionP, http_cookie);
105
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");
109     else {
110         uint32_t const abyssLen = (uint32_t)len;
111
112         ResponseContentType(abyssSessionP, "text/xml; charset=\"utf-8\"");
113         ResponseContentLength(abyssSessionP, abyssLen);
114         
115         ResponseWriteStart(abyssSessionP);
116         ResponseWriteBody(abyssSessionP, body, abyssLen);
117         ResponseWriteEnd(abyssSessionP);
118     }
119 }
120
121
122
123 static void
124 sendError(TSession *   const abyssSessionP, 
125           unsigned int const status) {
126 /*----------------------------------------------------------------------------
127   Send an error response back to the client.
128    
129 -----------------------------------------------------------------------------*/
130     ResponseStatus(abyssSessionP, (uint16_t) status);
131     ResponseError(abyssSessionP);
132 }
133
134
135
136 static void
137 traceChunkRead(TSession * const abyssSessionP) {
138
139     fprintf(stderr, "XML-RPC handler got a chunk of %u bytes\n",
140             (unsigned int)SessionReadDataAvail(abyssSessionP));
141 }
142
143
144
145 static void
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;
153
154     succeeded = SessionRefillBuffer(abyssSessionP);
155
156     if (!succeeded)
157         xmlrpc_env_set_fault_formatted(
158             envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for "
159             "client to send its POST data");
160     else {
161         if (trace)
162             traceChunkRead(abyssSessionP);
163     }
164 }
165
166
167
168 static void
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.
177
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;
182
183     if (trace)
184         fprintf(stderr, "XML-RPC handler processing body.  "
185                 "Content Size = %u bytes\n", (unsigned)contentSize);
186
187     body = xmlrpc_mem_block_new(envP, 0);
188     if (!envP->fault_occurred) {
189         size_t bytesRead;
190         const char * chunkPtr;
191         size_t chunkLen;
192
193         bytesRead = 0;
194
195         while (!envP->fault_occurred && bytesRead < contentSize) {
196             SessionGetReadData(abyssSessionP, contentSize - bytesRead, 
197                                &chunkPtr, &chunkLen);
198             bytesRead += chunkLen;
199
200             assert(bytesRead <= contentSize);
201
202             XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen);
203             if (bytesRead < contentSize)
204                 refillBufferFromConnection(envP, abyssSessionP, trace);
205         }
206         if (envP->fault_occurred)
207             xmlrpc_mem_block_free(body);
208         else
209             *bodyP = body;
210     }
211 }
212
213
214
215 static void
216 storeCookies(TSession *     const httpRequestP,
217              unsigned int * const httpErrorP) {
218 /*----------------------------------------------------------------------------
219    Get the cookie settings from the HTTP headers and remember them for
220    use in responses.
221 -----------------------------------------------------------------------------*/
222     const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
223     if (cookie) {
224         /* 
225            Setting the value in an environment variable doesn't make
226            any sense.  So for now, cookie code is disabled.
227            -Bryan 04.10.03.
228
229         setenv("HTTP_COOKIE", cookie, 1);
230         */
231     }
232     /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */
233
234     *httpErrorP = 0;
235 }
236
237
238
239
240 static void
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");
251
252     if (content_type == NULL)
253         *httpErrorP = 400;
254     else {
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"
259             */
260
261         if (sempos)
262             baselen = sempos - content_type;
263         else
264             baselen = strlen(content_type);
265
266         if (!xmlrpc_strneq(content_type, "text/xml", baselen))
267             *httpErrorP = 400;
268         else
269             *httpErrorP = 0;
270     }
271 }
272
273
274
275 static void
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");
287
288     if (content_length == NULL)
289         *httpErrorP = 411;
290     else {
291         if (content_length[0] == '\0')
292             *httpErrorP = 400;
293         else {
294             unsigned long contentLengthValue;
295             char * tail;
296         
297             contentLengthValue = strtoul(content_length, &tail, 10);
298         
299             if (*tail != '\0')
300                 /* There's non-numeric crap in the length */
301                 *httpErrorP = 400;
302             else if (contentLengthValue < 1)
303                 *httpErrorP = 400;
304             else if ((unsigned long)(size_t)contentLengthValue 
305                      != contentLengthValue)
306                 *httpErrorP = 400;
307             else {
308                 *httpErrorP = 0;
309                 *inputLenP = (size_t)contentLengthValue;
310             }
311         }
312     }
313 }
314
315
316
317 static void
318 traceHandlerCalled(TSession * const abyssSessionP) {
319     
320     const char * methodDesc;
321     const TRequestInfo * requestInfoP;
322
323     fprintf(stderr, "xmlrpc_server_abyss URI path handler called.\n");
324
325     SessionGetRequestInfo(abyssSessionP, &requestInfoP);
326
327     fprintf(stderr, "URI = '%s'\n", requestInfoP->uri);
328
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 = "?";
339     }
340     fprintf(stderr, "HTTP method = '%s'\n", methodDesc);
341
342     if (requestInfoP->query)
343         fprintf(stderr, "query (component of URL)='%s'\n",
344                 requestInfoP->query);
345     else
346         fprintf(stderr, "URL has no query component\n");
347 }
348
349
350
351 static void
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.
360
361    Its content length is 'contentSize' bytes.
362 -----------------------------------------------------------------------------*/
363     xmlrpc_env env;
364
365     if (trace)
366         fprintf(stderr,
367                 "xmlrpc_server_abyss URI path handler processing RPC.\n");
368
369     xmlrpc_env_init(&env);
370
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);
375     else {
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),
391                             wantChunk);
392                 
393                 XMLRPC_MEMBLOCK_FREE(char, output);
394             }
395             XMLRPC_MEMBLOCK_FREE(char, body);
396         }
397     }
398     if (env.fault_occurred) {
399         if (env.fault_code == XMLRPC_TIMEOUT_ERROR)
400             sendError(abyssSessionP, 408); /* 408 Request Timeout */
401         else
402             sendError(abyssSessionP, 500); /* 500 Internal Server Error */
403     }
404
405     xmlrpc_env_clean(&env);
406 }
407
408
409
410 /****************************************************************************
411     Abyss handlers (to be registered with and called by Abyss)
412 ****************************************************************************/
413
414 static const char * trace_abyss;
415
416
417
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 */
425     bool              chunkResponse;
426         /* The handler should chunk its response whenever possible */
427 };
428
429
430
431 static void
432 termUriHandler(void * const arg) {
433
434     struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = arg;
435
436     xmlrpc_strfree(uriHandlerXmlrpcP->uriPath);
437     free(uriHandlerXmlrpcP);
438 }
439
440
441
442 static void
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.
451
452    Our return code is TRUE to mean we handled it; FALSE to mean we didn't.
453
454    Note that failing the request counts as handling it, and not handling
455    it does not mean we failed it.
456
457    This is an Abyss HTTP Request handler -- type URIHandler2.
458 -----------------------------------------------------------------------------*/
459     struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = this->userdata;
460
461     const TRequestInfo * requestInfoP;
462
463     if (trace_abyss)
464         traceHandlerCalled(abyssSessionP);
465
466     SessionGetRequestInfo(abyssSessionP, &requestInfoP);
467
468     /* Note that requestInfoP->uri is not the whole URI.  It is just
469        the "file name" part of it.
470     */
471     if (strcmp(requestInfoP->uri, uriHandlerXmlrpcP->uriPath) != 0)
472         /* It's for the path (e.g. "/RPC2") that we're supposed to
473            handle.
474         */
475         *handledP = FALSE;
476     else {
477         *handledP = TRUE;
478
479         /* We understand only the POST HTTP method.  For anything else, return
480            "405 Method Not Allowed". 
481         */
482         if (requestInfoP->method != m_post)
483             sendError(abyssSessionP, 405);
484         else {
485             unsigned int httpError;
486             storeCookies(abyssSessionP, &httpError);
487             if (httpError)
488                 sendError(abyssSessionP, httpError);
489             else {
490                 unsigned int httpError;
491                 validateContentType(abyssSessionP, &httpError);
492                 if (httpError)
493                     sendError(abyssSessionP, httpError);
494                 else {
495                     unsigned int httpError;
496                     size_t contentSize;
497
498                     processContentLength(abyssSessionP, 
499                                          &contentSize, &httpError);
500                     if (httpError)
501                         sendError(abyssSessionP, httpError);
502                     else 
503                         processCall(abyssSessionP, contentSize,
504                                     uriHandlerXmlrpcP->registryP,
505                                     uriHandlerXmlrpcP->chunkResponse,
506                                     trace_abyss);
507                 }
508             }
509         }
510     }
511     if (trace_abyss)
512         fprintf(stderr, "xmlrpc_server_abyss URI path handler returning.\n");
513 }
514
515
516
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.
522 */
523
524 static xmlrpc_bool 
525 xmlrpc_server_abyss_default_handler(TSession * const sessionP) {
526
527     if (trace_abyss)
528         fprintf(stderr, "xmlrpc_server_abyss default handler called.\n");
529
530     sendError(sessionP, 404);
531
532     return TRUE;
533 }
534
535
536
537 static void 
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).
542
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 -----------------------------------------------------------------------------*/
548 #ifndef WIN32
549     bool childrenLeft;
550     bool error;
551
552     assert(signalClass == SIGCHLD);
553
554     error = false;
555     childrenLeft = true;  /* initial assumption */
556     
557     /* Reap defunct children until there aren't any more. */
558     while (childrenLeft && !error) {
559         int status;
560         pid_t pid;
561
562         pid = waitpid((pid_t) -1, &status, WNOHANG);
563     
564         if (pid == 0)
565             childrenLeft = false;
566         else if (pid < 0) {
567             /* because of ptrace */
568             if (errno != EINTR)   
569                 error = true;
570         } else
571             ServerHandleSigchld(pid);
572     }
573 #endif /* WIN32 */
574 }
575
576
577 struct signalHandlers {
578     struct sigaction pipe;
579     struct sigaction chld;
580 };
581
582
583
584 static void
585 setupSignalHandlers(struct signalHandlers * const oldHandlersP) {
586 #ifndef WIN32
587     struct sigaction mysigaction;
588     
589     sigemptyset(&mysigaction.sa_mask);
590     mysigaction.sa_flags = 0;
591
592     /* This signal indicates connection closed in the middle */
593     mysigaction.sa_handler = SIG_IGN;
594     sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe);
595     
596     /* This signal indicates a child process (request handler) has died */
597     mysigaction.sa_handler = sigchld;
598     sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld);
599 #endif
600 }    
601
602
603
604 static void
605 restoreSignalHandlers(struct signalHandlers const oldHandlers) {
606 #ifndef WIN32
607
608     sigaction(SIGPIPE, &oldHandlers.pipe, NULL);
609     sigaction(SIGCHLD, &oldHandlers.chld, NULL);
610
611 #endif
612 }
613
614
615
616 static void
617 runServerDaemon(TServer *  const serverP,
618                 runfirstFn const runfirst,
619                 void *     const runfirstArg) {
620
621     struct signalHandlers oldHandlers;
622
623     setupSignalHandlers(&oldHandlers);
624
625     ServerUseSigchld(serverP);
626
627     ServerDaemonize(serverP);
628     
629     /* We run the user supplied runfirst after forking, but before accepting
630        connections (helpful when running with threads)
631     */
632     if (runfirst)
633         runfirst(runfirstArg);
634
635     ServerRun(serverP);
636
637     restoreSignalHandlers(oldHandlers);
638 }
639
640
641
642 static void
643 setHandler(xmlrpc_env *      const envP,
644            TServer *         const srvP,
645            const char *      const uriPath,
646            xmlrpc_registry * const registryP,
647            bool              const chunkResponse) {
648     
649     struct uriHandlerXmlrpc * uriHandlerXmlrpcP;
650     URIHandler2 uriHandler;
651     abyss_bool success;
652
653     trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
654                                  
655     MALLOCVAR_NOFAIL(uriHandlerXmlrpcP);
656
657     uriHandlerXmlrpcP->registryP     = registryP;
658     uriHandlerXmlrpcP->uriPath       = strdup(uriPath);
659     uriHandlerXmlrpcP->chunkResponse = chunkResponse;
660
661     uriHandler.handleReq2 = handleXmlrpcReq;
662     uriHandler.handleReq1 = NULL;
663     uriHandler.userdata   = uriHandlerXmlrpcP;
664     uriHandler.init       = NULL;
665     uriHandler.term       = &termUriHandler;
666
667     ServerAddHandler2(srvP, &uriHandler, &success);
668
669     if (!success)
670         xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request "
671                       "handler.  ServerAddHandler2() failed.");
672
673     if (envP->fault_occurred)
674         free(uriHandlerXmlrpcP);
675 }
676
677
678
679 void
680 xmlrpc_server_abyss_set_handler(xmlrpc_env *      const envP,
681                                 TServer *         const srvP,
682                                 const char *      const uriPath,
683                                 xmlrpc_registry * const registryP) {
684
685     setHandler(envP, srvP, uriPath, registryP, false);
686 }
687
688     
689
690 static void
691 setHandlers(TServer *         const srvP,
692             const char *      const uriPath,
693             xmlrpc_registry * const registryP,
694             bool              const chunkResponse) {
695
696     xmlrpc_env env;
697
698     xmlrpc_env_init(&env);
699
700     trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
701                                  
702     setHandler(&env, srvP, uriPath, registryP, chunkResponse);
703     
704     if (env.fault_occurred)
705         abort();
706
707     ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler);
708
709     xmlrpc_env_clean(&env);
710 }
711
712
713
714 void
715 xmlrpc_server_abyss_set_handlers2(TServer *         const srvP,
716                                   const char *      const uriPath,
717                                   xmlrpc_registry * const registryP) {
718
719     setHandlers(srvP, uriPath, registryP, false);
720 }
721
722
723
724 void
725 xmlrpc_server_abyss_set_handlers(TServer *         const srvP,
726                                  xmlrpc_registry * const registryP) {
727
728     setHandlers(srvP, "/RPC2", registryP, false);
729 }
730
731
732
733 static void
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.
742
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
746    flexible API.
747 -----------------------------------------------------------------------------*/
748     TServer server;
749     runfirstFn runfirst;
750     void * runfirstArg;
751     
752     DateInit();
753     
754     ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
755     
756     ConfReadServerFile(parmsP->config_file_name, &server);
757         
758     setHandlers(&server, "/RPC2", parmsP->registryP, false);
759         
760     ServerInit(&server);
761     
762     if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) {
763         runfirst    = parmsP->runfirst;
764         runfirstArg = parmsP->runfirst_arg;
765     } else {
766         runfirst    = NULL;
767         runfirstArg = NULL;
768     }
769     runServerDaemon(&server, runfirst, runfirstArg);
770
771     ServerFree(&server);
772 }
773
774
775
776 static void
777 setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP,
778                          unsigned int                      const parmSize,
779                          TServer *                         const serverP) {
780
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.  
784     */
785
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) &&
793         parmsP->timeout > 0)
794         ServerSetTimeout(serverP, parmsP->timeout);
795     if (parmSize >= XMLRPC_APSIZE(dont_advertise))
796         ServerSetAdvertise(serverP, !parmsP->dont_advertise);
797 }
798
799
800
801 static void
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) {
810                    
811
812     if (parmSize >= XMLRPC_APSIZE(socket_bound))
813         *socketBoundP = parmsP->socket_bound;
814     else
815         *socketBoundP = FALSE;
816
817     if (*socketBoundP) {
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 "
821                           "short)");
822         else
823             *socketFdP = parmsP->socket_handle;
824     } else {
825         if (parmSize >= XMLRPC_APSIZE(port_number))
826             *portNumberP = parmsP->port_number;
827         else
828             *portNumberP = 8080;
829
830         if (*portNumberP > 0xffff)
831             xmlrpc_faultf(envP,
832                           "TCP port number %u exceeds the maximum possible "
833                           "TCP port number (65535)",
834                           *portNumberP);
835     }
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);
840         else
841             *logFileNameP = NULL;
842     }
843 }
844
845
846
847 static void
848 createServerBoundSocket(xmlrpc_env * const envP,
849                         TOsSocket    const socketFd,
850                         const char * const logFileName,
851                         TServer *    const serverP,
852                         TSocket **   const socketPP) {
853
854     TSocket * socketP;
855     const char * error;
856     
857     SocketUnixCreateFd(socketFd, &socketP);
858     
859     if (!socketP)
860         xmlrpc_faultf(envP, "Unable to create Abyss socket out of "
861                       "file descriptor %d.", socketFd);
862     else {
863         ServerCreateSocket2(serverP, socketP, &error);
864         if (error) {
865             xmlrpc_faultf(envP, "Abyss failed to create server.  %s",
866                           error);
867             xmlrpc_strfree(error);
868         } else {
869             *socketPP = socketP;
870                     
871             ServerSetName(serverP, "XmlRpcServer");
872             
873             if (logFileName)
874                 ServerSetLogFileName(serverP, logFileName);
875         }
876         if (envP->fault_occurred)
877                     SocketDestroy(socketP);
878     }
879 }
880
881
882
883 static void
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
891    to use.
892 -----------------------------------------------------------------------------*/
893     abyss_bool socketBound;
894     unsigned int portNumber;
895     TOsSocket socketFd;
896     const char * logFileName;
897
898     extractServerCreateParms(envP, parmsP, parmSize,
899                              &socketBound, &portNumber, &socketFd,
900                              &logFileName);
901
902     if (!envP->fault_occurred) {
903         if (socketBound)
904             createServerBoundSocket(envP, socketFd, logFileName,
905                                     serverP, socketPP);
906         else {
907             ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS, 
908                          logFileName);
909             
910             *socketPP = NULL;
911         }
912         if (logFileName)
913             xmlrpc_strfree(logFileName);
914     }
915 }
916
917
918
919 static bool
920 chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP,
921                   unsigned int                      const parmSize) {
922
923     return
924         parmSize >= XMLRPC_APSIZE(chunk_response) &&
925         parmsP->chunk_response;
926 }    
927
928
929
930 static const char *
931 uriPathParm(const xmlrpc_server_abyss_parms * const parmsP,
932             unsigned int                      const parmSize) {
933     
934     const char * uriPath;
935
936     if (parmSize >= XMLRPC_APSIZE(uri_path) && parmsP->uri_path)
937         uriPath = parmsP->uri_path;
938     else
939         uriPath = "/RPC2";
940
941     return uriPath;
942 }
943
944
945
946 static xmlrpc_server_shutdown_fn shutdownAbyss;
947
948 static void
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.
954
955    This is a server shutdown function to be registered in the method
956    registry, for use by the 'system.shutdown' system method.
957
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;
967
968     xmlrpc_env_init(envP);
969     
970     ServerTerminate(serverP);
971 }
972
973
974
975 static void
976 normalLevelAbyssRun(xmlrpc_env *                      const envP,
977                     const xmlrpc_server_abyss_parms * const parmsP,
978                     unsigned int                      const parmSize) {
979     
980     TServer server;
981     TSocket * socketP;
982
983     DateInit();
984
985     createServer(envP, parmsP, parmSize, &server, &socketP);
986
987     if (!envP->fault_occurred) {
988         struct signalHandlers oldHandlers;
989
990         setAdditionalServerParms(parmsP, parmSize, &server);
991
992         setHandlers(&server, uriPathParm(parmsP, parmSize), parmsP->registryP,
993                     chunkResponseParm(parmsP, parmSize));
994
995         ServerInit(&server);
996         
997         setupSignalHandlers(&oldHandlers);
998
999         ServerUseSigchld(&server);
1000         
1001         if (0)
1002             /* Too much of a security risk.  In 1.07, there is a server
1003                parameter to enable this.
1004             */
1005             xmlrpc_registry_set_shutdown(parmsP->registryP,
1006                                          &shutdownAbyss, &server);
1007         
1008         ServerRun(&server);
1009
1010         restoreSignalHandlers(oldHandlers);
1011
1012         ServerFree(&server);
1013
1014         if (socketP)
1015             SocketDestroy(socketP);
1016     }
1017 }
1018
1019
1020
1021 void
1022 xmlrpc_server_abyss(xmlrpc_env *                      const envP,
1023                     const xmlrpc_server_abyss_parms * const parmsP,
1024                     unsigned int                      const parmSize) {
1025  
1026     XMLRPC_ASSERT_ENV_OK(envP);
1027
1028     if (parmSize < XMLRPC_APSIZE(registryP))
1029         xmlrpc_faultf(envP,
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);
1035     else {
1036         if (parmsP->config_file_name)
1037             oldHighLevelAbyssRun(envP, parmsP, parmSize);
1038         else
1039             normalLevelAbyssRun(envP, parmsP, parmSize);
1040     }
1041 }
1042
1043
1044
1045 /*=========================================================================
1046   XML-RPC Server Method Registry
1047
1048   This is an old deprecated form of the server facilities that uses
1049   global variables.
1050 =========================================================================*/
1051
1052 /* These global variables must be treated as read-only after the
1053    server has started.
1054 */
1055
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.
1060     */
1061
1062 static xmlrpc_registry * builtin_registryP;
1063
1064
1065
1066 void 
1067 xmlrpc_server_abyss_init_registry(void) {
1068
1069     /* This used to just create the registry and Caller would be
1070        responsible for adding the handlers that use it.
1071
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.  
1077     */
1078     xmlrpc_env env;
1079
1080     xmlrpc_env_init(&env);
1081     builtin_registryP = xmlrpc_registry_new(&env);
1082     die_if_fault_occurred(&env);
1083     xmlrpc_env_clean(&env);
1084
1085     setHandlers(&globalSrv, "/RPC2", builtin_registryP, false);
1086 }
1087
1088
1089
1090 xmlrpc_registry *
1091 xmlrpc_server_abyss_registry(void) {
1092
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
1095        internal one.
1096     */
1097     return builtin_registryP;
1098 }
1099
1100
1101
1102 /* A quick & easy shorthand for adding a method. */
1103 void 
1104 xmlrpc_server_abyss_add_method(char *        const method_name,
1105                                xmlrpc_method const method,
1106                                void *        const user_data) {
1107     xmlrpc_env env;
1108
1109     xmlrpc_env_init(&env);
1110     xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name,
1111                                method, user_data);
1112     die_if_fault_occurred(&env);
1113     xmlrpc_env_clean(&env);
1114 }
1115
1116
1117
1118 void
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) {
1124
1125     xmlrpc_env env;
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);    
1132 }
1133
1134
1135
1136 void 
1137 xmlrpc_server_abyss_init(int          const flags ATTR_UNUSED, 
1138                          const char * const config_file) {
1139
1140     DateInit();
1141     MIMETypeInit();
1142
1143     ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
1144     
1145     ConfReadServerFile(config_file, &globalSrv);
1146
1147     xmlrpc_server_abyss_init_registry();
1148         /* Installs /RPC2 handler and default handler that use the
1149            built-in registry.
1150         */
1151
1152     ServerInit(&globalSrv);
1153 }
1154
1155
1156
1157 void 
1158 xmlrpc_server_abyss_run_first(runfirstFn const runfirst,
1159                               void *     const runfirstArg) {
1160     
1161     runServerDaemon(&globalSrv, runfirst, runfirstArg);
1162 }
1163
1164
1165
1166 void 
1167 xmlrpc_server_abyss_run(void) {
1168     runServerDaemon(&globalSrv, NULL, NULL);
1169 }
1170
1171
1172
1173 /*
1174 ** Copyright (C) 2001 by First Peer, Inc. All rights reserved.
1175 **
1176 ** Redistribution and use in source and binary forms, with or without
1177 ** modification, are permitted provided that the following conditions
1178 ** are met:
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. 
1186 **  
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
1197 ** SUCH DAMAGE.
1198 **
1199 ** There is more copyright information in the bottom half of this file. 
1200 ** Please see it for more details. 
1201 */