File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c |
Location: | line 1605, column 10 |
Description: | Access to field 'fault_occurred' results in a dereference of a null pointer (loaded from variable 'envP') |
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 | ||||||
35 | struct xmlrpc_server_abyss { | |||||
36 | TServer abyssServer; | |||||
37 | TChanSwitch * chanSwitchP; | |||||
38 | bool shutdownEnabled; | |||||
39 | /* User wants system.shutdown to succeed */ | |||||
40 | }; | |||||
41 | ||||||
42 | ||||||
43 | ||||||
44 | static void | |||||
45 | dieIfFaultOccurred(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 | ||||||
56 | static void | |||||
57 | initAbyss(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 | ||||||
70 | static void | |||||
71 | termAbyss(void) { | |||||
72 | ||||||
73 | AbyssTerm(); | |||||
74 | } | |||||
75 | ||||||
76 | ||||||
77 | ||||||
78 | static unsigned int globallyInitialized = 0; | |||||
79 | /* Initialization count */ | |||||
80 | ||||||
81 | ||||||
82 | void | |||||
83 | xmlrpc_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 | ||||||
99 | void | |||||
100 | xmlrpc_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 | ||||||
116 | static void | |||||
117 | validateGlobalInit(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 | ||||||
126 | static void | |||||
127 | addAuthCookie(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 | ||||||
147 | static void | |||||
148 | sendResponse(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 | ||||||
225 | static void | |||||
226 | sendError(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 | ||||||
238 | static void | |||||
239 | traceChunkRead(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 | ||||||
247 | static void | |||||
248 | refillBufferFromConnection(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 | ||||||
270 | static void | |||||
271 | getBody(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 | ||||||
316 | static void | |||||
317 | storeCookies(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 | ||||||
341 | static void | |||||
342 | processContentLength(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 | ||||||
394 | static void | |||||
395 | traceHandlerCalled(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 | ||||||
428 | static void | |||||
429 | processCall(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 | ||||||
498 | static void | |||||
499 | processXmlrpcCall(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 | ||||||
516 | static const char * trace_abyss; | |||||
517 | ||||||
518 | ||||||
519 | struct 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 | ||||||
535 | static void | |||||
536 | termAccessControl(ResponseAccessCtl * const accessCtlP) { | |||||
537 | ||||||
538 | xmlrpc_strfreenull(accessCtlP->allowOrigin); | |||||
539 | } | |||||
540 | ||||||
541 | ||||||
542 | ||||||
543 | static void | |||||
544 | termUriHandler(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 | ||||||
555 | static void | |||||
556 | handleXmlRpcCallReq(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 | ||||||
610 | static void | |||||
611 | handleXmlRpcOptionsReq(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 | ||||||
625 | static void | |||||
626 | handleIfXmlrpcReq(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 | ||||||
697 | static xmlrpc_bool | |||||
698 | xmlrpc_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 | ||||||
726 | static void | |||||
727 | setHandler(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 | ||||||
759 | static void | |||||
760 | interpretHttpAccessControl( | |||||
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 | ||||||
783 | void | |||||
784 | xmlrpc_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; | |||||
792 | ||||||
793 | MALLOCVAR_NOFAIL(uriHandlerXmlrpcP)do {if ((uriHandlerXmlrpcP = malloc(sizeof(*uriHandlerXmlrpcP ))) == ((void*)0)) abort();} while(0); | |||||
794 | ||||||
795 | if (!envP->fault_occurred) { | |||||
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))) | |||||
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) { | |||||
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))) | |||||
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) { | |||||
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))) | |||||
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) { | |||||
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)) && | |||||
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) | |||||
832 | termAccessControl(&uriHandlerXmlrpcP->accessControl); | |||||
833 | } | |||||
834 | if (!envP->fault_occurred) | |||||
835 | setHandler(envP, srvP, uriHandlerXmlrpcP, xmlProcessorMaxStackSize); | |||||
836 | ||||||
837 | if (envP->fault_occurred) | |||||
838 | free(uriHandlerXmlrpcP); | |||||
839 | } | |||||
840 | ||||||
841 | ||||||
842 | ||||||
843 | void | |||||
844 | xmlrpc_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 | ||||||
874 | void | |||||
875 | xmlrpc_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 | ||||||
893 | void | |||||
894 | xmlrpc_server_abyss_set_default_handler(TServer * const srvP) { | |||||
895 | ||||||
896 | ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler); | |||||
897 | } | |||||
898 | ||||||
899 | ||||||
900 | ||||||
901 | static void | |||||
902 | setHandlersRegistry(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( | |||||
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 | ||||||
937 | void | |||||
938 | xmlrpc_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 | ||||||
947 | void | |||||
948 | xmlrpc_server_abyss_set_handlers(TServer * const srvP, | |||||
949 | xmlrpc_registry * const registryP) { | |||||
950 | ||||||
951 | setHandlersRegistry(srvP, "/RPC2", registryP, false, NULL((void*)0), false, 0); | |||||
952 | } | |||||
953 | ||||||
954 | ||||||
955 | ||||||
956 | /*============================================================================ | |||||
957 | createServer() | |||||
958 | ============================================================================*/ | |||||
959 | ||||||
960 | static void | |||||
961 | setAdditionalServerParms(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 | ||||||
980 | static void | |||||
981 | extractServerCreateParms( | |||||
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 | ||||||
1026 | static void | |||||
1027 | chanSwitchCreateOsSocket(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 | ||||||
1041 | static void | |||||
1042 | createServerBoundSocket(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 | ||||||
1076 | static void | |||||
1077 | createServerBare(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 | ||||||
1117 | static const char * | |||||
1118 | uriPathParm(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 | ||||||
1133 | static bool | |||||
1134 | chunkResponseParm(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 | ||||||
1144 | static const char * | |||||
1145 | allowOriginParm(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 | ||||||
1155 | static bool | |||||
1156 | expiresParm(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 | ||||||
1166 | static unsigned int | |||||
1167 | maxAgeParm(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 | ||||||
1177 | static void | |||||
1178 | createServer(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 | ||||||
1202 | static bool | |||||
1203 | enableShutdownParm(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 | ||||||
1213 | static xmlrpc_server_shutdown_fn shutdownAbyss; | |||||
1214 | ||||||
1215 | static void | |||||
1216 | shutdownAbyss(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 | ||||||
1251 | void | |||||
1252 | xmlrpc_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 | ||||||
1300 | void | |||||
1301 | xmlrpc_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 | ||||||
1315 | void | |||||
1316 | xmlrpc_server_abyss_use_sigchld(xmlrpc_server_abyss_t * const serverP) { | |||||
1317 | ||||||
1318 | ServerUseSigchld(&serverP->abyssServer); | |||||
1319 | } | |||||
1320 | ||||||
1321 | ||||||
1322 | ||||||
1323 | void | |||||
1324 | xmlrpc_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 | ||||||
1332 | void | |||||
1333 | xmlrpc_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 | ||||||
1342 | void | |||||
1343 | xmlrpc_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 | ||||||
1352 | static void | |||||
1353 | sigchld(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 | ||||||
1394 | struct 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 | ||||||
1410 | static void | |||||
1411 | setupSignalHandlers(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 | ||||||
1430 | static void | |||||
1431 | restoreSignalHandlers(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 | ||||||
1442 | void | |||||
1443 | xmlrpc_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 | ||||||
1474 | void | |||||
1475 | xmlrpc_server_abyss_restore_sig( | |||||
1476 | const xmlrpc_server_abyss_sig * const oldHandlersP) { | |||||
1477 | ||||||
1478 | restoreSignalHandlers(oldHandlersP); | |||||
1479 | } | |||||
1480 | ||||||
1481 | ||||||
1482 | ||||||
1483 | static void | |||||
1484 | runServerDaemon(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 | ||||||
1509 | static void | |||||
1510 | oldHighLevelAbyssRun(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 | ||||||
1561 | static void | |||||
1562 | normalLevelAbyssRun(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 | ||||||
1588 | void | |||||
1589 | xmlrpc_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 | ||||||
1637 | static 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 | ||||||
1643 | static xmlrpc_registry * builtin_registryP; | |||||
1644 | ||||||
1645 | ||||||
1646 | ||||||
1647 | void | |||||
1648 | xmlrpc_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 | ||||||
1672 | xmlrpc_registry * | |||||
1673 | xmlrpc_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. */ | |||||
1685 | void | |||||
1686 | xmlrpc_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 | ||||||
1700 | void | |||||
1701 | xmlrpc_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 | ||||||
1718 | void | |||||
1719 | xmlrpc_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 | ||||||
1743 | void | |||||
1744 | xmlrpc_server_abyss_run_first(runfirstFn const runfirst, | |||||
1745 | void * const runfirstArg) { | |||||
1746 | ||||||
1747 | runServerDaemon(&globalSrv, runfirst, runfirstArg); | |||||
1748 | } | |||||
1749 | ||||||
1750 | ||||||
1751 | ||||||
1752 | void | |||||
1753 | xmlrpc_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 | */ |