Annotation of libwww/Library/src/HTSocket.c, revision 2.2

2.1       frystyk     1: /*                                                                  HTSocket.c
                      2: **     MANAGES READ AND WRITE TO AND FROM THE NETWORK
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
                      6: **
                      7: **
                      8: ** HISTORY:
                      9: **     6 June 95  HFN  Spawned off from HTFormat
                     10: */
                     11: 
                     12: /* Library Include files */
                     13: #include "tcp.h"
                     14: #include "HTUtils.h"
                     15: #include "HTString.h"
2.2     ! frystyk    16: #include "HTAccess.h"
2.1       frystyk    17: #include "HTTCP.h"
                     18: #include "HTStream.h"
                     19: #include "HTFormat.h"
                     20: #include "HTThread.h"
                     21: #include "HTError.h"
                     22: #include "HTSocket.h"                                   /* Implemented here */
                     23: 
2.2     ! frystyk    24: struct _HTInputSocket {
        !            25:     char       input_buffer[INPUT_BUFFER_SIZE];
        !            26:     char *     input_pointer;
        !            27:     char *     input_limit;
        !            28:     SOCKFD     input_file_number;
        !            29: };
        !            30: 
2.1       frystyk    31: struct _HTStream {
                     32:     CONST HTStreamClass *      isa;
                     33: };
                     34: 
                     35: /* ------------------------------------------------------------------------- */
                     36: /*                             SOCKET INPUT BUFFERING                       */
                     37: /* ------------------------------------------------------------------------- */
                     38: /*                     
                     39: **     This code is used because one cannot in general open a
                     40: **     file descriptor for a socket.
                     41: **
                     42: **     The input file is read using the macro which can read from
                     43: **     a socket or a file, but this should not be used for files
                     44: **     as fopen() etc is more portable of course.
                     45: **
                     46: **     The input buffer size, if large will give greater efficiency and
                     47: **     release the server faster, and if small will save space on PCs etc.
                     48: */
                     49: 
                     50: 
                     51: /*     Set up the buffering
                     52: **
                     53: **     These routines are public because they are in fact needed by
                     54: **     many parsers, and on PCs and Macs we should not duplicate
                     55: **     the static buffer area.
                     56: */
                     57: PUBLIC HTInputSocket * HTInputSocket_new ARGS1 (SOCKFD, file_number)
                     58: {
                     59:     HTInputSocket *isoc = (HTInputSocket *)calloc(1, sizeof(*isoc));
                     60:     if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
                     61:     isoc->input_file_number = file_number;
                     62:     isoc->input_pointer = isoc->input_limit = isoc->input_buffer;
                     63:     return isoc;
                     64: }
                     65: 
                     66: /* This should return HT_INTERRUPTED if interrupted BUT the connection
                     67:    MUST not be closed */ 
                     68: PUBLIC int HTInputSocket_getCharacter ARGS1(HTInputSocket*, isoc)
                     69: {
                     70:     int ch;
                     71:     do {
                     72:        if (isoc->input_pointer >= isoc->input_limit) {
                     73:            int status = NETREAD(isoc->input_file_number,
                     74:                                 isoc->input_buffer, INPUT_BUFFER_SIZE);
                     75:            if (status <= 0) {
                     76:                if (status == 0)
                     77:                    return EOF;
                     78:                if (status == HT_INTERRUPTED) {
                     79:                    if (TRACE)
                     80:                        fprintf(TDEST, "Get Char.... Interrupted in HTInputSocket_getCharacter\n");
                     81:                    return HT_INTERRUPTED;
                     82:                }
                     83:                if (PROT_TRACE)
                     84:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
                     85:                return EOF;     /* -1 is returned by UCX at end of HTTP link */
                     86:            }
                     87:            isoc->input_pointer = isoc->input_buffer;
                     88:            isoc->input_limit = isoc->input_buffer + status;
                     89:        }
                     90:        ch = (unsigned char) *isoc->input_pointer++;
                     91:     } while (ch == 13);                             /* Ignore ASCII carriage return */
                     92:     
                     93:     return FROMASCII(ch);
                     94: }
                     95: 
                     96: PUBLIC void HTInputSocket_free ARGS1(HTInputSocket *, me)
                     97: {
                     98:     if (me) free(me);
                     99: }
                    100: 
                    101: 
                    102: PUBLIC char * HTInputSocket_getBlock ARGS2(HTInputSocket*,     isoc,
                    103:                                           int *,               len)
                    104: {
                    105:     if (isoc->input_pointer >= isoc->input_limit) {
                    106:        int status = NETREAD(isoc->input_file_number,
                    107:                             isoc->input_buffer,
                    108:                             ((*len < INPUT_BUFFER_SIZE) ?
                    109:                              *len : INPUT_BUFFER_SIZE));
                    110:        if (status <= 0) {
                    111:            isoc->input_limit = isoc->input_buffer;
                    112:            if (status < 0) {
                    113:                if (PROT_TRACE)
                    114:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
                    115:            }
                    116:            *len = 0;
                    117:            return NULL;
                    118:        }
                    119:        else {
                    120:            *len = status;
                    121:            return isoc->input_buffer;
                    122:        }
                    123:     }
                    124:     else {
                    125:        char * ret = isoc->input_pointer;
                    126:        *len = isoc->input_limit - isoc->input_pointer;
                    127:        isoc->input_pointer = isoc->input_limit;
                    128:        return ret;
                    129:     }
                    130: }
                    131: 
                    132: 
                    133: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
                    134: {
                    135:     if (isoc) {
                    136:        int status;
                    137: 
                    138:        isoc->input_pointer = isoc->input_buffer;
                    139:        status = NETREAD(isoc->input_file_number,
                    140:                         isoc->input_buffer,
                    141:                         INPUT_BUFFER_SIZE);
                    142:        if (status <= 0) {
                    143:            isoc->input_limit = isoc->input_buffer;
                    144:            if (status < 0) {
                    145:                if (PROT_TRACE)
                    146:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
                    147:            }
                    148:        }
                    149:        else 
                    150:            isoc->input_limit = isoc->input_buffer + status;
                    151:        return status;
                    152:     }
                    153:     return -1;
                    154: }
                    155: 
                    156: 
                    157: PRIVATE void ascii_cat ARGS3(char **,  linep,
                    158:                             char *,    start,
                    159:                             char *,    end)
                    160: {
                    161:     if (linep && start && end && start <= end) {
                    162:        char *ptr;
                    163: 
                    164:        if (*linep) {
                    165:            int len = strlen(*linep);
                    166:            *linep = (char*)realloc(*linep, len + end-start + 1);
                    167:            ptr = *linep + len;
                    168:        }
                    169:        else {
                    170:            ptr = *linep = (char*)malloc(end-start + 1);
                    171:        }
                    172: 
                    173:        while (start < end) {
                    174:            *ptr = FROMASCII(*start);
                    175:            ptr++;
                    176:            start++;
                    177:        }
                    178:        *ptr = 0;
                    179:     }
                    180: }
                    181: 
                    182: 
                    183: PRIVATE char * get_some_line ARGS2(HTInputSocket *,    isoc,
                    184:                                   BOOL,                unfold)
                    185: {
                    186:     if (!isoc)
                    187:        return NULL;
                    188:     else {
                    189:        BOOL check_unfold = NO;
                    190:        int prev_cr = 0;
                    191:        char *start = isoc->input_pointer;
                    192:        char *cur = isoc->input_pointer;
                    193:        char * line = NULL;
                    194: 
                    195:        for(;;) {
                    196:            /*
                    197:            ** Get more if needed to complete line
                    198:            */
                    199:            if (cur >= isoc->input_limit) { /* Need more data */
                    200:                ascii_cat(&line, start, cur);
                    201:                if (fill_in_buffer(isoc) <= 0)
                    202:                    return line;
                    203:                start = cur = isoc->input_pointer;
                    204:            } /* if need more data */
                    205: 
                    206:            /*
                    207:            ** Find a line feed if there is one
                    208:            */
                    209:            for(; cur < isoc->input_limit; cur++) {
                    210:                char c = FROMASCII(*cur);
                    211:                if (!c) {
                    212:                    if (line) free(line);       /* Leak fixed AL 6 Feb 94 */
                    213:                    return NULL;        /* Panic! read a 0! */
                    214:                }
                    215:                if (check_unfold  &&  c != ' '  &&  c != '\t') {
                    216:                    return line;  /* Note: didn't update isoc->input_pointer */
                    217:                }
                    218:                else {
                    219:                    check_unfold = NO;
                    220:                }
                    221: 
                    222:                if (c=='\r') {
                    223:                    prev_cr = 1;
                    224:                }
                    225:                else {
                    226:                    if (c=='\n') {              /* Found a line feed */
                    227:                        ascii_cat(&line, start, cur-prev_cr);
                    228:                        start = isoc->input_pointer = cur+1;
                    229: 
                    230:                        if (line && (int) strlen(line) > 0 && unfold) {
                    231:                            check_unfold = YES;
                    232:                        }
                    233:                        else {
                    234:                            return line;
                    235:                        }
                    236:                    } /* if NL */
                    237:                    /* else just a regular character */
                    238:                    prev_cr = 0;
                    239:                } /* if not CR */
                    240:            } /* while characters in buffer remain */
                    241:        } /* until line read or end-of-file */
                    242:     } /* valid parameters to function */
                    243: }
                    244: 
                    245: /* The returned string must be freed by the caller */
                    246: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
                    247: {
                    248:     return get_some_line(isoc, NO);
                    249: }
                    250: 
                    251: /* The returned string must be freed by the caller */
                    252: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
                    253: {
                    254:     return get_some_line(isoc, YES);
                    255: }
                    256: 
                    257: 
                    258: /*     Push data from a socket down a stream
                    259: **     -------------------------------------
                    260: **
                    261: **   This routine is responsible for creating and PRESENTING any
                    262: **   graphic (or other) objects described by the file.
                    263: **
                    264: **   The file number given is assumed to be a TELNET stream ie containing
                    265: **   CRLF at the end of lines which need to be stripped to LF for unix
                    266: **   when the format is textual.
                    267: **
                    268: **   RETURNS the number of bytes transferred.
                    269: **
                    270: */
                    271: PUBLIC int HTCopy ARGS2(
                    272:        SOCKFD,                 file_number,
                    273:        HTStream*,              sink)
                    274: {
                    275:     HTStreamClass targetClass;    
                    276:     HTInputSocket * isoc;
                    277:     int cnt = 0;
                    278: 
                    279: /*     Push the data down the stream
                    280: **
                    281: */
                    282:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    283:     isoc = HTInputSocket_new(file_number);
                    284:     
                    285:     /* Push binary from socket down sink
                    286:     **
                    287:     **         This operation could be put into a main event loop
                    288:     */
                    289:     for(;;) {
                    290:        int status = NETREAD(
                    291:                file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
                    292:        if (status <= 0) {
                    293:            if (status == 0) break;
                    294:            if (TRACE) fprintf(TDEST,
                    295:                "Socket Copy. Read error, read returns %d with errno=%d\n",
                    296:                status, socerrno);
                    297:            break;
                    298:        }
                    299: 
                    300: #ifdef NOT_ASCII
                    301:        {
                    302:            char * p;
                    303:            for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
                    304:                *p = FROMASCII(*p);
                    305:            }
                    306:        }
                    307: #endif
                    308: 
                    309:        (*targetClass.put_block)(sink, isoc->input_buffer, status);
                    310:        cnt += status;
                    311:     } /* next bufferload */
                    312: 
                    313:     HTInputSocket_free(isoc);
                    314: 
                    315:     return cnt;
                    316: }
                    317: 
                    318: 
                    319: 
                    320: /*     Push data from a file pointer down a stream
                    321: **     -------------------------------------
                    322: **
                    323: **   This routine is responsible for creating and PRESENTING any
                    324: **   graphic (or other) objects described by the file.
                    325: **
                    326: **
                    327: */
                    328: PUBLIC void HTFileCopy ARGS2(
                    329:        FILE *,                 fp,
                    330:        HTStream*,              sink)
                    331: {
                    332:     HTStreamClass targetClass;    
                    333:     char input_buffer[INPUT_BUFFER_SIZE];
                    334:     
                    335: /*     Push the data down the stream
                    336: **
                    337: */
                    338:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    339:     
                    340:     /* Push binary from socket down sink
                    341:     */
                    342:     for(;;) {
                    343:        int status = fread(
                    344:               input_buffer, 1, INPUT_BUFFER_SIZE, fp);
                    345:        if (status == 0) { /* EOF or error */
                    346:            if (ferror(fp) == 0) break;
                    347:            if (TRACE) fprintf(TDEST,
                    348:                "File Copy... Read error, read returns %d\n", ferror(fp));
                    349:            break;
                    350:        }
                    351:        (*targetClass.put_block)(sink, input_buffer, status);
                    352:     } /* next bufferload */    
                    353: }
                    354: 
                    355: 
                    356: 
                    357: 
                    358: /*     Push data from a socket down a stream STRIPPING CR
                    359: **     --------------------------------------------------
                    360: **
                    361: **   This routine is responsible for creating and PRESENTING any
                    362: **   graphic (or other) objects described by the socket.
                    363: **
                    364: **   The file number given is assumed to be a TELNET stream ie containing
                    365: **   CRLF at the end of lines which need to be stripped to LF for unix
                    366: **   when the format is textual.
                    367: **     
                    368: **     Character handling is now of type int, Henrik, May 09-94
                    369: */
                    370: PUBLIC void HTCopyNoCR ARGS2(
                    371:        SOCKFD,                 file_number,
                    372:        HTStream*,              sink)
                    373: {
                    374:     HTStreamClass targetClass;
                    375:     HTInputSocket * isoc;   
                    376:     int ch;
                    377:     
                    378: /*     Push the data, ignoring CRLF, down the stream
                    379: **
                    380: */
                    381:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    382: 
                    383: /*     Push text from telnet socket down sink
                    384: **
                    385: **     @@@@@ To push strings could be faster? (especially is we
                    386: **     cheat and don't ignore CR! :-}
                    387: */  
                    388:     isoc = HTInputSocket_new(file_number);
                    389:     while ((ch = HTInputSocket_getCharacter(isoc)) >= 0)
                    390:        (*targetClass.put_character)(sink, ch);
                    391:     HTInputSocket_free(isoc);
                    392: }
                    393: 
                    394: 
                    395: /*     Parse a socket given format and file number
                    396: **
                    397: **   This routine is responsible for creating and PRESENTING any
                    398: **   graphic (or other) objects described by the file.
                    399: **
                    400: **   The file number given is assumed to be a TELNET stream ie containing
                    401: **   CRLF at the end of lines which need to be stripped to LF for unix
                    402: **   when the format is textual.
                    403: **
                    404: **     Returns <0 on error, HT_LOADED on success.
                    405: */
                    406: 
                    407: /* The parameter to this function and HTParsefile should be HTRequest */
                    408: 
                    409: PUBLIC int HTParseSocket ARGS3(
                    410:        HTFormat,               rep_in,
                    411:        SOCKFD,                 file_number,
                    412:        HTRequest *,            request)
                    413: {
                    414:     HTStream * stream;
                    415:     HTStreamClass targetClass;    
                    416: 
                    417:     if (request->error_stack) {
                    418:        if (TRACE) fprintf(TDEST, "ParseSocket. Called whith non-empty error stack, so I return right away!\n");
                    419:        return -1;
                    420:     }
                    421: 
                    422:     /* Set up stream stack */
                    423:     if ((stream = HTStreamStack(rep_in, request->output_format,
                    424:                                request->output_stream,
                    425:                                request, YES)) == NULL)
                    426:        return -1;
                    427:     
                    428: /*     Push the data, ignoring CRLF if necessary, down the stream
                    429: **
                    430: **
                    431: **   @@  Bug:  This decision ought to be made based on "encoding"
                    432: **   rather than on format.  @@@  When we handle encoding.
                    433: **   The current method smells anyway.
                    434: */
                    435:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
                    436:     if (rep_in == WWW_BINARY || rep_in == WWW_UNKNOWN
                    437:        || (HTAnchor_encoding(request->anchor) != HTAtom_for("8bit") &&
                    438:            HTAnchor_encoding(request->anchor) != HTAtom_for("7bit"))
                    439:         || strstr(HTAtom_name(rep_in), "image/")
                    440:        || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
                    441:        HTCopy(file_number, stream);
                    442:     } else
                    443:         HTCopyNoCR(file_number, stream);
                    444:     (*targetClass._free)(stream);
                    445:     
                    446:     return HT_LOADED;
                    447: }
                    448: 
                    449: 
                    450: 
                    451: /*     Parse a file given format and file pointer
                    452: **
                    453: **   This routine is responsible for creating and PRESENTING any
                    454: **   graphic (or other) objects described by the file.
                    455: **
                    456: **   The file number given is assumed to be a TELNET stream ie containing
                    457: **   CRLF at the end of lines which need to be stripped to \n for unix
                    458: **   when the format is textual.
                    459: **
                    460: */
2.2     ! frystyk   461: PRIVATE int HTParseFile ARGS3(
2.1       frystyk   462:        HTFormat,               rep_in,
                    463:        FILE *,                 fp,
                    464:        HTRequest *,            request)
                    465: {
                    466:     HTStream * stream;
                    467:     HTStreamClass targetClass;    
                    468: 
                    469:     if (request->error_stack) {
                    470:        if (TRACE) fprintf(TDEST, "ParseFile... Called whith non-empty error stack, so I return right away!\n");
                    471:        return -1;
                    472:     }
                    473: 
                    474:     /* Set up stream stack */
                    475:     if ((stream = HTStreamStack(rep_in, request->output_format,
                    476:                                request->output_stream, request, YES)) == NULL)
                    477:        return -1;
                    478:     
                    479: /*     Push the data down the stream
                    480: **
                    481: **
                    482: **   @@  Bug:  This decision ought to be made based on "encoding"
                    483: **   rather than on content-type.  @@@  When we handle encoding.
                    484: **   The current method smells anyway.
                    485: */
                    486:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
                    487:     HTFileCopy(fp, stream);
                    488:     (*targetClass._free)(stream);
                    489:     
                    490:     return HT_LOADED;
                    491: }
                    492: 
                    493: 
                    494: /* ------------------------------------------------------------------------- */
                    495: /*                     MULTI THREADED IMPLEMENTATIONS                       */
                    496: /* ------------------------------------------------------------------------- */
                    497: 
                    498: /*     Push data from a socket down a stream
                    499: **     -------------------------------------
                    500: **
                    501: **   This routine is responsible for creating and PRESENTING any
                    502: **   graphic (or other) objects described by the file. As this function
                    503: **   max reads a chunk of data on size INPUT_BUFFER_SIZE, it can be used
                    504: **   with both blocking or non-blocking sockets. It will always return to
                    505: **   the event loop, however if we are using blocking I/O then we get a full
                    506: **   buffer read, otherwise we get what's available.
                    507: **
                    508: ** Returns      HT_LOADED      if finished reading
                    509: **             HT_ERROR        if error,
                    510: **             HT_INTERRUPTED  if interrupted
                    511: **                     HT_WOULD_BLOCK  if read would block
                    512: */
                    513: PUBLIC int HTSocketRead ARGS2(HTRequest *, request, HTStream *, target)
                    514: {
                    515:     HTInputSocket *isoc = request->net_info->isoc;
                    516:     int b_read = isoc->input_limit-isoc->input_buffer;
                    517:     int status;
                    518:     if (!isoc || isoc->input_file_number==INVSOC) {
                    519:        if (PROT_TRACE) fprintf(TDEST, "Read Socket. Bad argument\n");
                    520:        return HT_ERROR;
                    521:     }
                    522: 
                    523:     if (HTThreadIntr(isoc->input_file_number))               /* Interrupted */
                    524:        return HT_INTERRUPTED;
                    525: #if 0
                    526:     while(1) {
                    527: #endif
                    528:        /* Read from socket if we got rid of all the data previously read */
                    529:        if (isoc->input_pointer >= isoc->input_limit) {
                    530:            if ((b_read = NETREAD(isoc->input_file_number, isoc->input_buffer,
                    531:                                  INPUT_BUFFER_SIZE)) < 0) {
                    532: #ifdef EAGAIN
                    533:                if (socerrno==EAGAIN || socerrno==EWOULDBLOCK) /* POSIX, SVR4*/
                    534: #else
                    535:                if (socerrno==EWOULDBLOCK)                            /* BSD */
                    536: #endif
                    537:                {
                    538:                    if (PROT_TRACE)
                    539:                        fprintf(TDEST, "Read Socket. WOULD BLOCK soc %d\n",
                    540:                                isoc->input_file_number);
                    541:                    HTThreadState(isoc->input_file_number, THD_SET_READ);
                    542:                    return HT_WOULD_BLOCK;
                    543:                } else {        /* We have a real error */
                    544:                    if (PROT_TRACE)
                    545:                        fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
                    546:                    return HT_ERROR;
                    547:                }
                    548:            } else if (!b_read) {
                    549:                HTThreadState(isoc->input_file_number, THD_CLR_READ);
                    550:                return HT_LOADED;
                    551:            }
                    552: 
                    553:            /* Remember how much we have read from the input socket */
                    554:            isoc->input_pointer = isoc->input_buffer;
                    555:            isoc->input_limit = isoc->input_buffer + b_read;
                    556: 
                    557: #ifdef NOT_ASCII
                    558:            {
                    559:                char *p = isoc->input_buffer;
                    560:                while (p < isoc->input_limit) {
                    561:                    *p = FROMASCII(*p);
                    562:                    p++;
                    563:                }
                    564:            }
                    565: #endif
                    566:            if (PROT_TRACE)
                    567:                fprintf(TDEST, "Read Socket. %d bytes read from socket %d\n",
                    568:                        b_read, isoc->input_file_number);
                    569:        }
                    570:        
                    571:        /* Now push the data down the stream */
                    572:        if ((status = (*target->isa->put_block)(target, isoc->input_buffer,
                    573:                                                b_read)) != HT_OK) {
                    574:            if (status==HT_WOULD_BLOCK) {
                    575:                if (PROT_TRACE)
                    576:                    fprintf(TDEST, "Read Socket. Stream WOULD BLOCK\n");
                    577:                HTThreadState(isoc->input_file_number, THD_CLR_READ);
                    578:                return HT_WOULD_BLOCK;
                    579:            } else {                                 /* We have a real error */
                    580:                if (PROT_TRACE)
                    581:                    fprintf(TDEST, "Read Socket. Stream ERROR\n");
                    582:                return status;
                    583:            }
                    584:        }
                    585:        isoc->input_pointer = isoc->input_buffer + b_read;
                    586: #if 0
                    587:     }
                    588: #else
                    589: /*     HTThreadState(isoc->input_file_number, THD_SET_READ); */
                    590:     return HT_WOULD_BLOCK;
                    591: #endif
                    592: }
2.2     ! frystyk   593: 
        !           594: 
        !           595: 
        !           596: /*     Push data from an ANSI file descriptor down a stream
        !           597: **     ----------------------------------------------------
        !           598: **
        !           599: **   This routine is responsible for creating and PRESENTING any
        !           600: **   graphic (or other) objects described by the file.
        !           601: **
        !           602: **   Bugs: When we can wait on a file then this should also check interrupts!
        !           603: **
        !           604: **   Returns    HT_LOADED      if finished reading
        !           605: **             HT_ERROR        if error,
        !           606: */
        !           607: PUBLIC int HTFileRead ARGS3(FILE *, fp, HTRequest *, request,
        !           608:                            HTStream *, target)
        !           609: {
        !           610:     HTInputSocket *isoc = request->net_info->isoc;
        !           611:     int b_read;
        !           612:     int status;
        !           613:     if (!fp) {
        !           614:        if (PROT_TRACE) fprintf(TDEST, "Read File... Bad argument\n");
        !           615:        return HT_ERROR;
        !           616:     }
        !           617: 
        !           618:     while(1) {
        !           619:        if ((b_read = fread(isoc->input_buffer, 1, INPUT_BUFFER_SIZE, fp))==0){
        !           620:            if (ferror(fp)) {
        !           621:                if (PROT_TRACE)
        !           622:                    fprintf(TDEST, "Read File... READ ERROR\n");
        !           623:            } else
        !           624:                return HT_LOADED;
        !           625:        }
        !           626:        isoc->input_pointer = isoc->input_buffer;
        !           627:        isoc->input_limit = isoc->input_buffer + b_read;
        !           628:        if (PROT_TRACE)
        !           629:            fprintf(TDEST, "Read File... %d bytes read from file %p\n",
        !           630:                    b_read, fp);
        !           631: 
        !           632:        /* Now push the data down the stream (we use blocking I/O) */
        !           633:        if ((status = (*target->isa->put_block)(target, isoc->input_buffer,
        !           634:                                                b_read)) != HT_OK) {
        !           635:            if (PROT_TRACE)
        !           636:                fprintf(TDEST, "Read File... Stream ERROR\n");
        !           637:            return status;
        !           638:        }
        !           639:        isoc->input_pointer = isoc->input_buffer + b_read;
        !           640:     }
        !           641: }
        !           642: 
        !           643: 

Webmaster