1
0

xmlrpc_server_abyss.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
  2. **
  3. ** Redistribution and use in source and binary forms, with or without
  4. ** modification, are permitted provided that the following conditions
  5. ** are met:
  6. ** 1. Redistributions of source code must retain the above copyright
  7. ** notice, this list of conditions and the following disclaimer.
  8. ** 2. Redistributions in binary form must reproduce the above copyright
  9. ** notice, this list of conditions and the following disclaimer in the
  10. ** documentation and/or other materials provided with the distribution.
  11. ** 3. The name of the author may not be used to endorse or promote products
  12. ** derived from this software without specific prior written permission.
  13. **
  14. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. ** SUCH DAMAGE.
  25. **
  26. ** There is more copyright information in the bottom half of this file.
  27. ** Please see it for more details. */
  28. #include "xmlrpc_config.h"
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include "abyss.h"
  33. #include "xmlrpc.h"
  34. #include "xmlrpc_server.h"
  35. #include "xmlrpc_int.h"
  36. #include "xmlrpc_server_abyss.h"
  37. #include "xmlrpc_server_abyss_int.h"
  38. /*=========================================================================
  39. ** die_if_fault_occurred
  40. **=========================================================================
  41. ** If certain kinds of out-of-memory errors occur during server setup,
  42. ** we want to quit and print an error.
  43. */
  44. static void die_if_fault_occurred(xmlrpc_env *env) {
  45. if (env->fault_occurred) {
  46. fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n",
  47. env->fault_string, env->fault_code);
  48. exit(1);
  49. }
  50. }
  51. /*=========================================================================
  52. ** send_xml_data
  53. **=========================================================================
  54. ** Blast some XML data back to the client.
  55. */
  56. static void
  57. send_xml_data (TSession * const r,
  58. char * const buffer,
  59. uint64 const len) {
  60. const char * const http_cookie = NULL;
  61. /* This used to set http_cookie to getenv("HTTP_COOKIE"), but
  62. that doesn't make any sense -- environment variables are not
  63. appropriate for this. So for now, cookie code is disabled.
  64. - Bryan 2004.10.03.
  65. */
  66. /* fwrite(buffer, sizeof(char), len, stderr); */
  67. /* XXX - Is it safe to chunk our response? */
  68. ResponseChunked(r);
  69. ResponseStatus(r, 200);
  70. if (http_cookie) {
  71. /* There's an auth cookie, so pass it back in the response. */
  72. char *cookie_response;
  73. cookie_response = malloc(10+strlen(http_cookie));
  74. sprintf(cookie_response, "auth=%s", http_cookie);
  75. /* Return abyss response. */
  76. ResponseAddField(r, "Set-Cookie", cookie_response);
  77. free(cookie_response);
  78. }
  79. ResponseContentType(r, "text/xml; charset=\"utf-8\"");
  80. ResponseContentLength(r, len);
  81. ResponseWrite(r);
  82. HTTPWrite(r, buffer, len);
  83. HTTPWriteEnd(r);
  84. }
  85. /*=========================================================================
  86. ** send_error
  87. **=========================================================================
  88. ** Send an error back to the client.
  89. */
  90. static void
  91. send_error(TSession * const abyssSessionP,
  92. unsigned int const status) {
  93. ResponseStatus(abyssSessionP, (uint16) status);
  94. ResponseError(abyssSessionP);
  95. }
  96. /*=========================================================================
  97. ** get_buffer_data
  98. **=========================================================================
  99. ** Extract some data from the TConn's underlying input buffer. Do not
  100. ** extract more than 'max'.
  101. */
  102. static void
  103. get_buffer_data(TSession * const r,
  104. int const max,
  105. char ** const out_start,
  106. int * const out_len) {
  107. /* Point to the start of our data. */
  108. *out_start = &r->conn->buffer[r->conn->bufferpos];
  109. /* Decide how much data to retrieve. */
  110. *out_len = r->conn->buffersize - r->conn->bufferpos;
  111. if (*out_len > max)
  112. *out_len = max;
  113. /* Update our buffer position. */
  114. r->conn->bufferpos += *out_len;
  115. }
  116. /*=========================================================================
  117. ** get_body
  118. **=========================================================================
  119. ** Slurp the body of the request into an xmlrpc_mem_block.
  120. */
  121. static void
  122. getBody(xmlrpc_env * const envP,
  123. TSession * const abyssSessionP,
  124. unsigned int const contentSize,
  125. xmlrpc_mem_block ** const bodyP) {
  126. /*----------------------------------------------------------------------------
  127. Get the entire body from the Abyss session and return it as the new
  128. memblock *bodyP.
  129. The first chunk of the body may already be in Abyss's buffer. We
  130. retrieve that before reading more.
  131. -----------------------------------------------------------------------------*/
  132. xmlrpc_mem_block * body;
  133. body = xmlrpc_mem_block_new(envP, 0);
  134. if (!envP->fault_occurred) {
  135. unsigned int bytesRead;
  136. char * chunkPtr;
  137. int chunkLen;
  138. bytesRead = 0;
  139. while (!envP->fault_occurred && bytesRead < contentSize) {
  140. get_buffer_data(abyssSessionP, contentSize - bytesRead,
  141. &chunkPtr, &chunkLen);
  142. bytesRead += chunkLen;
  143. XMLRPC_TYPED_MEM_BLOCK_APPEND(char, envP, body,
  144. chunkPtr, chunkLen);
  145. if (bytesRead < contentSize) {
  146. /* Get the next chunk of data from the connection into the
  147. buffer
  148. */
  149. abyss_bool succeeded;
  150. /* Reset our read buffer & flush data from previous reads. */
  151. ConnReadInit(abyssSessionP->conn);
  152. /* Read more network data into our buffer. If we encounter
  153. a timeout, exit immediately. We're very forgiving about
  154. the timeout here. We allow a full timeout per network
  155. read, which would allow somebody to keep a connection
  156. alive nearly indefinitely. But it's hard to do anything
  157. intelligent here without very complicated code.
  158. */
  159. succeeded = ConnRead(abyssSessionP->conn,
  160. abyssSessionP->server->timeout);
  161. if (!succeeded)
  162. xmlrpc_env_set_fault_formatted(
  163. envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for "
  164. "client to send its POST data");
  165. }
  166. }
  167. if (envP->fault_occurred)
  168. xmlrpc_mem_block_free(body);
  169. else
  170. *bodyP = body;
  171. }
  172. }
  173. static void
  174. storeCookies(TSession * const httpRequestP,
  175. unsigned int * const httpErrorP) {
  176. /*----------------------------------------------------------------------------
  177. Get the cookie settings from the HTTP headers and remember them for
  178. use in responses.
  179. -----------------------------------------------------------------------------*/
  180. const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
  181. if (cookie) {
  182. /*
  183. Setting the value in an environment variable doesn't make
  184. any sense. So for now, cookie code is disabled.
  185. -Bryan 04.10.03.
  186. setenv("HTTP_COOKIE", cookie, 1);
  187. */
  188. }
  189. /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */
  190. *httpErrorP = 0;
  191. }
  192. static void
  193. validateContentType(TSession * const httpRequestP,
  194. unsigned int * const httpErrorP) {
  195. /*----------------------------------------------------------------------------
  196. If the client didn't specify a content-type of "text/xml", return
  197. "400 Bad Request". We can't allow the client to default this header,
  198. because some firewall software may rely on all XML-RPC requests
  199. using the POST method and a content-type of "text/xml".
  200. -----------------------------------------------------------------------------*/
  201. const char * const content_type =
  202. RequestHeaderValue(httpRequestP, "content-type");
  203. if (content_type == NULL || strcmp(content_type, "text/xml") != 0)
  204. *httpErrorP = 400;
  205. else
  206. *httpErrorP = 0;
  207. }
  208. static void
  209. processContentLength(TSession * const httpRequestP,
  210. unsigned int * const inputLenP,
  211. unsigned int * const httpErrorP) {
  212. /*----------------------------------------------------------------------------
  213. Make sure the content length is present and non-zero. This is
  214. technically required by XML-RPC, but we only enforce it because we
  215. don't want to figure out how to safely handle HTTP < 1.1 requests
  216. without it. If the length is missing, return "411 Length Required".
  217. -----------------------------------------------------------------------------*/
  218. const char * const content_length =
  219. RequestHeaderValue(httpRequestP, "content-length");
  220. if (content_length == NULL)
  221. *httpErrorP = 411;
  222. else {
  223. int const contentLengthValue = atoi(content_length);
  224. if (contentLengthValue <= 0)
  225. *httpErrorP = 400;
  226. else {
  227. *httpErrorP = 0;
  228. *inputLenP = (unsigned int)contentLengthValue;
  229. }
  230. }
  231. }
  232. /****************************************************************************
  233. Abyss handlers (to be registered with and called by Abyss)
  234. ****************************************************************************/
  235. /* XXX - This variable is *not* currently threadsafe. Once the server has
  236. ** been started, it must be treated as read-only. */
  237. static xmlrpc_registry *global_registryP;
  238. static const char * trace_abyss;
  239. static void
  240. processCall(TSession * const abyssSessionP,
  241. int const inputLen) {
  242. /*----------------------------------------------------------------------------
  243. Handle an RPC request. This is an HTTP request that has the proper form
  244. to be one of our RPCs.
  245. -----------------------------------------------------------------------------*/
  246. xmlrpc_env env;
  247. if (trace_abyss)
  248. fprintf(stderr, "xmlrpc_server_abyss RPC2 handler processing RPC.\n");
  249. xmlrpc_env_init(&env);
  250. /* SECURITY: Make sure our content length is legal.
  251. XXX - We can cast 'inputLen' because we know it's >= 0, yes?
  252. */
  253. if ((size_t) inputLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
  254. xmlrpc_env_set_fault_formatted(
  255. &env, XMLRPC_LIMIT_EXCEEDED_ERROR,
  256. "XML-RPC request too large (%d bytes)", inputLen);
  257. else {
  258. xmlrpc_mem_block *body;
  259. /* Read XML data off the wire. */
  260. getBody(&env, abyssSessionP, inputLen, &body);
  261. if (!env.fault_occurred) {
  262. xmlrpc_mem_block * output;
  263. /* Process the RPC. */
  264. output = xmlrpc_registry_process_call(
  265. &env, global_registryP, NULL,
  266. XMLRPC_MEMBLOCK_CONTENTS(char, body),
  267. XMLRPC_MEMBLOCK_SIZE(char, body));
  268. if (!env.fault_occurred) {
  269. /* Send our the result. */
  270. send_xml_data(abyssSessionP,
  271. XMLRPC_MEMBLOCK_CONTENTS(char, output),
  272. XMLRPC_MEMBLOCK_SIZE(char, output));
  273. XMLRPC_MEMBLOCK_FREE(char, output);
  274. }
  275. XMLRPC_MEMBLOCK_FREE(char, body);
  276. }
  277. }
  278. if (env.fault_occurred) {
  279. if (env.fault_code == XMLRPC_TIMEOUT_ERROR)
  280. send_error(abyssSessionP, 408); /* 408 Request Timeout */
  281. else
  282. send_error(abyssSessionP, 500); /* 500 Internal Server Error */
  283. }
  284. xmlrpc_env_clean(&env);
  285. }
  286. /*=========================================================================
  287. ** xmlrpc_server_abyss_rpc2_handler
  288. **=========================================================================
  289. ** This handler processes all requests to '/RPC2'. See the header for
  290. ** more documentation.
  291. */
  292. xmlrpc_bool
  293. xmlrpc_server_abyss_rpc2_handler (TSession * const r) {
  294. xmlrpc_bool retval;
  295. if (trace_abyss)
  296. fprintf(stderr, "xmlrpc_server_abyss RPC2 handler called.\n");
  297. /* We handle only requests to /RPC2, the default XML-RPC URL.
  298. Everything else we pass through to other handlers.
  299. */
  300. if (strcmp(r->uri, "/RPC2") != 0)
  301. retval = FALSE;
  302. else {
  303. retval = TRUE;
  304. /* We understand only the POST HTTP method. For anything else, return
  305. "405 Method Not Allowed".
  306. */
  307. if (r->method != m_post)
  308. send_error(r, 405);
  309. else {
  310. unsigned int httpError;
  311. storeCookies(r, &httpError);
  312. if (httpError)
  313. send_error(r, httpError);
  314. else {
  315. unsigned int httpError;
  316. validateContentType(r, &httpError);
  317. if (httpError)
  318. send_error(r, httpError);
  319. else {
  320. unsigned int httpError;
  321. int inputLen;
  322. processContentLength(r, &inputLen, &httpError);
  323. if (httpError)
  324. send_error(r, httpError);
  325. processCall(r, inputLen);
  326. }
  327. }
  328. }
  329. }
  330. if (trace_abyss)
  331. fprintf(stderr, "xmlrpc_server_abyss RPC2 handler returning.\n");
  332. return retval;
  333. }
  334. /*=========================================================================
  335. ** xmlrpc_server_abyss_default_handler
  336. **=========================================================================
  337. ** This handler returns a 404 Not Found for all requests. See the header
  338. ** for more documentation.
  339. */
  340. xmlrpc_bool
  341. xmlrpc_server_abyss_default_handler (TSession * const r) {
  342. send_error(r, 404);
  343. return TRUE;
  344. }
  345. /**************************************************************************
  346. **
  347. ** The code below was adapted from the main.c file of the Abyss webserver
  348. ** project. In addition to the other copyrights on this file, the following
  349. ** code is also under this copyright:
  350. **
  351. ** Copyright (C) 2000 by Moez Mahfoudh <[email protected]>.
  352. ** All rights reserved.
  353. **
  354. ** Redistribution and use in source and binary forms, with or without
  355. ** modification, are permitted provided that the following conditions
  356. ** are met:
  357. ** 1. Redistributions of source code must retain the above copyright
  358. ** notice, this list of conditions and the following disclaimer.
  359. ** 2. Redistributions in binary form must reproduce the above copyright
  360. ** notice, this list of conditions and the following disclaimer in the
  361. ** documentation and/or other materials provided with the distribution.
  362. ** 3. The name of the author may not be used to endorse or promote products
  363. ** derived from this software without specific prior written permission.
  364. **
  365. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  366. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  367. ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  368. ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  369. ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  370. ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  371. ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  372. ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  373. ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  374. ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  375. ** SUCH DAMAGE.
  376. **
  377. **************************************************************************/
  378. #include <time.h>
  379. #include <fcntl.h>
  380. #ifdef _WIN32
  381. #include <io.h>
  382. #else
  383. /* Must check this
  384. #include <sys/io.h>
  385. */
  386. #endif /* _WIN32 */
  387. #ifdef _UNIX
  388. #include <sys/signal.h>
  389. #include <sys/wait.h>
  390. #include <grp.h>
  391. #endif
  392. #ifdef _UNIX
  393. static void
  394. sigterm(int const sig) {
  395. TraceExit("Signal %d received. Exiting...\n",sig);
  396. }
  397. #endif
  398. #ifdef _UNIX
  399. static void
  400. sigchld(int const sig ATTR_UNUSED) {
  401. /*----------------------------------------------------------------------------
  402. This is a signal handler for a SIGCHLD signal (which informs us that
  403. one of our child processes has terminated).
  404. We respond by reaping the zombie process.
  405. Implementation note: In some systems, just setting the signal handler
  406. to SIG_IGN (ignore signal) does this. In others, it doesn't.
  407. -----------------------------------------------------------------------------*/
  408. pid_t pid;
  409. int status;
  410. /* Reap defunct children until there aren't any more. */
  411. for (;;) {
  412. pid = waitpid( (pid_t) -1, &status, WNOHANG );
  413. /* none left */
  414. if (pid==0)
  415. break;
  416. if (pid<0) {
  417. /* because of ptrace */
  418. if (errno==EINTR)
  419. continue;
  420. break;
  421. }
  422. }
  423. }
  424. #endif /* _UNIX */
  425. static TServer globalSrv;
  426. /* When you use the old interface (xmlrpc_server_abyss_init(), etc.),
  427. this is the Abyss server to which they refer. Obviously, there can be
  428. only one Abyss server per program using this interface.
  429. */
  430. void
  431. xmlrpc_server_abyss_init(int const flags ATTR_UNUSED,
  432. const char * const config_file) {
  433. DateInit();
  434. MIMETypeInit();
  435. ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
  436. ConfReadServerFile(config_file, &globalSrv);
  437. xmlrpc_server_abyss_init_registry();
  438. /* Installs /RPC2 handler and default handler that use the
  439. built-in registry.
  440. */
  441. ServerInit(&globalSrv);
  442. }
  443. static void
  444. setupSignalHandlers(void) {
  445. #ifdef _UNIX
  446. struct sigaction mysigaction;
  447. sigemptyset(&mysigaction.sa_mask);
  448. mysigaction.sa_flags = 0;
  449. /* These signals abort the program, with tracing */
  450. mysigaction.sa_handler = sigterm;
  451. sigaction(SIGTERM, &mysigaction, NULL);
  452. sigaction(SIGINT, &mysigaction, NULL);
  453. sigaction(SIGHUP, &mysigaction, NULL);
  454. sigaction(SIGUSR1, &mysigaction, NULL);
  455. /* This signal indicates connection closed in the middle */
  456. mysigaction.sa_handler = SIG_IGN;
  457. sigaction(SIGPIPE, &mysigaction, NULL);
  458. /* This signal indicates a child process (request handler) has died */
  459. mysigaction.sa_handler = sigchld;
  460. sigaction(SIGCHLD, &mysigaction, NULL);
  461. #endif
  462. }
  463. static void
  464. runServer(TServer * const srvP,
  465. runfirstFn const runfirst,
  466. void * const runfirstArg) {
  467. setupSignalHandlers();
  468. #ifdef _UNIX
  469. /* Become a daemon */
  470. switch (fork()) {
  471. case 0:
  472. break;
  473. case -1:
  474. TraceExit("Unable to become a daemon");
  475. default:
  476. exit(0);
  477. };
  478. setsid();
  479. /* Change the current user if we are root */
  480. if (getuid()==0) {
  481. if (srvP->uid == (uid_t)-1)
  482. TraceExit("Can't run under root privileges. "
  483. "Please add a User option in your "
  484. "Abyss configuration file.");
  485. #ifdef HAVE_SETGROUPS
  486. if (setgroups(0,NULL)==(-1))
  487. TraceExit("Failed to setup the group.");
  488. if (srvP->gid != (gid_t)-1)
  489. if (setgid(srvP->gid)==(-1))
  490. TraceExit("Failed to change the group.");
  491. #endif
  492. if (setuid(srvP->uid) == -1)
  493. TraceExit("Failed to change the user.");
  494. };
  495. if (srvP->pidfile!=(-1)) {
  496. char z[16];
  497. sprintf(z,"%d",getpid());
  498. FileWrite(&srvP->pidfile,z,strlen(z));
  499. FileClose(&srvP->pidfile);
  500. };
  501. #endif
  502. /* We run the user supplied runfirst after forking, but before accepting
  503. connections (helpful when running with threads)
  504. */
  505. if (runfirst)
  506. runfirst(runfirstArg);
  507. ServerRun(srvP);
  508. /* We can't exist here because ServerRun doesn't return */
  509. XMLRPC_ASSERT(FALSE);
  510. }
  511. void
  512. xmlrpc_server_abyss_run_first(runfirstFn const runfirst,
  513. void * const runfirstArg) {
  514. runServer(&globalSrv, runfirst, runfirstArg);
  515. }
  516. void
  517. xmlrpc_server_abyss_run(void) {
  518. runServer(&globalSrv, NULL, NULL);
  519. }
  520. void
  521. xmlrpc_server_abyss_set_handlers(TServer * const srvP,
  522. xmlrpc_registry * const registryP) {
  523. /* Abyss ought to have a way to register with a handler an argument
  524. that gets passed to the handler every time it is called. That's
  525. where we should put the registry handle. But we don't find such
  526. a thing in Abyss, so we use the global variable 'global_registryP'.
  527. */
  528. global_registryP = registryP;
  529. trace_abyss = getenv("XMLRPC_TRACE_ABYSS");
  530. ServerAddHandler(srvP, xmlrpc_server_abyss_rpc2_handler);
  531. ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler);
  532. }
  533. void
  534. xmlrpc_server_abyss(xmlrpc_env * const envP,
  535. const xmlrpc_server_abyss_parms * const parmsP,
  536. unsigned int const parm_size) {
  537. XMLRPC_ASSERT_ENV_OK(envP);
  538. if (parm_size < XMLRPC_APSIZE(registryP))
  539. xmlrpc_env_set_fault_formatted(
  540. envP, XMLRPC_INTERNAL_ERROR,
  541. "You must specify members at least up through "
  542. "'registryP' in the server parameters argument. "
  543. "That would mean the parameter size would be >= %u "
  544. "but you specified a size of %u",
  545. XMLRPC_APSIZE(registryP), parm_size);
  546. else {
  547. TServer srv;
  548. runfirstFn runfirst;
  549. void * runfirstArg;
  550. DateInit();
  551. MIMETypeInit();
  552. ServerCreate(&srv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL);
  553. ConfReadServerFile(parmsP->config_file_name, &srv);
  554. xmlrpc_server_abyss_set_handlers(&srv, parmsP->registryP);
  555. ServerInit(&srv);
  556. if (parm_size >= XMLRPC_APSIZE(runfirst_arg)) {
  557. runfirst = parmsP->runfirst;
  558. runfirstArg = parmsP->runfirst_arg;
  559. } else {
  560. runfirst = NULL;
  561. runfirstArg = NULL;
  562. }
  563. runServer(&srv, runfirst, runfirstArg);
  564. }
  565. }
  566. /*=========================================================================
  567. ** XML-RPC Server Method Registry
  568. **=========================================================================
  569. ** A simple front-end to our method registry.
  570. */
  571. /* XXX - This variable is *not* currently threadsafe. Once the server has
  572. ** been started, it must be treated as read-only. */
  573. static xmlrpc_registry *builtin_registryP;
  574. void
  575. xmlrpc_server_abyss_init_registry(void) {
  576. /* This used to just create the registry and Caller would be
  577. responsible for adding the handlers that use it.
  578. But that isn't very modular -- the handlers and registry go
  579. together; there's no sense in using the built-in registry and
  580. not the built-in handlers because if you're custom building
  581. something, you can just make your own regular registry. So now
  582. we tie them together, and we don't export our handlers.
  583. */
  584. xmlrpc_env env;
  585. xmlrpc_env_init(&env);
  586. builtin_registryP = xmlrpc_registry_new(&env);
  587. die_if_fault_occurred(&env);
  588. xmlrpc_env_clean(&env);
  589. xmlrpc_server_abyss_set_handlers(&globalSrv, builtin_registryP);
  590. }
  591. xmlrpc_registry *
  592. xmlrpc_server_abyss_registry(void) {
  593. /* This is highly deprecated. If you want to mess with a registry,
  594. make your own with xmlrpc_registry_new() -- don't mess with the
  595. internal one.
  596. */
  597. return builtin_registryP;
  598. }
  599. /* A quick & easy shorthand for adding a method. */
  600. void
  601. xmlrpc_server_abyss_add_method (char * const method_name,
  602. xmlrpc_method const method,
  603. void * const user_data) {
  604. xmlrpc_env env;
  605. xmlrpc_env_init(&env);
  606. xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name,
  607. method, user_data);
  608. die_if_fault_occurred(&env);
  609. xmlrpc_env_clean(&env);
  610. }
  611. void
  612. xmlrpc_server_abyss_add_method_w_doc (char * const method_name,
  613. xmlrpc_method const method,
  614. void * const user_data,
  615. char * const signature,
  616. char * const help) {
  617. xmlrpc_env env;
  618. xmlrpc_env_init(&env);
  619. xmlrpc_registry_add_method_w_doc(
  620. &env, builtin_registryP, NULL, method_name,
  621. method, user_data, signature, help);
  622. die_if_fault_occurred(&env);
  623. xmlrpc_env_clean(&env);
  624. }