Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/lib/abyss/src/conn.c
Location:line 493, column 17
Description:Function call argument is an uninitialized value

Annotated Source Code

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 "bool.h"
11#include "mallocvar.h"
12#include "xmlrpc-c/util_int.h"
13#include "xmlrpc-c/string_int.h"
14#include "xmlrpc-c/sleep_int.h"
15#include "xmlrpc-c/abyss.h"
16#include "channel.h"
17#include "server.h"
18#include "thread.h"
19#include "file.h"
20
21#include "conn.h"
22
23/*********************************************************************
24** Conn
25*********************************************************************/
26
27static TThreadProc connJob;
28
29static void
30connJob(void * const userHandle) {
31/*----------------------------------------------------------------------------
32 This is the root function for a thread that processes a connection
33 (performs HTTP transactions).
34
35 We never return. We ultimately exit the thread.
36-----------------------------------------------------------------------------*/
37 TConn * const connectionP = userHandle;
38
39 (connectionP->job)(connectionP);
40
41 connectionP->finished = TRUE1;
42 /* Note that if we are running in a forked process, setting
43 connectionP->finished has no effect, because it's just our own
44 copy of *connectionP. In this case, Parent must update his own
45 copy based on a SIGCHLD signal that the OS will generate right
46 after we exit.
47 */
48
49
50 /* Note that ThreadExit() runs a cleanup function, which in our
51 case is connDone().
52 */
53 ThreadExit(connectionP->threadP, 0);
54}
55
56
57
58/* This is the maximum amount of stack that 'connJob' itself uses --
59 does not count what user's connection job function uses.
60*/
61#define CONNJOB_STACK1024 1024
62
63
64static void
65connDone(TConn * const connectionP) {
66
67 /* In the forked case, this is designed to run in the parent
68 process after the child has terminated.
69 */
70 connectionP->finished = TRUE1;
71
72 if (connectionP->done)
73 connectionP->done(connectionP);
74}
75
76
77
78static TThreadDoneFn threadDone;
79
80static void
81threadDone(void * const userHandle) {
82
83 TConn * const connectionP = userHandle;
84
85 connDone(connectionP);
86}
87
88
89
90static void
91makeThread(TConn * const connectionP,
92 enum abyss_foreback const foregroundBackground,
93 bool const useSigchld,
94 size_t const jobStackSize,
95 const char ** const errorP) {
96
97 switch (foregroundBackground) {
98 case ABYSS_FOREGROUND:
99 connectionP->hasOwnThread = FALSE0;
100 *errorP = NULL((void*)0);
101 break;
102 case ABYSS_BACKGROUND: {
103 const char * error;
104 connectionP->hasOwnThread = TRUE1;
105 ThreadCreate(&connectionP->threadP, connectionP,
106 &connJob, &threadDone, useSigchld,
107 CONNJOB_STACK1024 + jobStackSize,
108 &error);
109 if (error) {
110 xmlrpc_asprintf(errorP, "Unable to create thread to "
111 "process connection. %s", error);
112 xmlrpc_strfree(error);
113 } else
114 *errorP = NULL((void*)0);
115 } break;
116 } /* switch */
117}
118
119
120
121void
122ConnCreate(TConn ** const connectionPP,
123 TServer * const serverP,
124 TChannel * const channelP,
125 void * const channelInfoP,
126 TThreadProc * const job,
127 size_t const jobStackSize,
128 TThreadDoneFn * const done,
129 enum abyss_foreback const foregroundBackground,
130 bool const useSigchld,
131 const char ** const errorP) {
132/*----------------------------------------------------------------------------
133 Create an HTTP connection.
134
135 A connection carries one or more HTTP transactions (request/response).
136
137 *channelP transports the requests and responses.
138
139 The connection handles those HTTP requests.
140
141 The connection handles the requests primarily by running the
142 function 'job' once. Some connections can do that autonomously, as
143 soon as the connection is created. Others don't until Caller
144 subsequently calls ConnProcess. Some connections complete the
145 processing before ConnProcess return, while others may run the
146 connection asynchronously to the creator, in the background, via a
147 TThread thread. 'foregroundBackground' determines which.
148
149 'job' calls methods of the connection to get requests and send
150 responses.
151
152 Some time after the HTTP transactions are all done, 'done' gets
153 called in some context.
154
155 'channelInfoP' == NULL means no channel info supplied.
156-----------------------------------------------------------------------------*/
157 TConn * connectionP;
158
159 MALLOCVAR(connectionP)connectionP = malloc(sizeof(*connectionP));
160
161 if (connectionP == NULL((void*)0))
162 xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection "
163 "descriptor.");
164 else {
165 connectionP->server = serverP;
166 connectionP->channelP = channelP;
167 connectionP->channelInfoP = channelInfoP;
168 connectionP->buffer.b[0] = '\0';
169 connectionP->buffersize = 0;
170 connectionP->bufferpos = 0;
171 connectionP->finished = FALSE0;
172 connectionP->job = job;
173 connectionP->done = done;
174 connectionP->inbytes = 0;
175 connectionP->outbytes = 0;
176 connectionP->trace = getenv("ABYSS_TRACE_CONN");
177
178 makeThread(connectionP, foregroundBackground, useSigchld,
179 jobStackSize, errorP);
180 }
181 *connectionPP = connectionP;
182}
183
184
185
186bool
187ConnProcess(TConn * const connectionP) {
188/*----------------------------------------------------------------------------
189 Drive the main processing of a connection -- run the connection's
190 "job" function, which should read HTTP requests from the connection
191 and send HTTP responses.
192
193 If we succeed, we guarantee the connection's "done" function will get
194 called some time after all processing is complete. It might be before
195 we return or some time after. If we fail, we guarantee the "done"
196 function will not be called.
197-----------------------------------------------------------------------------*/
198 bool retval;
199
200 if (connectionP->hasOwnThread) {
201 /* There's a background thread to handle this connection. Set
202 it running.
203 */
204 assert(connectionP->threadP)((connectionP->threadP) ? (void) (0) : __assert_fail ("connectionP->threadP"
, "../../../../libs/xmlrpc-c/lib/abyss/src/conn.c", 204, __PRETTY_FUNCTION__
))
;
205 retval = ThreadRun(connectionP->threadP);
206 } else {
207 /* No background thread. We just handle it here while Caller waits. */
208 (connectionP->job)(connectionP);
209 connDone(connectionP);
210 retval = TRUE1;
211 }
212 return retval;
213}
214
215
216
217void
218ConnWaitAndRelease(TConn * const connectionP) {
219
220 if (connectionP->hasOwnThread) {
221 assert(connectionP->threadP)((connectionP->threadP) ? (void) (0) : __assert_fail ("connectionP->threadP"
, "../../../../libs/xmlrpc-c/lib/abyss/src/conn.c", 221, __PRETTY_FUNCTION__
))
;
222 ThreadWaitAndRelease(connectionP->threadP);
223 }
224 free(connectionP);
225}
226
227
228
229bool
230ConnKill(TConn * const connectionP) {
231 connectionP->finished = TRUE1;
232 return ThreadKill(connectionP->threadP);
233}
234
235
236
237void
238ConnReadInit(TConn * const connectionP) {
239
240 if (connectionP->buffersize > connectionP->bufferpos) {
241 connectionP->buffersize -= connectionP->bufferpos;
242 memmove(connectionP->buffer.b,
243 connectionP->buffer.b + connectionP->bufferpos,
244 connectionP->buffersize);
245 connectionP->bufferpos = 0;
246 } else
247 connectionP->buffersize = connectionP->bufferpos = 0;
248
249 connectionP->buffer.b[connectionP->buffersize] = '\0';
250
251 connectionP->inbytes = connectionP->outbytes = 0;
252}
253
254
255
256static void
257traceReadTimeout(TConn * const connectionP,
258 uint32_t const timeout) {
259
260 if (connectionP->trace)
261 fprintf(stderrstderr, "TIMED OUT waiting over %u seconds "
262 "for data from client.\n", timeout);
263}
264
265
266
267static size_t
268nextLineSize(const char * const string,
269 size_t const startPos,
270 size_t const stringSize) {
271/*----------------------------------------------------------------------------
272 Return the length of the line that starts at offset 'startPos' in the
273 string 'string', which is 'stringSize' characters long.
274
275 'string' in not NUL-terminated.
276
277 A line begins at beginning of string or after a newline character and
278 runs through the next newline character or end of string. The line
279 includes the newline character at the end, if any.
280-----------------------------------------------------------------------------*/
281 size_t i;
282
283 for (i = startPos; i < stringSize && string[i] != '\n'; ++i);
284
285 if (i < stringSize)
286 ++i; /* Include the newline */
287
288 return i - startPos;
289}
290
291
292
293static void
294traceBuffer(const char * const label,
295 const unsigned char * const buffer,
296 unsigned int const size) {
297
298 const char * const buffer_t = (const char *)buffer;
299
300 size_t cursor; /* Index into buffer[] */
301
302 fprintf(stderrstderr, "%s:\n\n", label);
303
304 for (cursor = 0; cursor < size; ) {
305 /* Print one line of buffer */
306
307 size_t const lineSize = nextLineSize(buffer_t, cursor, size);
308 const char * const printableLine =
309 xmlrpc_makePrintable_lp(&buffer_t[cursor], lineSize);
310
311 fprintf(stderrstderr, "%s\n", printableLine);
312
313 cursor += lineSize;
314
315 xmlrpc_strfree(printableLine);
316 }
317 fprintf(stderrstderr, "\n");
318}
319
320
321
322static void
323traceBufferText(const char * const label,
324 const char * const buffer,
325 unsigned int const size) {
326
327 traceBuffer(label, (const unsigned char *)buffer, size);
328}
329
330
331
332static void
333traceChannelRead(TConn * const connectionP,
334 unsigned int const size) {
335
336 if (connectionP->trace)
337 traceBuffer("READ FROM CHANNEL",
338 connectionP->buffer.b + connectionP->buffersize, size);
339}
340
341
342
343static void
344traceChannelWrite(TConn * const connectionP,
345 const char * const buffer,
346 unsigned int const size,
347 bool const failed) {
348
349 if (connectionP->trace) {
350 const char * const label =
351 failed ? "FAILED TO WRITE TO CHANNEL" : "WROTE TO CHANNEL";
352 traceBufferText(label, buffer, size);
353 }
354}
355
356
357
358static uint32_t
359bufferSpace(TConn * const connectionP) {
360
361 return BUFFER_SIZE4096 - connectionP->buffersize;
362}
363
364
365
366static void
367readFromChannel(TConn * const connectionP,
368 bool * const eofP,
369 const char ** const errorP) {
370/*----------------------------------------------------------------------------
371 Read some data from the channel of Connection *connectionP.
372
373 Iff there is none available to read, return *eofP == true.
374-----------------------------------------------------------------------------*/
375 uint32_t bytesRead;
376 bool readError;
377
378 ChannelRead(connectionP->channelP,
379 connectionP->buffer.b + connectionP->buffersize,
380 bufferSpace(connectionP) - 1,
8
Calling 'bufferSpace'
9
Returning from 'bufferSpace'
381 &bytesRead, &readError);
382
383 if (readError)
10
Assuming 'readError' is not equal to 0
11
Taking true branch
384 xmlrpc_asprintf(errorP, "Error reading from channel");
385 else {
386 *errorP = NULL((void*)0);
387 if (bytesRead > 0) {
388 *eofP = FALSE0;
389 traceChannelRead(connectionP, bytesRead);
390 connectionP->inbytes += bytesRead;
391 connectionP->buffersize += bytesRead;
392 connectionP->buffer.t[connectionP->buffersize] = '\0';
393 } else
394 *eofP = TRUE1;
395 }
396}
397
398
399
400static void
401dealWithReadTimeout(bool * const timedOutP,
402 bool const timedOut,
403 uint32_t const timeout,
404 const char ** const errorP) {
405
406 if (timedOutP)
407 *timedOutP = timedOut;
408 else {
409 if (timedOut)
410 xmlrpc_asprintf(errorP, "Read from Abyss client "
411 "connection timed out after %u seconds "
412 "or was interrupted",
413 timeout);
414 }
415}
416
417
418
419static void
420dealWithReadEof(bool * const eofP,
421 bool const eof,
422 const char ** const errorP) {
423
424 if (eofP)
425 *eofP = eof;
426 else {
427 if (eof)
428 xmlrpc_asprintf(errorP, "Read from Abyss client "
429 "connection failed because client closed the "
430 "connection");
431 }
432}
433
434
435
436void
437ConnRead(TConn * const connectionP,
438 uint32_t const timeout,
439 bool * const eofP,
440 bool * const timedOutP,
441 const char ** const errorP) {
442/*----------------------------------------------------------------------------
443 Read some stuff on connection *connectionP from the channel. Read it into
444 the connection's buffer.
445
446 Don't wait more than 'timeout' seconds for data to arrive. If no data has
447 arrived by then and 'timedOutP' is null, fail. If 'timedOut' is non-null,
448 return as *timedOutP whether 'timeout' seconds passed without any data
449 arriving.
450
451 Also, stop waiting upon any interruption and treat it the same as a
452 timeout. An interruption is either a signal received (and caught) at
453 an appropriate time or a ChannelInterrupt() call before or during the
454 wait.
455
456 If 'eofP' is non-null, return *eofP == true, without reading anything, iff
457 there will no more data forthcoming on the connection because client has
458 closed the connection. If 'eofP' is null, fail in that case.
459-----------------------------------------------------------------------------*/
460 uint32_t const timeoutMs = timeout * 1000;
461
462 if (timeoutMs < timeout)
1
Taking false branch
463 /* Arithmetic overflow */
464 xmlrpc_asprintf(errorP, "Timeout value is too large");
465 else {
466 bool const waitForRead = TRUE1;
467 bool const waitForWrite = FALSE0;
468
469 bool readyForRead;
470 bool failed;
471
472 ChannelWait(connectionP->channelP, waitForRead, waitForWrite,
473 timeoutMs, &readyForRead, NULL((void*)0), &failed);
474
475 if (failed)
2
Assuming 'failed' is 0
3
Taking false branch
476 xmlrpc_asprintf(errorP,
477 "Wait for stuff to arrive from client failed.");
478 else {
479 bool eof;
4
'eof' declared without an initial value
480 if (readyForRead) {
5
Assuming 'readyForRead' is not equal to 0
6
Taking true branch
481 readFromChannel(connectionP, &eof, errorP);
7
Calling 'readFromChannel'
12
Returning from 'readFromChannel'
482 } else {
483 /* Wait was interrupted, either by our requested timeout,
484 a (caught) signal, or a ChannelInterrupt().
485 */
486 traceReadTimeout(connectionP, timeout);
487 *errorP = NULL((void*)0);
488 eof = FALSE0;
489 }
490 if (!*errorP)
13
Taking true branch
491 dealWithReadTimeout(timedOutP, !readyForRead, timeout, errorP);
492 if (!*errorP)
14
Taking true branch
493 dealWithReadEof(eofP, eof, errorP);
15
Function call argument is an uninitialized value
494 }
495 }
496}
497
498
499
500bool
501ConnWrite(TConn * const connectionP,
502 const void * const buffer,
503 uint32_t const size) {
504
505 bool failed;
506
507 ChannelWrite(connectionP->channelP, buffer, size, &failed);
508
509 traceChannelWrite(connectionP, buffer, size, failed);
510
511 if (!failed)
512 connectionP->outbytes += size;
513
514 return !failed;
515}
516
517
518
519bool
520ConnWriteFromFile(TConn * const connectionP,
521 const TFile * const fileP,
522 uint64_t const start,
523 uint64_t const last,
524 void * const buffer,
525 uint32_t const buffersize,
526 uint32_t const rate) {
527/*----------------------------------------------------------------------------
528 Write the contents of the file stream *fileP, from offset 'start'
529 up through 'last', to the HTTP connection *connectionP.
530
531 Meter the reading so as not to read more than 'rate' bytes per second.
532
533 Use the 'bufferSize' bytes at 'buffer' as an internal buffer for this.
534-----------------------------------------------------------------------------*/
535 bool retval;
536 uint32_t waittime;
537 bool success;
538 uint32_t readChunkSize;
539 uint32_t ChunkSize = 4096 * 2; /* read buffer size */
540
541 if (rate > 0) {
542 readChunkSize = MIN(buffersize, rate)((buffersize) < (rate) ? (buffersize) : (rate)); /* One second's worth */
543 waittime = (1000 * buffersize) / rate;
544 } else {
545 readChunkSize = ChunkSize;
546 waittime = 0;
547 }
548
549 success = FileSeek(fileP, start, SEEK_SET0);
550 if (!success)
551 retval = FALSE0;
552 else {
553 uint64_t const totalBytesToRead = last - start + 1;
554 uint64_t bytesread = 0;
555
556 int32_t bytesReadThisTime = 0;
557 char * chunk = (char *) buffer; /* the beginning */
558 do {
559
560 if ((bytesReadThisTime = FileRead(fileP, chunk, readChunkSize)) <= 0 )
561 break;
562
563 bytesread += bytesReadThisTime;
564 chunk += bytesReadThisTime;
565
566 /* fix bug in ms ie as it doesn't render text/plain properly */
567 /* if CRLFs are split between reassembled tcp packets, */
568 /* ie "might" undeterministically render extra empty lines */
569 /* if it ends in CR or LF, read an extra chunk until the buffer is full */
570 /* or end of file is reached. You may still have bad luck, complaints go to MS) */
571
572/* if (bytesReadThisTime == readChunkSize && chunk - (char *) buffer + readChunkSize < buffersize) {
573 * char * end = chunk - 1;
574 * if (*end == CR || *end == LF) {
575 * continue;
576 * }
577 * }
578 */
579 if (!bytesReadThisTime || !ConnWrite(connectionP, buffer, chunk - (char *) buffer)) {
580 break;
581 }
582
583 chunk = (char *) buffer; /* a new beginning */
584
585 if (waittime > 0)
586 xmlrpc_millisecond_sleep(waittime);
587
588 } while (bytesReadThisTime == readChunkSize);
589
590 retval = (bytesread >= totalBytesToRead);
591 }
592 return retval;
593}
594
595
596
597TServer *
598ConnServer(TConn * const connectionP) {
599 return connectionP->server;
600}
601
602
603
604void
605ConnFormatClientAddr(TConn * const connectionP,
606 const char ** const clientAddrPP) {
607
608 ChannelFormatPeerInfo(connectionP->channelP, clientAddrPP);
609}
610
611
612
613/*******************************************************************************
614**
615** conn.c
616**
617** This file is part of the ABYSS Web server project.
618**
619** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
620** All rights reserved.
621**
622** Redistribution and use in source and binary forms, with or without
623** modification, are permitted provided that the following conditions
624** are met:
625** 1. Redistributions of source code must retain the above copyright
626** notice, this list of conditions and the following disclaimer.
627** 2. Redistributions in binary form must reproduce the above copyright
628** notice, this list of conditions and the following disclaimer in the
629** documentation and/or other materials provided with the distribution.
630** 3. The name of the author may not be used to endorse or promote products
631** derived from this software without specific prior written permission.
632**
633** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
634** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
635** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
636** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
637** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
638** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
639** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
640** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
641** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
642** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
643** SUCH DAMAGE.
644**
645******************************************************************************/