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