Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c
Location:line 835, column 9
Description:Function call argument is an uninitialized value

Annotated Source Code

1/* Copyright information is at the end of the file */
2
3#include "xmlrpc_config.h"
4
5#define _XOPEN_SOURCE700 600 /* For strdup(), sigaction */
6
7#include <assert.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <errno(*__errno_location ()).h>
12#include <time.h>
13#include <fcntl.h>
14#ifdef _WIN32
15# include <io.h>
16#else
17# include <signal.h>
18# include <sys/wait.h>
19# include <grp.h>
20#endif
21
22#include "bool.h"
23#include "int.h"
24#include "mallocvar.h"
25#include "xmlrpc-c/abyss.h"
26
27#include "xmlrpc-c/base.h"
28#include "xmlrpc-c/server.h"
29#include "xmlrpc-c/base_int.h"
30#include "xmlrpc-c/string_int.h"
31#include "xmlrpc-c/server_abyss.h"
32
33
34
35struct xmlrpc_server_abyss {
36 TServer abyssServer;
37 TChanSwitch * chanSwitchP;
38 bool shutdownEnabled;
39 /* User wants system.shutdown to succeed */
40};
41
42
43
44static void
45dieIfFaultOccurred(xmlrpc_env * const envP) {
46
47 if (envP->fault_occurred) {
48 fprintf(stderrstderr, "Unexpected XML-RPC fault: %s (%d)\n",
49 envP->fault_string, envP->fault_code);
50 exit(1);
51 }
52}
53
54
55
56static void
57initAbyss(xmlrpc_env * const envP) {
58
59 const char * error;
60 AbyssInit(&error);
61 if (error) {
62 xmlrpc_faultf(envP, "Failed to initialize the Abyss library. %s",
63 error);
64 xmlrpc_strfree(error);
65 }
66}
67
68
69
70static void
71termAbyss(void) {
72
73 AbyssTerm();
74}
75
76
77
78static unsigned int globallyInitialized = 0;
79 /* Initialization count */
80
81
82void
83xmlrpc_server_abyss_global_init(xmlrpc_env * const envP) {
84
85 /* Note that this is specified as not thread safe; user calls it at
86 the beginning of his program, when it is only one thread.
87 */
88
89 XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string
== ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 89); while
(0)
;
90
91 if (globallyInitialized == 0)
92 initAbyss(envP);
93
94 ++globallyInitialized;
95}
96
97
98
99void
100xmlrpc_server_abyss_global_term(void) {
101
102 /* Note that this is specified as not thread safe; user calls it at
103 the end of his program, when it is only one thread.
104 */
105
106 XMLRPC_ASSERT(globallyInitialized > 0)do if (!(globallyInitialized > 0)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 106);
while (0)
;
107
108 --globallyInitialized;
109
110 if (globallyInitialized == 0)
111 termAbyss();
112}
113
114
115
116static void
117validateGlobalInit(xmlrpc_env * const envP) {
118
119 if (!globallyInitialized)
120 xmlrpc_faultf(envP, "libxmlrpc_server_abyss has not been globally "
121 "initialized. See xmlrpc_server_abyss_init()");
122}
123
124
125
126static void
127addAuthCookie(xmlrpc_env * const envP,
128 TSession * const abyssSessionP,
129 const char * const authCookie) {
130
131 const char * cookieResponse;
132
133 xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie);
134
135 if (xmlrpc_strnomem(cookieResponse))
136 xmlrpc_faultf(envP, "Insufficient memory to generate cookie "
137 "response header.");
138 else {
139 ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse);
140
141 xmlrpc_strfree(cookieResponse);
142 }
143}
144
145
146
147static void
148sendResponse(xmlrpc_env * const envP,
149 TSession * const abyssSessionP,
150 const char * const body,
151 size_t const len,
152 bool const chunked,
153 ResponseAccessCtl const accessControl) {
154/*----------------------------------------------------------------------------
155 Generate an HTTP response containing body 'body' of length 'len'
156 characters.
157
158 This is meant to run in the context of an Abyss URI handler for
159 Abyss session 'abyssSessionP'.
160-----------------------------------------------------------------------------*/
161 const char * http_cookie = NULL((void*)0);
162 /* This used to set http_cookie to getenv("HTTP_COOKIE"), but
163 that doesn't make any sense -- environment variables are not
164 appropriate for this. So for now, cookie code is disabled.
165 - Bryan 2004.10.03.
166 */
167
168 /* Various bugs before Xmlrpc-c 1.05 caused the response to be not
169 chunked in the most basic case, but chunked if the client explicitly
170 requested keepalive. I think it's better not to chunk, because
171 it's simpler, so I removed this in 1.05. I don't know what the
172 purpose of chunking would be, and an original comment suggests
173 the author wasn't sure chunking was a good idea.
174
175 In 1.06 we added the user option to chunk.
176 */
177 if (chunked)
178 ResponseChunked(abyssSessionP);
179
180 ResponseStatus(abyssSessionP, 200);
181
182 if (http_cookie)
183 /* There's an auth cookie, so pass it back in the response. */
184 addAuthCookie(envP, abyssSessionP, http_cookie);
185
186 if ((size_t)(uint32_t)len != len)
187 xmlrpc_faultf(envP, "XML-RPC method generated a response too "
188 "large for Abyss to send");
189 else {
190 uint32_t const abyssLen = (uint32_t)len;
191
192 /* See discussion below of quotes around "utf-8" */
193 ResponseContentType(abyssSessionP, "text/xml");
194 ResponseContentLength(abyssSessionP, abyssLen);
195 ResponseAccessControl(abyssSessionP, accessControl);
196
197 if (ResponseWriteStart(abyssSessionP))
198 if (ResponseWriteBody(abyssSessionP, body, abyssLen))
199 if (ResponseWriteEnd(abyssSessionP))
200 return;
201
202 xmlrpc_faultf(envP, "socket send() problem");
203 }
204}
205
206
207
208/* From 0.9.10 (May 2001) through 1.17 (December 2008), the content-type
209 header said charset="utf-8" (i.e. with the value of 'charset' an HTTP quoted
210 string). Before 0.9.10, the header didn't have charset at all.
211
212 We got a complaint in January 2009 that some client didn't understand that,
213 saying
214
215 apache2: XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of
216 received response: "UTF-8"
217
218 And that removing the quotation marks fixes this.
219
220 From what I can tell, the module is wrong to distinguish between the
221 two, but I don't think it hurts anything to use a basic HTTP token instead
222 of an HTTP quoted string here, so starting in 1.18, we do. */
223
224
225static void
226sendError(TSession * const abyssSessionP,
227 unsigned int const status,
228 const char * const explanation) {
229/*----------------------------------------------------------------------------
230 Send an error response back to the client.
231-----------------------------------------------------------------------------*/
232 ResponseStatus(abyssSessionP, (uint16_t) status);
233 ResponseError2(abyssSessionP, explanation);
234}
235
236
237
238static void
239traceChunkRead(TSession * const abyssSessionP) {
240
241 fprintf(stderrstderr, "XML-RPC handler got a chunk of %u bytes\n",
242 (unsigned int)SessionReadDataAvail(abyssSessionP));
243}
244
245
246
247static void
248refillBufferFromConnection(xmlrpc_env * const envP,
249 TSession * const abyssSessionP,
250 const char * const trace) {
251/*----------------------------------------------------------------------------
252 Get the next chunk of data from the connection into the buffer.
253-----------------------------------------------------------------------------*/
254 bool succeeded;
255
256 succeeded = SessionRefillBuffer(abyssSessionP);
257
258 if (!succeeded)
259 xmlrpc_env_set_fault_formatted(
260 envP, XMLRPC_TIMEOUT_ERROR(-505), "Timed out waiting for "
261 "client to send its POST data");
262 else {
263 if (trace)
264 traceChunkRead(abyssSessionP);
265 }
266}
267
268
269
270static void
271getBody(xmlrpc_env * const envP,
272 TSession * const abyssSessionP,
273 size_t const contentSize,
274 const char * const trace,
275 xmlrpc_mem_block ** const bodyP) {
276/*----------------------------------------------------------------------------
277 Get the entire body, which is of size 'contentSize' bytes, from the
278 Abyss session and return it as the new memblock *bodyP.
279
280 The first chunk of the body may already be in Abyss's buffer. We
281 retrieve that before reading more.
282-----------------------------------------------------------------------------*/
283 xmlrpc_mem_block * body;
284
285 if (trace)
286 fprintf(stderrstderr, "XML-RPC handler processing body. "
287 "Content Size = %u bytes\n", (unsigned)contentSize);
288
289 body = xmlrpc_mem_block_new(envP, 0);
290 if (!envP->fault_occurred) {
291 size_t bytesRead;
292 const char * chunkPtr;
293 size_t chunkLen;
294
295 bytesRead = 0;
296
297 while (!envP->fault_occurred && bytesRead < contentSize) {
298 SessionGetReadData(abyssSessionP, contentSize - bytesRead,
299 &chunkPtr, &chunkLen);
300 bytesRead += chunkLen;
301
302 assert(bytesRead <= contentSize)((bytesRead <= contentSize) ? (void) (0) : __assert_fail (
"bytesRead <= contentSize", "../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c"
, 302, __PRETTY_FUNCTION__))
;
303
304 XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen)xmlrpc_mem_block_append(envP, body, chunkPtr, sizeof(char) * (
chunkLen))
;
305 if (bytesRead < contentSize)
306 refillBufferFromConnection(envP, abyssSessionP, trace);
307 }
308 if (envP->fault_occurred)
309 xmlrpc_mem_block_free(body);
310 }
311 *bodyP = body;
312}
313
314
315
316static void
317storeCookies(TSession * const httpRequestP,
318 const char ** const errorP) {
319/*----------------------------------------------------------------------------
320 Get the cookie settings from the HTTP headers and remember them for
321 use in responses.
322-----------------------------------------------------------------------------*/
323 const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
324 if (cookie) {
325 /*
326 Setting the value in an environment variable doesn't make
327 any sense. So for now, cookie code is disabled.
328 -Bryan 04.10.03.
329
330 setenv("HTTP_COOKIE", cookie, 1);
331 */
332 }
333 /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */
334
335 *errorP = NULL((void*)0);
336}
337
338
339
340
341static void
342processContentLength(TSession * const httpRequestP,
343 size_t * const inputLenP,
344 bool * const missingP,
345 const char ** const errorP) {
346/*----------------------------------------------------------------------------
347 Make sure the content length is present and non-zero. This is
348 technically required by XML-RPC, but we only enforce it because we
349 don't want to figure out how to safely handle HTTP < 1.1 requests
350 without it.
351-----------------------------------------------------------------------------*/
352 const char * const content_length =
353 RequestHeaderValue(httpRequestP, "content-length");
354
355 if (content_length == NULL((void*)0)) {
356 *missingP = TRUE1;
357 *errorP = NULL((void*)0);
358 } else {
359 *missingP = FALSE0;
360 *inputLenP = 0; /* quiet compiler warning */
361 if (content_length[0] == '\0')
362 xmlrpc_asprintf(errorP, "The value in your content-length "
363 "HTTP header value is a null string");
364 else {
365 unsigned long contentLengthValue;
366 char * tail;
367
368 contentLengthValue = strtoul(content_length, &tail, 10);
369
370 if (*tail != '\0')
371 xmlrpc_asprintf(errorP, "There's non-numeric crap in "
372 "the value of your content-length "
373 "HTTP header: '%s'", tail);
374 else if (contentLengthValue < 1)
375 xmlrpc_asprintf(errorP, "According to your content-length "
376 "HTTP header, your request is empty (zero "
377 "length)");
378 else if ((unsigned long)(size_t)contentLengthValue
379 != contentLengthValue)
380 xmlrpc_asprintf(errorP, "According to your content-length "
381 "HTTP header, your request is too big to "
382 "process; we can't even do arithmetic on its "
383 "size: %s bytes", content_length);
384 else {
385 *errorP = NULL((void*)0);
386 *inputLenP = (size_t)contentLengthValue;
387 }
388 }
389 }
390}
391
392
393
394static void
395traceHandlerCalled(TSession * const abyssSessionP) {
396
397 const char * methodDesc;
398 const TRequestInfo * requestInfoP;
399
400 fprintf(stderrstderr, "xmlrpc_server_abyss URI path handler called.\n");
401
402 SessionGetRequestInfo(abyssSessionP, &requestInfoP);
403
404 fprintf(stderrstderr, "URI = '%s'\n", requestInfoP->uri);
405
406 switch (requestInfoP->method) {
407 case m_unknown: methodDesc = "unknown"; break;
408 case m_get: methodDesc = "get"; break;
409 case m_put: methodDesc = "put"; break;
410 case m_head: methodDesc = "head"; break;
411 case m_post: methodDesc = "post"; break;
412 case m_delete: methodDesc = "delete"; break;
413 case m_trace: methodDesc = "trace"; break;
414 case m_options: methodDesc = "m_options"; break;
415 default: methodDesc = "?";
416 }
417 fprintf(stderrstderr, "HTTP method = '%s'\n", methodDesc);
418
419 if (requestInfoP->query)
420 fprintf(stderrstderr, "query (component of URL)='%s'\n",
421 requestInfoP->query);
422 else
423 fprintf(stderrstderr, "URL has no query component\n");
424}
425
426
427
428static void
429processCall(TSession * const abyssSessionP,
430 size_t const contentSize,
431 xmlrpc_call_processor xmlProcessor,
432 void * const xmlProcessorArg,
433 bool const wantChunk,
434 ResponseAccessCtl const accessControl,
435 const char * const trace) {
436/*----------------------------------------------------------------------------
437 Handle an RPC request. This is an HTTP request that has the proper form
438 to be an XML-RPC call.
439
440 The text of the call is available through the Abyss session
441 'abyssSessionP'.
442
443 Its content length is 'contentSize' bytes.
444-----------------------------------------------------------------------------*/
445 xmlrpc_env env;
446
447 if (trace)
448 fprintf(stderrstderr,
449 "xmlrpc_server_abyss URI path handler processing RPC.\n");
450
451 xmlrpc_env_init(&env);
452
453 if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1)))
454 xmlrpc_env_set_fault_formatted(
455 &env, XMLRPC_LIMIT_EXCEEDED_ERROR(-509),
456 "XML-RPC request too large (%u bytes)", (unsigned)contentSize);
457 else {
458 xmlrpc_mem_block * body = NULL((void*)0);
459 /* Read XML data off the wire. */
460 getBody(&env, abyssSessionP, contentSize, trace, &body);
461 if (!env.fault_occurred) {
462 xmlrpc_mem_block * output;
463
464 /* Process the RPC. */
465 xmlProcessor(
466 &env, xmlProcessorArg,
467 XMLRPC_MEMBLOCK_CONTENTS(char, body)((char*) xmlrpc_mem_block_contents(body)),
468 XMLRPC_MEMBLOCK_SIZE(char, body)(xmlrpc_mem_block_size(body) / sizeof(char)),
469 abyssSessionP,
470 &output);
471 if (!env.fault_occurred) {
472 /* Send out the result. */
473 sendResponse(&env, abyssSessionP,
474 XMLRPC_MEMBLOCK_CONTENTS(char, output)((char*) xmlrpc_mem_block_contents(output)),
475 XMLRPC_MEMBLOCK_SIZE(char, output)(xmlrpc_mem_block_size(output) / sizeof(char)),
476 wantChunk, accessControl);
477
478 XMLRPC_MEMBLOCK_FREE(char, output)xmlrpc_mem_block_free(output);
479 }
480 XMLRPC_MEMBLOCK_FREE(char, body)xmlrpc_mem_block_free(body);
481 }
482 }
483 if (env.fault_occurred) {
484 uint16_t httpResponseStatus;
485 if (env.fault_code == XMLRPC_TIMEOUT_ERROR(-505))
486 httpResponseStatus = 408; /* Request Timeout */
487 else
488 httpResponseStatus = 500; /* Internal Server Error */
489
490 sendError(abyssSessionP, httpResponseStatus, env.fault_string);
491 }
492
493 xmlrpc_env_clean(&env);
494}
495
496
497
498static void
499processXmlrpcCall(xmlrpc_env * const envP,
500 void * const arg,
501 const char * const callXml,
502 size_t const callXmlLen,
503 TSession * const abyssSessionP,
504 xmlrpc_mem_block ** const responseXmlPP) {
505
506 xmlrpc_registry * const registryP = arg;
507
508 xmlrpc_registry_process_call2(envP, registryP,
509 callXml, callXmlLen, abyssSessionP,
510 responseXmlPP);
511
512}
513
514
515
516static const char * trace_abyss;
517
518
519struct uriHandlerXmlrpc {
520/*----------------------------------------------------------------------------
521 This is the part of an Abyss HTTP request handler (aka URI handler)
522 that is specific to the Xmlrpc-c handler.
523-----------------------------------------------------------------------------*/
524 xmlrpc_registry * registryP;
525 const char * uriPath; /* malloc'ed */
526 bool chunkResponse;
527 /* The handler should chunk its response whenever possible */
528 xmlrpc_call_processor * xmlProcessor;
529 void * xmlProcessorArg;
530 ResponseAccessCtl accessControl;
531};
532
533
534
535static void
536termAccessControl(ResponseAccessCtl * const accessCtlP) {
537
538 xmlrpc_strfreenull(accessCtlP->allowOrigin);
539}
540
541
542
543static void
544termUriHandler(void * const arg) {
545
546 struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = arg;
547
548 xmlrpc_strfree(uriHandlerXmlrpcP->uriPath);
549 termAccessControl(&uriHandlerXmlrpcP->accessControl);
550 free(uriHandlerXmlrpcP);
551}
552
553
554
555static void
556handleXmlRpcCallReq(TSession * const abyssSessionP,
557 const TRequestInfo * const requestInfoP ATTR_UNUSED__attribute__((__unused__)),
558 xmlrpc_call_processor xmlProcessor,
559 void * const xmlProcessorArg,
560 bool const wantChunk,
561 ResponseAccessCtl const accessControl) {
562/*----------------------------------------------------------------------------
563 Handle the HTTP request described by *requestInfoP, which arrived over
564 Abyss HTTP session *abyssSessionP, which is an XML-RPC call
565 (i.e. a POST request to /RPC2 or whatever other URI our server is
566 supposed to handle).
567
568 Handle it by feeding the XML which is its content to 'xmlProcessor'
569 along with argument 'xmlProcessorArg'.
570-----------------------------------------------------------------------------*/
571 /* We used to reject the call if content-type was not present and
572 text/xml, on some security theory (a firewall may block text/xml with
573 the intent of blocking XML-RPC. Now, we believe that is silly, and we
574 have seen an incorrectly implemented client that says text/plain.
575 */
576 const char * error;
577
578 assert(requestInfoP->method == m_post)((requestInfoP->method == m_post) ? (void) (0) : __assert_fail
("requestInfoP->method == m_post", "../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c"
, 578, __PRETTY_FUNCTION__))
;
579
580 storeCookies(abyssSessionP, &error);
581 if (error) {
582 sendError(abyssSessionP, 400, error);
583 xmlrpc_strfree(error);
584 } else {
585 const char * error;
586 bool missing;
587 size_t contentSize;
588
589 processContentLength(abyssSessionP,
590 &contentSize, &missing, &error);
591 if (error) {
592 sendError(abyssSessionP, 400, error);
593 xmlrpc_strfree(error);
594 } else {
595 if (missing)
596 sendError(abyssSessionP, 411, "You must send a "
597 "content-length HTTP header in an "
598 "XML-RPC call.");
599 else
600 processCall(abyssSessionP, contentSize,
601 xmlProcessor, xmlProcessorArg,
602 wantChunk, accessControl,
603 trace_abyss);
604 }
605 }
606}
607
608
609
610static void
611handleXmlRpcOptionsReq(TSession * const abyssSessionP,
612 ResponseAccessCtl const accessControl) {
613
614 ResponseAddField(abyssSessionP, "Allow", "POST");
615
616 ResponseAccessControl(abyssSessionP, accessControl);
617 ResponseContentLength(abyssSessionP, 0);
618 ResponseStatus(abyssSessionP, 200);
619 if (ResponseWriteStart(abyssSessionP))
620 ResponseWriteEnd(abyssSessionP);
621}
622
623
624
625static void
626handleIfXmlrpcReq(void * const handlerArg,
627 TSession * const abyssSessionP,
628 abyss_bool * const handledP) {
629/*----------------------------------------------------------------------------
630 Our job is to look at this HTTP request that the Abyss server is
631 trying to process and see if we can handle it. If it's an XML-RPC
632 call for this XML-RPC server, we handle it. If it's not, we refuse
633 it and Abyss can try some other handler.
634
635 Our return code is TRUE to mean we handled it; FALSE to mean we didn't.
636
637 Note that failing the request counts as handling it, and not handling
638 it does not mean we failed it.
639
640 This is an Abyss HTTP Request handler -- type handleReqFn3.
641-----------------------------------------------------------------------------*/
642 struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = handlerArg;
643
644 const TRequestInfo * requestInfoP;
645
646 if (trace_abyss)
647 traceHandlerCalled(abyssSessionP);
648
649 SessionGetRequestInfo(abyssSessionP, &requestInfoP);
650
651 /* Note that requestInfoP->uri is not the whole URI. It is just
652 the "file name" part of it.
653 */
654 if (!xmlrpc_streq(requestInfoP->uri, uriHandlerXmlrpcP->uriPath))
655 /* It's not for the path (e.g. "/RPC2") that we're supposed to
656 handle.
657 */
658 *handledP = FALSE0;
659 else {
660 *handledP = TRUE1;
661
662 switch (requestInfoP->method) {
663 case m_post:
664 handleXmlRpcCallReq(abyssSessionP, requestInfoP,
665 uriHandlerXmlrpcP->xmlProcessor,
666 uriHandlerXmlrpcP->xmlProcessorArg,
667 uriHandlerXmlrpcP->chunkResponse,
668 uriHandlerXmlrpcP->accessControl);
669 break;
670 case m_options:
671 handleXmlRpcOptionsReq(abyssSessionP,
672 uriHandlerXmlrpcP->accessControl);
673 break;
674 default:
675 sendError(abyssSessionP, 405,
676 "POST is the only HTTP method this server understands");
677 /* 405 = Method Not Allowed */
678 }
679 }
680 if (trace_abyss)
681 fprintf(stderrstderr, "xmlrpc_server_abyss URI path handler returning.\n");
682}
683
684
685/* This doesn't include what the user's method function requires */
686#define HANDLE_XMLRPC_REQ_STACK1024 1024
687
688
689
690/*=========================================================================
691** xmlrpc_server_abyss_default_handler
692**=========================================================================
693** This handler returns a 404 Not Found for all requests. See the header
694** for more documentation.
695*/
696
697static xmlrpc_bool
698xmlrpc_server_abyss_default_handler(TSession * const sessionP) {
699
700 const TRequestInfo * requestInfoP;
701
702 const char * explanation;
703
704 if (trace_abyss)
705 fprintf(stderrstderr, "xmlrpc_server_abyss default handler called.\n");
706
707 SessionGetRequestInfo(sessionP, &requestInfoP);
708
709 xmlrpc_asprintf(
710 &explanation,
711 "This XML-RPC For C/C++ Abyss XML-RPC server "
712 "responds to only one URI path. "
713 "I don't know what URI path that is, "
714 "but it's not the one you requested: '%s'. (Typically, it's "
715 "'/RPC2')", requestInfoP->uri);
716
717 sendError(sessionP, 404, explanation);
718
719 xmlrpc_strfree(explanation);
720
721 return TRUE1;
722}
723
724
725
726static void
727setHandler(xmlrpc_env * const envP,
728 TServer * const srvP,
729 struct uriHandlerXmlrpc * const uriHandlerXmlrpcP,
730 size_t const xmlProcessorMaxStackSize) {
731
732 abyss_bool success;
733
734 trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
735
736 {
737 size_t const stackSize =
738 HANDLE_XMLRPC_REQ_STACK1024 + xmlProcessorMaxStackSize;
739 struct ServerReqHandler3 const handlerDesc = {
740 /* .term = */ &termUriHandler,
741 /* .handleReq = */ &handleIfXmlrpcReq,
742 /* .userdata = */ uriHandlerXmlrpcP,
743 /* .handleReqStackSize = */ stackSize
744 };
745 ServerAddHandler3(srvP, &handlerDesc, &success);
746 }
747 if (!success)
748 xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request "
749 "handler. ServerAddHandler3() failed.");
750
751 if (envP->fault_occurred){
752 free((void *)uriHandlerXmlrpcP->uriPath);
753 free(uriHandlerXmlrpcP);
754 }
755}
756
757
758
759static void
760interpretHttpAccessControl(
761 const xmlrpc_server_abyss_handler_parms * const parmsP,
762 unsigned int const parmSize,
763 ResponseAccessCtl * const accessCtlP) {
764
765 if (parmSize >= XMLRPC_AHPSIZE(allow_origin)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->allow_origin) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->allow_origin))
&& parmsP->allow_origin)
766 accessCtlP->allowOrigin = xmlrpc_strdupsol(parmsP->allow_origin);
767 else
768 accessCtlP->allowOrigin = NULL((void*)0);
769
770 if (parmSize >= XMLRPC_AHPSIZE(access_ctl_expires)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->access_ctl_expires) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->access_ctl_expires))
771 && parmsP->access_ctl_expires) {
772 accessCtlP->expires = true;
773
774 if (parmSize >= XMLRPC_AHPSIZE(access_ctl_max_age)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->access_ctl_max_age) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->access_ctl_max_age))
)
775 accessCtlP->maxAge = parmsP->access_ctl_max_age;
776 else
777 accessCtlP->maxAge = 0;
778 }
779}
780
781
782
783void
784xmlrpc_server_abyss_set_handler3(
785 xmlrpc_env * const envP,
786 TServer * const srvP,
787 const xmlrpc_server_abyss_handler_parms * const parmsP,
788 unsigned int const parmSize) {
789
790 struct uriHandlerXmlrpc * uriHandlerXmlrpcP;
791 size_t xmlProcessorMaxStackSize;
3
'xmlProcessorMaxStackSize' declared without an initial value
792
793 MALLOCVAR_NOFAIL(uriHandlerXmlrpcP)do {if ((uriHandlerXmlrpcP = malloc(sizeof(*uriHandlerXmlrpcP
))) == ((void*)0)) abort();} while(0)
;
794
795 if (!envP->fault_occurred) {
4
Taking true branch
796 if (parmSize >= XMLRPC_AHPSIZE(xml_processor)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->xml_processor) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->xml_processor))
)
5
Taking false branch
797 uriHandlerXmlrpcP->xmlProcessor = parmsP->xml_processor;
798 else
799 xmlrpc_faultf(envP, "Parameter too short to contain the required "
800 "'xml_processor' member");
801 }
802 if (!envP->fault_occurred) {
6
Taking true branch
803 if (parmSize >= XMLRPC_AHPSIZE(xml_processor_arg)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->xml_processor_arg) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->xml_processor_arg))
)
7
Taking false branch
804 uriHandlerXmlrpcP->xmlProcessorArg = parmsP->xml_processor_arg;
805 else
806 xmlrpc_faultf(envP, "Parameter too short to contain the required "
807 "'xml_processor_arg' member");
808 }
809 if (!envP->fault_occurred) {
8
Taking true branch
810 if (parmSize >= XMLRPC_AHPSIZE(xml_processor_max_stack)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->xml_processor_max_stack) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->xml_processor_max_stack))
)
9
Taking false branch
811 xmlProcessorMaxStackSize = parmsP->xml_processor_max_stack;
812 else
813 xmlrpc_faultf(envP, "Parameter too short to contain the required "
814 "'xml_processor_max_stack' member");
815 }
816 if (!envP->fault_occurred) {
10
Taking true branch
817 if (parmSize >= XMLRPC_AHPSIZE(uri_path)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->uri_path) + sizeof(((xmlrpc_server_abyss_handler_parms *
)0)->uri_path))
&& parmsP->uri_path)
818 uriHandlerXmlrpcP->uriPath = xmlrpc_strdupsol(parmsP->uri_path);
819 else
820 uriHandlerXmlrpcP->uriPath = xmlrpc_strdupsol("/RPC2");
821
822 if (parmSize >= XMLRPC_AHPSIZE(chunk_response)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->chunk_response) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->chunk_response))
&&
11
Taking false branch
823 parmsP->chunk_response)
824 uriHandlerXmlrpcP->chunkResponse = parmsP->chunk_response;
825 else
826 uriHandlerXmlrpcP->chunkResponse = false;
827
828 interpretHttpAccessControl(parmsP, parmSize,
829 &uriHandlerXmlrpcP->accessControl);
830
831 if (envP->fault_occurred)
12
Taking false branch
832 termAccessControl(&uriHandlerXmlrpcP->accessControl);
833 }
834 if (!envP->fault_occurred)
13
Taking true branch
835 setHandler(envP, srvP, uriHandlerXmlrpcP, xmlProcessorMaxStackSize);
14
Function call argument is an uninitialized value
836
837 if (envP->fault_occurred)
838 free(uriHandlerXmlrpcP);
839}
840
841
842
843void
844xmlrpc_server_abyss_set_handler2(
845 TServer * const srvP,
846 const char * const uriPath,
847 xmlrpc_call_processor xmlProcessor,
848 void * const xmlProcessorArg,
849 size_t const xmlProcessorMaxStackSize,
850 xmlrpc_bool const chunkResponse) {
851
852 xmlrpc_env env;
853 xmlrpc_server_abyss_handler_parms parms;
854
855 xmlrpc_env_init(&env);
856
857 parms.xml_processor = xmlProcessor;
858 parms.xml_processor_arg = xmlProcessorArg;
859 parms.xml_processor_max_stack = xmlProcessorMaxStackSize;
860 parms.uri_path = uriPath;
861 parms.chunk_response = chunkResponse;
862
863 xmlrpc_server_abyss_set_handler3(&env, srvP,
864 &parms, XMLRPC_AHPSIZE(chunk_response)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->chunk_response) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->chunk_response))
);
865
866 if (env.fault_occurred)
867 abort();
868
869 xmlrpc_env_clean(&env);
870}
871
872
873
874void
875xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP,
876 TServer * const srvP,
877 const char * const uriPath,
878 xmlrpc_registry * const registryP) {
879
880 xmlrpc_server_abyss_handler_parms parms;
881
882 parms.xml_processor = &processXmlrpcCall;
883 parms.xml_processor_arg = registryP;
884 parms.xml_processor_max_stack = xmlrpc_registry_max_stackSize(registryP);
885 parms.uri_path = uriPath;
886
887 xmlrpc_server_abyss_set_handler3(envP, srvP,
888 &parms, XMLRPC_AHPSIZE(uri_path)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->uri_path) + sizeof(((xmlrpc_server_abyss_handler_parms *
)0)->uri_path))
);
889}
890
891
892
893void
894xmlrpc_server_abyss_set_default_handler(TServer * const srvP) {
895
896 ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler);
897}
898
899
900
901static void
902setHandlersRegistry(TServer * const srvP,
903 const char * const uriPath,
904 xmlrpc_registry * const registryP,
905 bool const chunkResponse,
906 const char * const allowOrigin,
907 bool const expires,
908 unsigned int const maxAge) {
909
910 xmlrpc_env env;
911 xmlrpc_server_abyss_handler_parms parms;
912
913 xmlrpc_env_init(&env);
914
915 parms.xml_processor = &processXmlrpcCall;
916 parms.xml_processor_arg = registryP;
917 parms.xml_processor_max_stack = xmlrpc_registry_max_stackSize(registryP),
918 parms.uri_path = uriPath;
919 parms.chunk_response = chunkResponse;
920 parms.allow_origin = allowOrigin;
921 parms.access_ctl_expires = expires;
922 parms.access_ctl_max_age = maxAge;
923
924 xmlrpc_server_abyss_set_handler3(
2
Calling 'xmlrpc_server_abyss_set_handler3'
925 &env, srvP, &parms, XMLRPC_AHPSIZE(access_ctl_max_age)(((size_t)(char*)&((xmlrpc_server_abyss_handler_parms *)0
)->access_ctl_max_age) + sizeof(((xmlrpc_server_abyss_handler_parms
*)0)->access_ctl_max_age))
)
;
926
927 if (env.fault_occurred)
928 abort();
929
930 xmlrpc_env_clean(&env);
931
932 xmlrpc_server_abyss_set_default_handler(srvP);
933}
934
935
936
937void
938xmlrpc_server_abyss_set_handlers2(TServer * const srvP,
939 const char * const uriPath,
940 xmlrpc_registry * const registryP) {
941
942 setHandlersRegistry(srvP, uriPath, registryP, false, NULL((void*)0), false, 0);
943}
944
945
946
947void
948xmlrpc_server_abyss_set_handlers(TServer * const srvP,
949 xmlrpc_registry * const registryP) {
950
951 setHandlersRegistry(srvP, "/RPC2", registryP, false, NULL((void*)0), false, 0);
1
Calling 'setHandlersRegistry'
952}
953
954
955
956/*============================================================================
957 createServer()
958============================================================================*/
959
960static void
961setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP,
962 unsigned int const parmSize,
963 TServer * const serverP) {
964
965 if (parmSize >= XMLRPC_APSIZE(keepalive_timeout)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->keepalive_timeout
) + sizeof(((xmlrpc_server_abyss_parms *)0)->keepalive_timeout
))
&&
966 parmsP->keepalive_timeout > 0)
967 ServerSetKeepaliveTimeout(serverP, parmsP->keepalive_timeout);
968 if (parmSize >= XMLRPC_APSIZE(keepalive_max_conn)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->keepalive_max_conn
) + sizeof(((xmlrpc_server_abyss_parms *)0)->keepalive_max_conn
))
&&
969 parmsP->keepalive_max_conn > 0)
970 ServerSetKeepaliveMaxConn(serverP, parmsP->keepalive_max_conn);
971 if (parmSize >= XMLRPC_APSIZE(timeout)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->timeout
) + sizeof(((xmlrpc_server_abyss_parms *)0)->timeout))
&&
972 parmsP->timeout > 0)
973 ServerSetTimeout(serverP, parmsP->timeout);
974 if (parmSize >= XMLRPC_APSIZE(dont_advertise)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->dont_advertise
) + sizeof(((xmlrpc_server_abyss_parms *)0)->dont_advertise
))
)
975 ServerSetAdvertise(serverP, !parmsP->dont_advertise);
976}
977
978
979
980static void
981extractServerCreateParms(
982 xmlrpc_env * const envP,
983 const xmlrpc_server_abyss_parms * const parmsP,
984 unsigned int const parmSize,
985 bool * const socketBoundP,
986 unsigned int * const portNumberP,
987 TOsSocket * const socketFdP,
988 const char ** const logFileNameP) {
989
990
991 if (parmSize >= XMLRPC_APSIZE(socket_bound)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->socket_bound
) + sizeof(((xmlrpc_server_abyss_parms *)0)->socket_bound)
)
)
992 *socketBoundP = parmsP->socket_bound;
993 else
994 *socketBoundP = FALSE0;
995
996 if (*socketBoundP) {
997 if (parmSize < XMLRPC_APSIZE(socket_handle)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->socket_handle
) + sizeof(((xmlrpc_server_abyss_parms *)0)->socket_handle
))
)
998 xmlrpc_faultf(envP, "socket_bound is true, but server parameter "
999 "structure does not contain socket_handle (it's too "
1000 "short)");
1001 else
1002 *socketFdP = parmsP->socket_handle;
1003 } else {
1004 if (parmSize >= XMLRPC_APSIZE(port_number)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->port_number
) + sizeof(((xmlrpc_server_abyss_parms *)0)->port_number))
)
1005 *portNumberP = parmsP->port_number;
1006 else
1007 *portNumberP = 8080;
1008
1009 if (*portNumberP > 0xffff)
1010 xmlrpc_faultf(envP,
1011 "TCP port number %u exceeds the maximum possible "
1012 "TCP port number (65535)",
1013 *portNumberP);
1014 }
1015 if (!envP->fault_occurred) {
1016 if (parmSize >= XMLRPC_APSIZE(log_file_name)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->log_file_name
) + sizeof(((xmlrpc_server_abyss_parms *)0)->log_file_name
))
&&
1017 parmsP->log_file_name)
1018 *logFileNameP = strdup(parmsP->log_file_name)(__extension__ (__builtin_constant_p (parmsP->log_file_name
) && ((size_t)(const void *)((parmsP->log_file_name
) + 1) - (size_t)(const void *)(parmsP->log_file_name) == 1
) ? (((const char *) (parmsP->log_file_name))[0] == '\0' ?
(char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len =
strlen (parmsP->log_file_name) + 1; char *__retval = (char
*) malloc (__len); if (__retval != ((void*)0)) __retval = (char
*) memcpy (__retval, parmsP->log_file_name, __len); __retval
; })) : __strdup (parmsP->log_file_name)))
;
1019 else
1020 *logFileNameP = NULL((void*)0);
1021 }
1022}
1023
1024
1025
1026static void
1027chanSwitchCreateOsSocket(TOsSocket const socketFd,
1028 TChanSwitch ** const chanSwitchPP,
1029 const char ** const errorP) {
1030
1031#ifdef WIN32
1032 ChanSwitchWinCreateWinsock(socketFd, chanSwitchPP, errorP);
1033#else
1034 ChanSwitchUnixCreateFd(socketFd, chanSwitchPP, errorP);
1035#endif
1036
1037}
1038
1039
1040
1041static void
1042createServerBoundSocket(xmlrpc_env * const envP,
1043 TOsSocket const socketFd,
1044 const char * const logFileName,
1045 TServer * const serverP,
1046 TChanSwitch ** const chanSwitchPP) {
1047
1048 TChanSwitch * chanSwitchP;
1049 const char * error;
1050
1051 chanSwitchCreateOsSocket(socketFd, &chanSwitchP, &error);
1052 if (error) {
1053 xmlrpc_faultf(envP, "Unable to create Abyss socket out of "
1054 "file descriptor %d. %s", socketFd, error);
1055 xmlrpc_strfree(error);
1056 } else {
1057 ServerCreateSwitch(serverP, chanSwitchP, &error);
1058 if (error) {
1059 xmlrpc_faultf(envP, "Abyss failed to create server. %s", error);
1060 xmlrpc_strfree(error);
1061 } else {
1062 *chanSwitchPP = chanSwitchP;
1063
1064 ServerSetName(serverP, "XmlRpcServer");
1065
1066 if (logFileName)
1067 ServerSetLogFileName(serverP, logFileName);
1068 }
1069 if (envP->fault_occurred)
1070 ChanSwitchDestroy(chanSwitchP);
1071 }
1072}
1073
1074
1075
1076static void
1077createServerBare(xmlrpc_env * const envP,
1078 const xmlrpc_server_abyss_parms * const parmsP,
1079 unsigned int const parmSize,
1080 TServer * const serverP,
1081 TChanSwitch ** const chanSwitchPP) {
1082/*----------------------------------------------------------------------------
1083 Create a bare server. It will need further setup before it is ready
1084 to use.
1085-----------------------------------------------------------------------------*/
1086 bool socketBound;
1087 unsigned int portNumber = 0;
1088 TOsSocket socketFd = 0;
1089 const char * logFileName;
1090
1091 extractServerCreateParms(envP, parmsP, parmSize,
1092 &socketBound, &portNumber, &socketFd,
1093 &logFileName);
1094
1095 if (!envP->fault_occurred) {
1096 if (socketBound)
1097 createServerBoundSocket(envP, socketFd, logFileName,
1098 serverP, chanSwitchPP);
1099 else {
1100 abyss_bool success;
1101
1102 success = ServerCreate(serverP, "XmlRpcServer", portNumber,
1103 DEFAULT_DOCS"/usr/local/abyss""/htdocs", logFileName);
1104
1105 if (!success)
1106 xmlrpc_faultf(envP, "Failed to create an Abyss server object");
1107
1108 *chanSwitchPP = NULL((void*)0);
1109 }
1110 if (logFileName)
1111 xmlrpc_strfree(logFileName);
1112 }
1113}
1114
1115
1116
1117static const char *
1118uriPathParm(const xmlrpc_server_abyss_parms * const parmsP,
1119 unsigned int const parmSize) {
1120
1121 const char * uriPath;
1122
1123 if (parmSize >= XMLRPC_APSIZE(uri_path)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->uri_path
) + sizeof(((xmlrpc_server_abyss_parms *)0)->uri_path))
&& parmsP->uri_path)
1124 uriPath = parmsP->uri_path;
1125 else
1126 uriPath = "/RPC2";
1127
1128 return uriPath;
1129}
1130
1131
1132
1133static bool
1134chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP,
1135 unsigned int const parmSize) {
1136
1137 return
1138 parmSize >= XMLRPC_APSIZE(chunk_response)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->chunk_response
) + sizeof(((xmlrpc_server_abyss_parms *)0)->chunk_response
))
&&
1139 parmsP->chunk_response;
1140}
1141
1142
1143
1144static const char *
1145allowOriginParm(const xmlrpc_server_abyss_parms * const parmsP,
1146 unsigned int const parmSize) {
1147
1148 return
1149 parmSize >= XMLRPC_APSIZE(allow_origin)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->allow_origin
) + sizeof(((xmlrpc_server_abyss_parms *)0)->allow_origin)
)
?
1150 parmsP->allow_origin : NULL((void*)0);
1151}
1152
1153
1154
1155static bool
1156expiresParm(const xmlrpc_server_abyss_parms * const parmsP,
1157 unsigned int const parmSize) {
1158
1159 return
1160 parmSize >= XMLRPC_APSIZE(access_ctl_expires)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->access_ctl_expires
) + sizeof(((xmlrpc_server_abyss_parms *)0)->access_ctl_expires
))
?
1161 parmsP->access_ctl_expires : false;
1162}
1163
1164
1165
1166static unsigned int
1167maxAgeParm(const xmlrpc_server_abyss_parms * const parmsP,
1168 unsigned int const parmSize) {
1169
1170 return
1171 parmSize >= XMLRPC_APSIZE(access_ctl_max_age)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->access_ctl_max_age
) + sizeof(((xmlrpc_server_abyss_parms *)0)->access_ctl_max_age
))
?
1172 parmsP->access_ctl_max_age : 0;
1173}
1174
1175
1176
1177static void
1178createServer(xmlrpc_env * const envP,
1179 const xmlrpc_server_abyss_parms * const parmsP,
1180 unsigned int const parmSize,
1181 TServer * const abyssServerP,
1182 TChanSwitch ** const chanSwitchPP) {
1183
1184 createServerBare(envP, parmsP, parmSize, abyssServerP, chanSwitchPP);
1185
1186 if (!envP->fault_occurred) {
1187 setAdditionalServerParms(parmsP, parmSize, abyssServerP);
1188
1189 setHandlersRegistry(abyssServerP, uriPathParm(parmsP, parmSize),
1190 parmsP->registryP,
1191 chunkResponseParm(parmsP, parmSize),
1192 allowOriginParm(parmsP, parmSize),
1193 expiresParm(parmsP, parmSize),
1194 maxAgeParm(parmsP, parmSize));
1195
1196 ServerInit(abyssServerP);
1197 }
1198}
1199
1200
1201
1202static bool
1203enableShutdownParm(const xmlrpc_server_abyss_parms * const parmsP,
1204 unsigned int const parmSize) {
1205
1206 return
1207 parmSize >= XMLRPC_APSIZE(enable_shutdown)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->enable_shutdown
) + sizeof(((xmlrpc_server_abyss_parms *)0)->enable_shutdown
))
&&
1208 parmsP->enable_shutdown;
1209}
1210
1211
1212
1213static xmlrpc_server_shutdown_fn shutdownAbyss;
1214
1215static void
1216shutdownAbyss(xmlrpc_env * const faultP,
1217 void * const context,
1218 const char * const comment ATTR_UNUSED__attribute__((__unused__)),
1219 void * const callInfo ATTR_UNUSED__attribute__((__unused__))) {
1220/*----------------------------------------------------------------------------
1221 Tell Abyss to wrap up whatever it's doing and shut down.
1222
1223 This is a server shutdown function to be registered in the method
1224 registry, for use by the 'system.shutdown' system method.
1225
1226 After we return, Abyss will finish up the system.shutdown and any
1227 other connections that are in progress, then the call to
1228 ServerRun() etc. will return.
1229
1230 *faultP is the result of the shutdown request, not whether we
1231 succeeded or failed. We are not allowed to fail.
1232-----------------------------------------------------------------------------*/
1233 xmlrpc_server_abyss_t * const serverP = context;
1234
1235 xmlrpc_env_init(faultP);
1236
1237 if (!serverP->shutdownEnabled)
1238 xmlrpc_env_set_fault_formatted(
1239 faultP, XMLRPC_REQUEST_REFUSED_ERROR(-507),
1240 "Shutdown by client is disabled on this server.");
1241 else
1242 ServerTerminate(&serverP->abyssServer);
1243}
1244
1245
1246
1247/*=============================================================================
1248 xmlrpc_server_abyss object methods
1249=============================================================================*/
1250
1251void
1252xmlrpc_server_abyss_create(xmlrpc_env * const envP,
1253 const xmlrpc_server_abyss_parms * const parmsP,
1254 unsigned int const parmSize,
1255 xmlrpc_server_abyss_t ** const serverPP) {
1256
1257 xmlrpc_server_abyss_t * serverP;
1258
1259 XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string
== ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1259)
; while (0)
;
1260
1261 validateGlobalInit(envP);
1262
1263 if (!envP->fault_occurred) {
1264 if (parmSize < XMLRPC_APSIZE(registryP)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->registryP
) + sizeof(((xmlrpc_server_abyss_parms *)0)->registryP))
)
1265 xmlrpc_faultf(envP,
1266 "You must specify members at least up through "
1267 "'registryP' in the server parameters argument. "
1268 "That would mean the parameter size would be >= %u "
1269 "but you specified a size of %u",
1270 (unsigned)XMLRPC_APSIZE(registryP)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->registryP
) + sizeof(((xmlrpc_server_abyss_parms *)0)->registryP))
, parmSize);
1271 else {
1272 MALLOCVAR(serverP)serverP = malloc(sizeof(*serverP));
1273
1274 if (serverP == NULL((void*)0))
1275 xmlrpc_faultf(envP, "Unable to allocate memory for "
1276 "server descriptor.");
1277 else {
1278 createServer(envP, parmsP, parmSize,
1279 &serverP->abyssServer, &serverP->chanSwitchP);
1280
1281 if (!envP->fault_occurred) {
1282 serverP->shutdownEnabled =
1283 enableShutdownParm(parmsP, parmSize);
1284
1285 xmlrpc_registry_set_shutdown(
1286 parmsP->registryP, &shutdownAbyss, serverP);
1287
1288 if (envP->fault_occurred)
1289 free(serverP);
1290 else
1291 *serverPP = serverP;
1292 }
1293 }
1294 }
1295 }
1296}
1297
1298
1299
1300void
1301xmlrpc_server_abyss_destroy(xmlrpc_server_abyss_t * const serverP) {
1302
1303 XMLRPC_ASSERT(globallyInitialized)do if (!(globallyInitialized)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c"
, 1303); while (0)
;
1304
1305 ServerFree(&serverP->abyssServer);
1306
1307 if (serverP->chanSwitchP)
1308 ChanSwitchDestroy(serverP->chanSwitchP);
1309
1310 free(serverP);
1311}
1312
1313
1314
1315void
1316xmlrpc_server_abyss_use_sigchld(xmlrpc_server_abyss_t * const serverP) {
1317
1318 ServerUseSigchld(&serverP->abyssServer);
1319}
1320
1321
1322
1323void
1324xmlrpc_server_abyss_run_server(xmlrpc_env * const envP ATTR_UNUSED__attribute__((__unused__)),
1325 xmlrpc_server_abyss_t * const serverP) {
1326
1327 ServerRun(&serverP->abyssServer);
1328}
1329
1330
1331
1332void
1333xmlrpc_server_abyss_terminate(
1334 xmlrpc_env * const envP ATTR_UNUSED__attribute__((__unused__)),
1335 xmlrpc_server_abyss_t * const serverP) {
1336
1337 ServerTerminate(&serverP->abyssServer);
1338}
1339
1340
1341
1342void
1343xmlrpc_server_abyss_reset_terminate(
1344 xmlrpc_env * const envP ATTR_UNUSED__attribute__((__unused__)),
1345 xmlrpc_server_abyss_t * const serverP) {
1346
1347 ServerResetTerminate(&serverP->abyssServer);
1348}
1349
1350
1351
1352static void
1353sigchld(int const signalClass ATTR_UNUSED__attribute__((__unused__))) {
1354/*----------------------------------------------------------------------------
1355 This is a signal handler for a SIGCHLD signal (which informs us that
1356 one of our child processes has terminated).
1357
1358 The only child processes we have are those that belong to the Abyss
1359 server (and then only if the Abyss server was configured to use
1360 forking as a threading mechanism), so we respond by passing the
1361 signal on to the Abyss server. And reaping the dead child.
1362-----------------------------------------------------------------------------*/
1363#ifndef WIN32
1364 /* Reap zombie children / report to Abyss until there aren't any more. */
1365
1366 bool childrenLeft;
1367 bool error;
1368
1369 assert(signalClass == SIGCHLD)((signalClass == 17) ? (void) (0) : __assert_fail ("signalClass == 17"
, "../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1369
, __PRETTY_FUNCTION__))
;
1370
1371 error = false;
1372 childrenLeft = true; /* initial assumption */
1373
1374 /* Reap defunct children until there aren't any more. */
1375 while (childrenLeft && !error) {
1376 int status;
1377 pid_t pid;
1378
1379 pid = waitpid((pid_t) -1, &status, WNOHANG1);
1380
1381 if (pid == 0)
1382 childrenLeft = false;
1383 else if (pid < 0) {
1384 /* because of ptrace */
1385 if (errno(*__errno_location ()) != EINTR4)
1386 error = true;
1387 } else
1388 ServerHandleSigchld(pid);
1389 }
1390#endif /* WIN32 */
1391}
1392
1393
1394struct xmlrpc_server_abyss_sig {
1395
1396 /* A description of the state of the process' signal handlers before
1397 functions in this library messed with them; useful for restoring
1398 them later.
1399 */
1400#ifndef WIN32
1401 struct sigaction pipe;
1402 struct sigaction chld;
1403#else
1404 int dummy;
1405#endif
1406};
1407
1408
1409
1410static void
1411setupSignalHandlers(xmlrpc_server_abyss_sig * const oldHandlersP) {
1412#ifndef WIN32
1413 struct sigaction mysigaction;
1414
1415 sigemptyset(&mysigaction.sa_mask);
1416 mysigaction.sa_flags = 0;
1417
1418 /* This signal indicates connection closed in the middle */
1419 mysigaction.sa_handler__sigaction_handler.sa_handler = SIG_IGN((__sighandler_t) 1);
1420 sigaction(SIGPIPE13, &mysigaction, &oldHandlersP->pipe);
1421
1422 /* This signal indicates a child process (request handler) has died */
1423 mysigaction.sa_handler__sigaction_handler.sa_handler = sigchld;
1424 sigaction(SIGCHLD17, &mysigaction, &oldHandlersP->chld);
1425#endif
1426}
1427
1428
1429
1430static void
1431restoreSignalHandlers(const xmlrpc_server_abyss_sig * const oldHandlersP) {
1432#ifndef WIN32
1433
1434 sigaction(SIGPIPE13, &oldHandlersP->pipe, NULL((void*)0));
1435 sigaction(SIGCHLD17, &oldHandlersP->chld, NULL((void*)0));
1436
1437#endif
1438}
1439
1440
1441
1442void
1443xmlrpc_server_abyss_setup_sig(
1444 xmlrpc_env * const envP,
1445 xmlrpc_server_abyss_t * const serverP,
1446 xmlrpc_server_abyss_sig ** const oldHandlersPP) {
1447
1448 xmlrpc_server_abyss_sig * oldHandlersP;
1449
1450 XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string
== ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1450)
; while (0)
;
1451
1452 validateGlobalInit(envP);
1453
1454 if (!envP->fault_occurred) {
1455 MALLOCVAR(oldHandlersP)oldHandlersP = malloc(sizeof(*oldHandlersP));
1456
1457 if (oldHandlersP == NULL((void*)0))
1458 xmlrpc_faultf(envP, "Unable to allocate memory to save signal "
1459 "handling state.");
1460 else {
1461 setupSignalHandlers(oldHandlersP);
1462
1463 xmlrpc_server_abyss_use_sigchld(serverP);
1464 }
1465 if (oldHandlersPP)
1466 *oldHandlersPP = oldHandlersP;
1467 else
1468 free(oldHandlersP);
1469 }
1470}
1471
1472
1473
1474void
1475xmlrpc_server_abyss_restore_sig(
1476 const xmlrpc_server_abyss_sig * const oldHandlersP) {
1477
1478 restoreSignalHandlers(oldHandlersP);
1479}
1480
1481
1482
1483static void
1484runServerDaemon(TServer * const serverP,
1485 runfirstFn const runfirst,
1486 void * const runfirstArg) {
1487
1488 xmlrpc_server_abyss_sig oldHandlers;
1489
1490 setupSignalHandlers(&oldHandlers);
1491
1492 ServerUseSigchld(serverP);
1493
1494 ServerDaemonize(serverP);
1495
1496 /* We run the user supplied runfirst after forking, but before accepting
1497 connections (helpful when running with threads)
1498 */
1499 if (runfirst)
1500 runfirst(runfirstArg);
1501
1502 ServerRun(serverP);
1503
1504 restoreSignalHandlers(&oldHandlers);
1505}
1506
1507
1508
1509static void
1510oldHighLevelAbyssRun(xmlrpc_env * const envP,
1511 const xmlrpc_server_abyss_parms * const parmsP,
1512 unsigned int const parmSize) {
1513/*----------------------------------------------------------------------------
1514 This is the old deprecated interface, where the caller of the
1515 xmlrpc_server_abyss API supplies an Abyss configuration file and
1516 we use it to daemonize (fork into the background, chdir, set uid, etc.)
1517 and run the Abyss server.
1518
1519 The new preferred interface, implemented by normalLevelAbyssRun(),
1520 instead lets Caller set up the process environment himself and pass
1521 Abyss parameters in memory. That's a more conventional and
1522 flexible API.
1523-----------------------------------------------------------------------------*/
1524 TServer server;
1525 abyss_bool success;
1526
1527 success = ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS"/usr/local/abyss""/htdocs", NULL((void*)0));
1528
1529 if (!success)
1530 xmlrpc_faultf(envP, "Failed to create Abyss server object");
1531 else {
1532 runfirstFn runfirst;
1533 void * runfirstArg;
1534
1535 assert(parmSize >= XMLRPC_APSIZE(config_file_name))((parmSize >= (((size_t)(char*)&((xmlrpc_server_abyss_parms
*)0)->config_file_name) + sizeof(((xmlrpc_server_abyss_parms
*)0)->config_file_name))) ? (void) (0) : __assert_fail ("parmSize >= (((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->config_file_name) + sizeof(((xmlrpc_server_abyss_parms *)0)->config_file_name))"
, "../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1535
, __PRETTY_FUNCTION__))
;
1536
1537 ConfReadServerFile(parmsP->config_file_name, &server);
1538
1539 assert(parmSize >= XMLRPC_APSIZE(registryP))((parmSize >= (((size_t)(char*)&((xmlrpc_server_abyss_parms
*)0)->registryP) + sizeof(((xmlrpc_server_abyss_parms *)0
)->registryP))) ? (void) (0) : __assert_fail ("parmSize >= (((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->registryP) + sizeof(((xmlrpc_server_abyss_parms *)0)->registryP))"
, "../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1539
, __PRETTY_FUNCTION__))
;
1540
1541 setHandlersRegistry(&server, "/RPC2", parmsP->registryP, false, NULL((void*)0),
1542 false, 0);
1543
1544 ServerInit(&server);
1545
1546 if (parmSize >= XMLRPC_APSIZE(runfirst_arg)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->runfirst_arg
) + sizeof(((xmlrpc_server_abyss_parms *)0)->runfirst_arg)
)
) {
1547 runfirst = parmsP->runfirst;
1548 runfirstArg = parmsP->runfirst_arg;
1549 } else {
1550 runfirst = NULL((void*)0);
1551 runfirstArg = NULL((void*)0);
1552 }
1553 runServerDaemon(&server, runfirst, runfirstArg);
1554
1555 ServerFree(&server);
1556 }
1557}
1558
1559
1560
1561static void
1562normalLevelAbyssRun(xmlrpc_env * const envP,
1563 const xmlrpc_server_abyss_parms * const parmsP,
1564 unsigned int const parmSize) {
1565
1566 xmlrpc_server_abyss_t * serverP;
1567
1568 xmlrpc_server_abyss_create(envP, parmsP, parmSize, &serverP);
1569
1570 if (!envP->fault_occurred) {
1571 xmlrpc_server_abyss_sig * oldHandlersP;
1572
1573 xmlrpc_server_abyss_setup_sig(envP, serverP, &oldHandlersP);
1574
1575 if (!envP->fault_occurred) {
1576 xmlrpc_server_abyss_run_server(envP, serverP);
1577
1578 xmlrpc_server_abyss_restore_sig(oldHandlersP);
1579
1580 free(oldHandlersP);
1581 }
1582 xmlrpc_server_abyss_destroy(serverP);
1583 }
1584}
1585
1586
1587
1588void
1589xmlrpc_server_abyss(xmlrpc_env * const envP,
1590 const xmlrpc_server_abyss_parms * const parmsP,
1591 unsigned int const parmSize) {
1592/*----------------------------------------------------------------------------
1593 Note that this is not re-entrant and not thread-safe, due to the
1594 global library initialization. If you want to run a server inside
1595 a thread of a multi-threaded program, use
1596 xmlrpc_server_abyss_create() instead. As required by that
1597 subroutine, your program will contain a call to
1598 xmlrpc_server_abyss_global_init() early in your program, when it is only
1599 one thread.
1600-----------------------------------------------------------------------------*/
1601 XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string
== ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c", 1601)
; while (0)
;
1602
1603 xmlrpc_server_abyss_global_init(envP);
1604
1605 if (!envP->fault_occurred) {
1606 if (parmSize < XMLRPC_APSIZE(registryP)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->registryP
) + sizeof(((xmlrpc_server_abyss_parms *)0)->registryP))
)
1607 xmlrpc_faultf(envP,
1608 "You must specify members at least up through "
1609 "'registryP' in the server parameters argument. "
1610 "That would mean the parameter size would be >= %u "
1611 "but you specified a size of %u",
1612 (unsigned)XMLRPC_APSIZE(registryP)(((size_t)(char*)&((xmlrpc_server_abyss_parms *)0)->registryP
) + sizeof(((xmlrpc_server_abyss_parms *)0)->registryP))
, parmSize);
1613 else {
1614 if (parmsP->config_file_name)
1615 oldHighLevelAbyssRun(envP, parmsP, parmSize);
1616 else
1617 normalLevelAbyssRun(envP, parmsP, parmSize);
1618
1619 }
1620 xmlrpc_server_abyss_global_term();
1621 }
1622}
1623
1624
1625
1626/*=========================================================================
1627 XML-RPC Server Method Registry
1628
1629 This is an old deprecated form of the server facilities that uses
1630 global variables.
1631=========================================================================*/
1632
1633/* These global variables must be treated as read-only after the
1634 server has started.
1635*/
1636
1637static TServer globalSrv;
1638 /* When you use the old interface (xmlrpc_server_abyss_init(), etc.),
1639 this is the Abyss server to which they refer. Obviously, there can be
1640 only one Abyss server per program using this interface.
1641 */
1642
1643static xmlrpc_registry * builtin_registryP;
1644
1645
1646
1647void
1648xmlrpc_server_abyss_init_registry(void) {
1649
1650 /* This used to just create the registry and Caller would be
1651 responsible for adding the handlers that use it.
1652
1653 But that isn't very modular -- the handlers and registry go
1654 together; there's no sense in using the built-in registry and
1655 not the built-in handlers because if you're custom building
1656 something, you can just make your own regular registry. So now
1657 we tie them together, and we don't export our handlers.
1658 */
1659 xmlrpc_env env;
1660
1661 xmlrpc_env_init(&env);
1662 builtin_registryP = xmlrpc_registry_new(&env);
1663 dieIfFaultOccurred(&env);
1664 xmlrpc_env_clean(&env);
1665
1666 setHandlersRegistry(&globalSrv, "/RPC2", builtin_registryP, false, NULL((void*)0),
1667 false, 0);
1668}
1669
1670
1671
1672xmlrpc_registry *
1673xmlrpc_server_abyss_registry(void) {
1674
1675 /* This is highly deprecated. If you want to mess with a registry,
1676 make your own with xmlrpc_registry_new() -- don't mess with the
1677 internal one.
1678 */
1679 return builtin_registryP;
1680}
1681
1682
1683
1684/* A quick & easy shorthand for adding a method. */
1685void
1686xmlrpc_server_abyss_add_method(char * const method_name,
1687 xmlrpc_method const method,
1688 void * const user_data) {
1689 xmlrpc_env env;
1690
1691 xmlrpc_env_init(&env);
1692 xmlrpc_registry_add_method(&env, builtin_registryP, NULL((void*)0), method_name,
1693 method, user_data);
1694 dieIfFaultOccurred(&env);
1695 xmlrpc_env_clean(&env);
1696}
1697
1698
1699
1700void
1701xmlrpc_server_abyss_add_method_w_doc(char * const method_name,
1702 xmlrpc_method const method,
1703 void * const user_data,
1704 char * const signature,
1705 char * const help) {
1706
1707 xmlrpc_env env;
1708 xmlrpc_env_init(&env);
1709 xmlrpc_registry_add_method_w_doc(
1710 &env, builtin_registryP, NULL((void*)0), method_name,
1711 method, user_data, signature, help);
1712 dieIfFaultOccurred(&env);
1713 xmlrpc_env_clean(&env);
1714}
1715
1716
1717
1718void
1719xmlrpc_server_abyss_init(int const flags ATTR_UNUSED__attribute__((__unused__)),
1720 const char * const config_file) {
1721
1722 abyss_bool success;
1723
1724 success = ServerCreate(&globalSrv, "XmlRpcServer", 8080,
1725 DEFAULT_DOCS"/usr/local/abyss""/htdocs", NULL((void*)0));
1726
1727 if (!success)
1728 abort();
1729 else {
1730 ConfReadServerFile(config_file, &globalSrv);
1731
1732 xmlrpc_server_abyss_init_registry();
1733 /* Installs /RPC2 handler and default handler that use the
1734 built-in registry.
1735 */
1736
1737 ServerInit(&globalSrv);
1738 }
1739}
1740
1741
1742
1743void
1744xmlrpc_server_abyss_run_first(runfirstFn const runfirst,
1745 void * const runfirstArg) {
1746
1747 runServerDaemon(&globalSrv, runfirst, runfirstArg);
1748}
1749
1750
1751
1752void
1753xmlrpc_server_abyss_run(void) {
1754 runServerDaemon(&globalSrv, NULL((void*)0), NULL((void*)0));
1755}
1756
1757
1758
1759/*
1760** Copyright (C) 2001 by First Peer, Inc. All rights reserved.
1761**
1762** Redistribution and use in source and binary forms, with or without
1763** modification, are permitted provided that the following conditions
1764** are met:
1765** 1. Redistributions of source code must retain the above copyright
1766** notice, this list of conditions and the following disclaimer.
1767** 2. Redistributions in binary form must reproduce the above copyright
1768** notice, this list of conditions and the following disclaimer in the
1769** documentation and/or other materials provided with the distribution.
1770** 3. The name of the author may not be used to endorse or promote products
1771** derived from this software without specific prior written permission.
1772**
1773** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1774** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1775** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1776** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1777** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1778** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1779** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1780** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1781** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1782** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1783** SUCH DAMAGE.
1784**
1785** There is more copyright information in the bottom half of this file.
1786** Please see it for more details.
1787*/