| 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 |
| 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 | ||||
| 27 | static TThreadProc connJob; | |||
| 28 | ||||
| 29 | static void | |||
| 30 | connJob(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 | ||||
| 64 | static void | |||
| 65 | connDone(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 | ||||
| 78 | static TThreadDoneFn threadDone; | |||
| 79 | ||||
| 80 | static void | |||
| 81 | threadDone(void * const userHandle) { | |||
| 82 | ||||
| 83 | TConn * const connectionP = userHandle; | |||
| 84 | ||||
| 85 | connDone(connectionP); | |||
| 86 | } | |||
| 87 | ||||
| 88 | ||||
| 89 | ||||
| 90 | static void | |||
| 91 | makeThread(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 | ||||
| 121 | void | |||
| 122 | ConnCreate(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 | ||||
| 186 | bool | |||
| 187 | ConnProcess(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 | ||||
| 217 | void | |||
| 218 | ConnWaitAndRelease(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 | ||||
| 229 | bool | |||
| 230 | ConnKill(TConn * const connectionP) { | |||
| 231 | connectionP->finished = TRUE1; | |||
| 232 | return ThreadKill(connectionP->threadP); | |||
| 233 | } | |||
| 234 | ||||
| 235 | ||||
| 236 | ||||
| 237 | void | |||
| 238 | ConnReadInit(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 | ||||
| 256 | static void | |||
| 257 | traceReadTimeout(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 | ||||
| 267 | static size_t | |||
| 268 | nextLineSize(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 | ||||
| 293 | static void | |||
| 294 | traceBuffer(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 | ||||
| 322 | static void | |||
| 323 | traceBufferText(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 | ||||
| 332 | static void | |||
| 333 | traceChannelRead(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 | ||||
| 343 | static void | |||
| 344 | traceChannelWrite(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 | ||||
| 358 | static uint32_t | |||
| 359 | bufferSpace(TConn * const connectionP) { | |||
| 360 | ||||
| 361 | return BUFFER_SIZE4096 - connectionP->buffersize; | |||
| 362 | } | |||
| 363 | ||||
| 364 | ||||
| 365 | ||||
| 366 | static void | |||
| 367 | readFromChannel(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, | |||
| 381 | &bytesRead, &readError); | |||
| 382 | ||||
| 383 | if (readError) | |||
| 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 | ||||
| 400 | static void | |||
| 401 | dealWithReadTimeout(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 | ||||
| 419 | static void | |||
| 420 | dealWithReadEof(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 | ||||
| 436 | void | |||
| 437 | ConnRead(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) | |||
| ||||
| 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) | |||
| 476 | xmlrpc_asprintf(errorP, | |||
| 477 | "Wait for stuff to arrive from client failed."); | |||
| 478 | else { | |||
| 479 | bool eof; | |||
| 480 | if (readyForRead) { | |||
| 481 | readFromChannel(connectionP, &eof, errorP); | |||
| 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) | |||
| 491 | dealWithReadTimeout(timedOutP, !readyForRead, timeout, errorP); | |||
| 492 | if (!*errorP) | |||
| 493 | dealWithReadEof(eofP, eof, errorP); | |||
| ||||
| 494 | } | |||
| 495 | } | |||
| 496 | } | |||
| 497 | ||||
| 498 | ||||
| 499 | ||||
| 500 | bool | |||
| 501 | ConnWrite(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 | ||||
| 519 | bool | |||
| 520 | ConnWriteFromFile(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 | ||||
| 597 | TServer * | |||
| 598 | ConnServer(TConn * const connectionP) { | |||
| 599 | return connectionP->server; | |||
| 600 | } | |||
| 601 | ||||
| 602 | ||||
| 603 | ||||
| 604 | void | |||
| 605 | ConnFormatClientAddr(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 | ******************************************************************************/ |