Browse code

modules_k/*: moved k modules in directory modules/

Daniel-Constantin Mierla authored on 20/01/2013 11:57:52
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,629 +0,0 @@
1
-/* Copyright information is at the end of the file. */
2
-
3
-#include <time.h>
4
-#include <string.h>
5
-#include <stdlib.h>
6
-#include <stdio.h>
7
-#include <ctype.h>
8
-#include <assert.h>
9
-
10
-#include "abyss_mallocvar.h"
11
-#include "abyss_xmlrpc_int.h"
12
-#include <xmlrpc-c/abyss.h>
13
-#include "abyss_socket.h"
14
-#include "abyss_server.h"
15
-#include "abyss_thread.h"
16
-
17
-#include "abyss_conn.h"
18
-
19
-/*********************************************************************
20
-** Conn
21
-*********************************************************************/
22
-
23
-static TThreadProc connJob;
24
-
25
-static void
26
-connJob(void * const userHandle) {
27
-/*----------------------------------------------------------------------------
28
-   This is the root function for a thread that processes a connection
29
-   (performs HTTP transactions).
30
-    TConn * const connectionP = userHandle;
31
-
32
-    (connectionP->job)(connectionP);
33
-
34
-    connectionP->finished = TRUE;
35
-        /* Note that if we are running in a forked process, setting
36
-           connectionP->finished has no effect, because it's just our own
37
-           copy of *connectionP.  In this case, Parent must update his own
38
-           copy based on a SIGCHLD signal that the OS will generate right
39
-           after we exit.
40
-        */
41
-
42
-    ThreadExit(0);
43
-}
44
-
45
-
46
-
47
-static void
48
-connDone(TConn * const connectionP) {
49
-
50
-    /* In the forked case, this is designed to run in the parent
51
-       process after the child has terminated.
52
-    */
53
-    connectionP->finished = TRUE;
54
-
55
-    if (connectionP->done)
56
-        connectionP->done(connectionP);
57
-}
58
-
59
-
60
-
61
-static TThreadDoneFn threadDone;
62
-
63
-static void
64
-threadDone(void * const userHandle) {
65
-
66
-    TConn * const connectionP = userHandle;
67
-    
68
-    connDone(connectionP);
69
-}
70
-
71
-
72
-
73
-static void
74
-makeThread(TConn *             const connectionP,
75
-           enum abyss_foreback const foregroundBackground,
76
-           abyss_bool          const useSigchld,
77
-           const char **       const errorP) {
78
-           
79
-    switch (foregroundBackground) {
80
-    case ABYSS_FOREGROUND:
81
-        connectionP->hasOwnThread = FALSE;
82
-        *errorP = NULL;
83
-        break;
84
-    case ABYSS_BACKGROUND: {
85
-        const char * error;
86
-        connectionP->hasOwnThread = TRUE;
87
-        ThreadCreate(&connectionP->threadP, connectionP,
88
-                     &connJob, &threadDone, useSigchld,
89
-                     &error);
90
-        if (error) {
91
-            xmlrpc_asprintf(errorP, "Unable to create thread to "
92
-                            "process connection.  %s", error);
93
-            xmlrpc_strfree(error);
94
-        } else
95
-            *errorP = NULL;
96
-    } break;
97
-    } /* switch */
98
-}
99
-
100
-    
101
-
102
-void
103
-ConnCreate(TConn **            const connectionPP,
104
-           TServer *           const serverP,
105
-           TSocket *           const connectedSocketP,
106
-           TThreadProc *       const job,
107
-           TThreadDoneFn *     const done,
108
-           enum abyss_foreback const foregroundBackground,
109
-           abyss_bool          const useSigchld,
110
-           const char **       const errorP) {
111
-/*----------------------------------------------------------------------------
112
-   Create an HTTP connection.
113
-
114
-   A connection carries one or more HTTP transactions (request/response).
115
-
116
-   'connectedSocketP' transports the requests and responses.
117
-
118
-   The connection handles those HTTP requests.
119
-
120
-   The connection handles the requests primarily by running the
121
-   function 'job' once.  Some connections can do that autonomously, as
122
-   soon as the connection is created.  Others don't until Caller
123
-   subsequently calls ConnProcess.  Some connections complete the
124
-   processing before ConnProcess return, while others may run the
125
-   connection asynchronously to the creator, in the background, via a
126
-   TThread thread.  'foregroundBackground' determines which.
127
-
128
-   'job' calls methods of the connection to get requests and send
129
-   responses.
130
-
131
-   Some time after the HTTP transactions are all done, 'done' gets
132
-   called in some context.
133
-    TConn * connectionP;
134
-
135
-    MALLOCVAR(connectionP);
136
-
137
-    if (connectionP == NULL)
138
-        xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection "
139
-                        "descriptor.");
140
-    else {
141
-        abyss_bool success;
142
-        uint16_t peerPortNumber;
143
-
144
-        connectionP->server     = serverP;
145
-        connectionP->socketP    = connectedSocketP;
146
-        connectionP->buffersize = 0;
147
-        connectionP->bufferpos  = 0;
148
-        connectionP->finished   = FALSE;
149
-        connectionP->job        = job;
150
-        connectionP->done       = done;
151
-        connectionP->inbytes    = 0;
152
-        connectionP->outbytes   = 0;
153
-        connectionP->trace      = getenv("ABYSS_TRACE_CONN");
154
-
155
-        SocketGetPeerName(connectedSocketP,
156
-                          &connectionP->peerip, &peerPortNumber, &success);
157
-
158
-        if (success)
159
-            makeThread(connectionP, foregroundBackground, useSigchld, errorP);
160
-        else
161
-            xmlrpc_asprintf(errorP, "Failed to get peer name from socket.");
162
-    }
163
-    *connectionPP = connectionP;
164
-}
165
-
166
-
167
-
168
-abyss_bool
169
-ConnProcess(TConn * const connectionP) {
170
-/*----------------------------------------------------------------------------
171
-   Drive the main processing of a connection -- run the connection's
172
-   "job" function, which should read HTTP requests from the connection
173
-   and send HTTP responses.
174
-
175
-   If we succeed, we guarantee the connection's "done" function will get
176
-   called some time after all processing is complete.  It might be before
177
-   we return or some time after.  If we fail, we guarantee the "done"
178
-   function will not be called.
179
-    abyss_bool retval;
180
-
181
-    if (connectionP->hasOwnThread) {
182
-        /* There's a background thread to handle this connection.  Set
183
-           it running.
184
-        */
185
-        retval = ThreadRun(connectionP->threadP);
186
-    } else {
187
-        /* No background thread.  We just handle it here while Caller waits. */
188
-        (connectionP->job)(connectionP);
189
-        connDone(connectionP);
190
-        retval = TRUE;
191
-    }
192
-    return retval;
193
-}
194
-
195
-
196
-
197
-void
198
-ConnWaitAndRelease(TConn * const connectionP) {
199
-    if (connectionP->hasOwnThread)
200
-        ThreadWaitAndRelease(connectionP->threadP);
201
-    
202
-    free(connectionP);
203
-}
204
-
205
-
206
-
207
-abyss_bool
208
-ConnKill(TConn * connectionP) {
209
-    connectionP->finished = TRUE;
210
-    return ThreadKill(connectionP->threadP);
211
-}
212
-
213
-
214
-
215
-void
216
-ConnReadInit(TConn * const connectionP) {
217
-    if (connectionP->buffersize>connectionP->bufferpos) {
218
-        connectionP->buffersize -= connectionP->bufferpos;
219
-        memmove(connectionP->buffer,
220
-                connectionP->buffer+connectionP->bufferpos,
221
-                connectionP->buffersize);
222
-        connectionP->bufferpos = 0;
223
-    } else
224
-        connectionP->buffersize=connectionP->bufferpos = 0;
225
-
226
-    connectionP->inbytes=connectionP->outbytes = 0;
227
-}
228
-
229
-
230
-
231
-static void
232
-traceBuffer(const char * const label,
233
-            const char * const buffer,
234
-            unsigned int const size) {
235
-
236
-    unsigned int nonPrintableCount;
237
-    unsigned int i;
238
-    
239
-    nonPrintableCount = 0;  /* Initial value */
240
-    
241
-    for (i = 0; i < size; ++i) {
242
-        if (!isprint(buffer[i]) && buffer[i] != '\n' && buffer[i] != '\r')
243
-            ++nonPrintableCount;
244
-    }
245
-    if (nonPrintableCount > 0)
246
-        fprintf(stderr, "%s contains %u nonprintable characters.\n", 
247
-                label, nonPrintableCount);
248
-    
249
-    fprintf(stderr, "%s:\n", label);
250
-    fprintf(stderr, "%.*s\n", (int)size, buffer);
251
-}
252
-
253
-
254
-
255
-static void
256
-traceSocketRead(TConn *      const connectionP,
257
-                unsigned int const size) {
258
-
259
-    if (connectionP->trace)
260
-        traceBuffer("READ FROM SOCKET:",
261
-                    connectionP->buffer + connectionP->buffersize, size);
262
-}
263
-
264
-
265
-
266
-static void
267
-traceSocketWrite(TConn *      const connectionP,
268
-                 const char * const buffer,
269
-                 unsigned int const size,
270
-                 abyss_bool   const failed) {
271
-
272
-    if (connectionP->trace) {
273
-        const char * const label =
274
-            failed ? "FAILED TO WRITE TO SOCKET:" : "WROTE TO SOCKET";
275
-        traceBuffer(label, buffer, size);
276
-    }
277
-}
278
-
279
-
280
-
281
-static uint32_t
282
-bufferSpace(TConn * const connectionP) {
283
-    
284
-    return BUFFER_SIZE - connectionP->buffersize;
285
-}
286
-                    
287
-
288
-
289
-abyss_bool
290
-ConnRead(TConn *  const connectionP,
291
-         uint32_t const timeout) {
292
-/*----------------------------------------------------------------------------
293
-   Read some stuff on connection *connectionP from the socket.
294
-
295
-   Don't wait more than 'timeout' seconds for data to arrive.  Fail if
296
-   nothing arrives within that time.
297
-    time_t const deadline = time(NULL) + timeout;
298
-
299
-    abyss_bool cantGetData;
300
-    abyss_bool gotData;
301
-
302
-    cantGetData = FALSE;
303
-    gotData = FALSE;
304
-    
305
-    while (!gotData && !cantGetData) {
306
-        int const timeLeft = deadline - time(NULL);
307
-
308
-        if (timeLeft <= 0)
309
-            cantGetData = TRUE;
310
-        else {
311
-            int rc;
312
-            
313
-            rc = SocketWait(connectionP->socketP, TRUE, FALSE,
314
-                            timeLeft * 1000);
315
-            
316
-            if (rc != 1)
317
-                cantGetData = TRUE;
318
-            else {
319
-                uint32_t bytesAvail;
320
-            
321
-                bytesAvail = SocketAvailableReadBytes(connectionP->socketP);
322
-                
323
-                if (bytesAvail <= 0)
324
-                    cantGetData = TRUE;
325
-                else {
326
-                    uint32_t const bytesToRead =
327
-                        MIN(bytesAvail, bufferSpace(connectionP)-1);
328
-
329
-                    uint32_t bytesRead;
330
-
331
-                    bytesRead = SocketRead(
332
-                        connectionP->socketP,
333
-                        (unsigned char*)connectionP->buffer + connectionP->buffersize,
334
-                        bytesToRead);
335
-                    if (bytesRead > 0) {
336
-                        traceSocketRead(connectionP, bytesRead);
337
-                        connectionP->inbytes += bytesRead;
338
-                        connectionP->buffersize += bytesRead;
339
-                        connectionP->buffer[connectionP->buffersize] = '\0';
340
-                        gotData = TRUE;
341
-                    }
342
-                }
343
-            }
344
-        }
345
-    }
346
-    if (gotData)
347
-        return TRUE;
348
-    else
349
-        return FALSE;
350
-}
351
-
352
-
353
-            
354
-abyss_bool
355
-ConnWrite(TConn *      const connectionP,
356
-          const void * const buffer,
357
-          uint32_t     const size) {
358
-
359
-    abyss_bool failed;
360
-
361
-    SocketWrite(connectionP->socketP, buffer, size, &failed);
362
-
363
-    traceSocketWrite(connectionP, buffer, size, failed);
364
-
365
-    if (!failed)
366
-        connectionP->outbytes += size;
367
-
368
-    return !failed;
369
-}
370
-
371
-
372
-
373
-abyss_bool
374
-ConnWriteFromFile(TConn *  const connectionP,
375
-                  TFile *  const fileP,
376
-                  uint64_t const start,
377
-                  uint64_t const last,
378
-                  void *   const buffer,
379
-                  uint32_t const buffersize,
380
-                  uint32_t const rate) {
381
-/*----------------------------------------------------------------------------
382
-   Write the contents of the file stream *fileP, from offset 'start'
383
-   up through 'last', to the HTTP connection *connectionP.
384
-
385
-   Meter the reading so as not to read more than 'rate' bytes per second.
386
-
387
-   Use the 'bufferSize' bytes at 'buffer' as an internal buffer for this.
388
-    abyss_bool retval;
389
-    uint32_t waittime;
390
-    abyss_bool success;
391
-    uint32_t readChunkSize;
392
-
393
-    if (rate > 0) {
394
-        readChunkSize = MIN(buffersize, rate);  /* One second's worth */
395
-        waittime = (1000 * buffersize) / rate;
396
-    } else {
397
-        readChunkSize = buffersize;
398
-        waittime = 0;
399
-    }
400
-
401
-    success = FileSeek(fileP, start, SEEK_SET);
402
-    if (!success)
403
-        retval = FALSE;
404
-    else {
405
-        uint64_t const totalBytesToRead = last - start + 1;
406
-        uint64_t bytesread;
407
-
408
-        bytesread = 0;  /* initial value */
409
-
410
-        while (bytesread < totalBytesToRead) {
411
-            uint64_t const bytesLeft = totalBytesToRead - bytesread;
412
-            uint64_t const bytesToRead = MIN(readChunkSize, bytesLeft);
413
-
414
-            uint64_t bytesReadThisTime;
415
-
416
-            bytesReadThisTime = FileRead(fileP, buffer, bytesToRead);
417
-            bytesread += bytesReadThisTime;
418
-            
419
-            if (bytesReadThisTime > 0)
420
-                ConnWrite(connectionP, buffer, bytesReadThisTime);
421
-            else
422
-                break;
423
-            
424
-            if (waittime > 0)
425
-                xmlrpc_millisecond_sleep(waittime);
426
-        }
427
-        retval = (bytesread >= totalBytesToRead);
428
-    }
429
-    return retval;
430
-}
431
-
432
-
433
-
434
-static void
435
-processHeaderLine(char *       const start,
436
-                  const char * const headerStart,
437
-                  TConn *      const connectionP,                  
438
-                  time_t       const deadline,
439
-                  abyss_bool * const gotHeaderP,
440
-                  char **      const nextP,
441
-                  abyss_bool * const errorP) {
442
-/*----------------------------------------------------------------------------
443
-  If there's enough data in the buffer at *pP, process a line of HTTP
444
-  header.
445
-
446
-  It is part of a header that starts at 'headerStart' and has been
447
-  previously processed up to 'start'.  The data in the buffer is
448
-  terminated by a NUL.
449
-
450
-  WE MODIFY THE DATA.
451
-    abyss_bool gotHeader;
452
-    char * lfPos;
453
-    char * p;
454
-
455
-    p = start;
456
-
457
-    gotHeader = FALSE;  /* initial assumption */
458
-
459
-    lfPos = strchr(p, LF);
460
-    if (lfPos) {
461
-        if ((*p != LF) && (*p != CR)) {
462
-            /* We're looking at a non-empty line */
463
-            if (*(lfPos+1) == '\0') {
464
-                /* There's nothing in the buffer after the line, so we
465
-                   don't know if there's a continuation line coming.
466
-                   Must read more.
467
-                */
468
-                int const timeLeft = deadline - time(NULL);
469
-                
470
-                *errorP = !ConnRead(connectionP, timeLeft);
471
-            }
472
-            if (!*errorP) {
473
-                p = lfPos; /* Point to LF */
474
-                
475
-                /* If the next line starts with whitespace, it's a
476
-                   continuation line, so blank out the line
477
-                   delimiter (LF or CRLF) so as to join the next
478
-                   line with this one.
479
-                */
480
-                if ((*(p+1) == ' ') || (*(p+1) == '\t')) {
481
-                    if (p > headerStart && *(p-1) == CR)
482
-                        *(p-1) = ' ';
483
-                    *p++ = ' ';
484
-                } else
485
-                    gotHeader = TRUE;
486
-            }
487
-        } else {
488
-            /* We're looking at an empty line (i.e. what marks the
489
-               end of the header)
490
-            */
491
-            p = lfPos;  /* Point to LF */
492
-            gotHeader = TRUE;
493
-        }
494
-    }
495
-
496
-    if (gotHeader) {
497
-        /* 'p' points to the final LF */
498
-
499
-        /* Replace the LF or the CR in CRLF with NUL, so as to terminate
500
-           the string at 'headerStart' that is the full header.
501
-        */
502
-        if (p > headerStart && *(p-1) == CR)
503
-            *(p-1) = '\0';  /* NUL out CR in CRLF */
504
-        else
505
-            *p = '\0';  /* NUL out LF */
506
-
507
-        ++p;  /* Point to next line in buffer */
508
-    }
509
-    *gotHeaderP = gotHeader;
510
-    *nextP = p;
511
-}
512
-
513
-
514
-
515
-abyss_bool
516
-ConnReadHeader(TConn * const connectionP,
517
-               char ** const headerP) {
518
-/*----------------------------------------------------------------------------
519
-   Read an HTTP header on connection *connectionP.
520
-
521
-   An HTTP header is basically a line, except that if a line starts
522
-   with white space, it's a continuation of the previous line.  A line
523
-   is delimited by either LF or CRLF.
524
-
525
-   In the course of reading, we read at least one character past the
526
-   line delimiter at the end of the header; we may read much more.  We
527
-   leave everything after the header (and its line delimiter) in the
528
-   internal buffer, with the buffer pointer pointing to it.
529
-
530
-   We use stuff already in the internal buffer (perhaps left by a
531
-   previous call to this subroutine) before reading any more from from
532
-   the socket.
533
-
534
-   Return as *headerP the header value.  This is in the connection's
535
-   internal buffer.  This contains no line delimiters.
536
-    uint32_t const deadline = time(NULL) + connectionP->server->srvP->timeout;
537
-
538
-    abyss_bool retval;
539
-    char * p;
540
-    char * headerStart;
541
-    abyss_bool error;
542
-    abyss_bool gotHeader;
543
-
544
-    p = connectionP->buffer + connectionP->bufferpos;
545
-    headerStart = p;
546
-
547
-    gotHeader = FALSE;
548
-    error = FALSE;
549
-
550
-    while (!gotHeader && !error) {
551
-        int const timeLeft = deadline - time(NULL);
552
-
553
-        if (timeLeft <= 0)
554
-            error = TRUE;
555
-        else {
556
-            if (p >= connectionP->buffer + connectionP->buffersize)
557
-                /* Need more data from the socket to chew on */
558
-                error = !ConnRead(connectionP, timeLeft);
559
-
560
-            if (!error) {
561
-                assert(connectionP->buffer + connectionP->buffersize > p);
562
-                processHeaderLine(p, headerStart, connectionP, deadline,
563
-                                  &gotHeader, &p, &error);
564
-            }
565
-        }
566
-    }
567
-    if (gotHeader) {
568
-        /* We've consumed this part of the buffer (but be careful --
569
-           you can't reuse that part of the buffer because the string
570
-           we're returning is in it!
571
-        */
572
-        connectionP->bufferpos += p - headerStart;
573
-        *headerP = headerStart;
574
-        retval = TRUE;
575
-    } else
576
-        retval = FALSE;
577
-
578
-    return retval;
579
-}
580
-
581
-
582
-
583
-TServer *
584
-ConnServer(TConn * const connectionP) {
585
-    return connectionP->server;
586
-}
587
-
588
-
589
-
590
-/*******************************************************************************
591
-**
592
-** conn.c
593
-**
594
-** This file is part of the ABYSS Web server project.
595
-**
596
-** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
597
-** All rights reserved.
598
-**
599
-** Redistribution and use in source and binary forms, with or without
600
-** modification, are permitted provided that the following conditions
601
-** are met:
602
-** 1. Redistributions of source code must retain the above copyright
603
-**    notice, this list of conditions and the following disclaimer.
604
-** 2. Redistributions in binary form must reproduce the above copyright
605
-**    notice, this list of conditions and the following disclaimer in the
606
-**    documentation and/or other materials provided with the distribution.
607
-** 3. The name of the author may not be used to endorse or promote products
608
-**    derived from this software without specific prior written permission.
609
-** 
610
-** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
611
-** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
612
-** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613
-** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
614
-** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
615
-** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
616
-** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
617
-** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
618
-** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
619
-** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
620
-** SUCH DAMAGE.
621
-**
622
-******************************************************************************/
Browse code

fixup to the libxmlrpc pthread support problem - replace the compiled abyss server provided by the libxmlrpc with our own compiling: - import the source files for the abyss server (used by the libxmlrpc) in order to force compiling of fork support (and not pthread) - change makefile to compile these additional files for libxmlrpc ver > 1.0.0 ; also, in this case, the module will not link with the abyss libs provided by the libxmlrpc - if 0.9.10 version is detected, the imported sources will not be compiled and the libxmlrpc code will be used.

Closes bug 1835638.
Many thanks to Dan Pascu for the help in troubleshooting and fixing this nasty problem.


git-svn-id: https://openser.svn.sourceforge.net/svnroot/openser/trunk@3226 689a6050-402a-0410-94f2-e92a70836424

Bogdan-Andrei Iancu authored on 28/11/2007 19:50:36
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,629 @@
1
+/* Copyright information is at the end of the file. */
2
+
3
+#include <time.h>
4
+#include <string.h>
5
+#include <stdlib.h>
6
+#include <stdio.h>
7
+#include <ctype.h>
8
+#include <assert.h>
9
+
10
+#include "abyss_mallocvar.h"
11
+#include "abyss_xmlrpc_int.h"
12
+#include <xmlrpc-c/abyss.h>
13
+#include "abyss_socket.h"
14
+#include "abyss_server.h"
15
+#include "abyss_thread.h"
16
+
17
+#include "abyss_conn.h"
18
+
19
+/*********************************************************************
20
+** Conn
21
+*********************************************************************/
22
+
23
+static TThreadProc connJob;
24
+
25
+static void
26
+connJob(void * const userHandle) {
27
+/*----------------------------------------------------------------------------
28
+   This is the root function for a thread that processes a connection
29
+   (performs HTTP transactions).
30
+-----------------------------------------------------------------------------*/
31
+    TConn * const connectionP = userHandle;
32
+
33
+    (connectionP->job)(connectionP);
34
+
35
+    connectionP->finished = TRUE;
36
+        /* Note that if we are running in a forked process, setting
37
+           connectionP->finished has no effect, because it's just our own
38
+           copy of *connectionP.  In this case, Parent must update his own
39
+           copy based on a SIGCHLD signal that the OS will generate right
40
+           after we exit.
41
+        */
42
+
43
+    ThreadExit(0);
44
+}
45
+
46
+
47
+
48
+static void
49
+connDone(TConn * const connectionP) {
50
+
51
+    /* In the forked case, this is designed to run in the parent
52
+       process after the child has terminated.
53
+    */
54
+    connectionP->finished = TRUE;
55
+
56
+    if (connectionP->done)
57
+        connectionP->done(connectionP);
58
+}
59
+
60
+
61
+
62
+static TThreadDoneFn threadDone;
63
+
64
+static void
65
+threadDone(void * const userHandle) {
66
+
67
+    TConn * const connectionP = userHandle;
68
+    
69
+    connDone(connectionP);
70
+}
71
+
72
+
73
+
74
+static void
75
+makeThread(TConn *             const connectionP,
76
+           enum abyss_foreback const foregroundBackground,
77
+           abyss_bool          const useSigchld,
78
+           const char **       const errorP) {
79
+           
80
+    switch (foregroundBackground) {
81
+    case ABYSS_FOREGROUND:
82
+        connectionP->hasOwnThread = FALSE;
83
+        *errorP = NULL;
84
+        break;
85
+    case ABYSS_BACKGROUND: {
86
+        const char * error;
87
+        connectionP->hasOwnThread = TRUE;
88
+        ThreadCreate(&connectionP->threadP, connectionP,
89
+                     &connJob, &threadDone, useSigchld,
90
+                     &error);
91
+        if (error) {
92
+            xmlrpc_asprintf(errorP, "Unable to create thread to "
93
+                            "process connection.  %s", error);
94
+            xmlrpc_strfree(error);
95
+        } else
96
+            *errorP = NULL;
97
+    } break;
98
+    } /* switch */
99
+}
100
+
101
+    
102
+
103
+void
104
+ConnCreate(TConn **            const connectionPP,
105
+           TServer *           const serverP,
106
+           TSocket *           const connectedSocketP,
107
+           TThreadProc *       const job,
108
+           TThreadDoneFn *     const done,
109
+           enum abyss_foreback const foregroundBackground,
110
+           abyss_bool          const useSigchld,
111
+           const char **       const errorP) {
112
+/*----------------------------------------------------------------------------
113
+   Create an HTTP connection.
114
+
115
+   A connection carries one or more HTTP transactions (request/response).
116
+
117
+   'connectedSocketP' transports the requests and responses.
118
+
119
+   The connection handles those HTTP requests.
120
+
121
+   The connection handles the requests primarily by running the
122
+   function 'job' once.  Some connections can do that autonomously, as
123
+   soon as the connection is created.  Others don't until Caller
124
+   subsequently calls ConnProcess.  Some connections complete the
125
+   processing before ConnProcess return, while others may run the
126
+   connection asynchronously to the creator, in the background, via a
127
+   TThread thread.  'foregroundBackground' determines which.
128
+
129
+   'job' calls methods of the connection to get requests and send
130
+   responses.
131
+
132
+   Some time after the HTTP transactions are all done, 'done' gets
133
+   called in some context.
134
+-----------------------------------------------------------------------------*/
135
+    TConn * connectionP;
136
+
137
+    MALLOCVAR(connectionP);
138
+
139
+    if (connectionP == NULL)
140
+        xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection "
141
+                        "descriptor.");
142
+    else {
143
+        abyss_bool success;
144
+        uint16_t peerPortNumber;
145
+
146
+        connectionP->server     = serverP;
147
+        connectionP->socketP    = connectedSocketP;
148
+        connectionP->buffersize = 0;
149
+        connectionP->bufferpos  = 0;
150
+        connectionP->finished   = FALSE;
151
+        connectionP->job        = job;
152
+        connectionP->done       = done;
153
+        connectionP->inbytes    = 0;
154
+        connectionP->outbytes   = 0;
155
+        connectionP->trace      = getenv("ABYSS_TRACE_CONN");
156
+
157
+        SocketGetPeerName(connectedSocketP,
158
+                          &connectionP->peerip, &peerPortNumber, &success);
159
+
160
+        if (success)
161
+            makeThread(connectionP, foregroundBackground, useSigchld, errorP);
162
+        else
163
+            xmlrpc_asprintf(errorP, "Failed to get peer name from socket.");
164
+    }
165
+    *connectionPP = connectionP;
166
+}
167
+
168
+
169
+
170
+abyss_bool
171
+ConnProcess(TConn * const connectionP) {
172
+/*----------------------------------------------------------------------------
173
+   Drive the main processing of a connection -- run the connection's
174
+   "job" function, which should read HTTP requests from the connection
175
+   and send HTTP responses.
176
+
177
+   If we succeed, we guarantee the connection's "done" function will get
178
+   called some time after all processing is complete.  It might be before
179
+   we return or some time after.  If we fail, we guarantee the "done"
180
+   function will not be called.
181
+-----------------------------------------------------------------------------*/
182
+    abyss_bool retval;
183
+
184
+    if (connectionP->hasOwnThread) {
185
+        /* There's a background thread to handle this connection.  Set
186
+           it running.
187
+        */
188
+        retval = ThreadRun(connectionP->threadP);
189
+    } else {
190
+        /* No background thread.  We just handle it here while Caller waits. */
191
+        (connectionP->job)(connectionP);
192
+        connDone(connectionP);
193
+        retval = TRUE;
194
+    }
195
+    return retval;
196
+}
197
+
198
+
199
+
200
+void
201
+ConnWaitAndRelease(TConn * const connectionP) {
202
+    if (connectionP->hasOwnThread)
203
+        ThreadWaitAndRelease(connectionP->threadP);
204
+    
205
+    free(connectionP);
206
+}
207
+
208
+
209
+
210
+abyss_bool
211
+ConnKill(TConn * connectionP) {
212
+    connectionP->finished = TRUE;
213
+    return ThreadKill(connectionP->threadP);
214
+}
215
+
216
+
217
+
218
+void
219
+ConnReadInit(TConn * const connectionP) {
220
+    if (connectionP->buffersize>connectionP->bufferpos) {
221
+        connectionP->buffersize -= connectionP->bufferpos;
222
+        memmove(connectionP->buffer,
223
+                connectionP->buffer+connectionP->bufferpos,
224
+                connectionP->buffersize);
225
+        connectionP->bufferpos = 0;
226
+    } else
227
+        connectionP->buffersize=connectionP->bufferpos = 0;
228
+
229
+    connectionP->inbytes=connectionP->outbytes = 0;
230
+}
231
+
232
+
233
+
234
+static void
235
+traceBuffer(const char * const label,
236
+            const char * const buffer,
237
+            unsigned int const size) {
238
+
239
+    unsigned int nonPrintableCount;
240
+    unsigned int i;
241
+    
242
+    nonPrintableCount = 0;  /* Initial value */
243
+    
244
+    for (i = 0; i < size; ++i) {
245
+        if (!isprint(buffer[i]) && buffer[i] != '\n' && buffer[i] != '\r')
246
+            ++nonPrintableCount;
247
+    }
248
+    if (nonPrintableCount > 0)
249
+        fprintf(stderr, "%s contains %u nonprintable characters.\n", 
250
+                label, nonPrintableCount);
251
+    
252
+    fprintf(stderr, "%s:\n", label);
253
+    fprintf(stderr, "%.*s\n", (int)size, buffer);
254
+}
255
+
256
+
257
+
258
+static void
259
+traceSocketRead(TConn *      const connectionP,
260
+                unsigned int const size) {
261
+
262
+    if (connectionP->trace)
263
+        traceBuffer("READ FROM SOCKET:",
264
+                    connectionP->buffer + connectionP->buffersize, size);
265
+}
266
+
267
+
268
+
269
+static void
270
+traceSocketWrite(TConn *      const connectionP,
271
+                 const char * const buffer,
272
+                 unsigned int const size,
273
+                 abyss_bool   const failed) {
274
+
275
+    if (connectionP->trace) {
276
+        const char * const label =