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

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

Webmaster