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

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

Webmaster