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 |
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 | */ |