~ubuntu-branches/ubuntu/lucid/cmake/lucid

« back to all changes in this revision

Viewing changes to Utilities/cmxmlrpc/xmlrpc_server_abyss.c

  • Committer: Bazaar Package Importer
  • Author(s): Artur Rona
  • Date: 2009-12-16 11:11:54 UTC
  • mfrom: (3.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20091216111154-6accvv6yq86h2hkc
Tags: 2.8.0-5ubuntu1
* Merge from debian testing (LP: #497349). Remaining changes:
  - Keep the Replaces: on cmake-data to cover the Kubuntu version from
    Jaunty in case someone decides to do an (unsupported) Jaunty->Lucid
    upgrade.

Show diffs side-by-side

added added

removed removed

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