| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_server_abyss.c | 
| Location: | line 1296, column 1 | 
| Description: | Potential leak of memory pointed to by 'serverP' | 
| 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 | */ |