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

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 */
2.25      frystyk    13: #include "sysdep.h"
2.1       frystyk    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.27    ! frystyk    26: /* A channel occupies exactly one socket */
        !            27: struct _HTChannel {
        !            28:     HTChannel *                next;
        !            29:     SOCKET             sockfd;
        !            30:     char               data [CHANNEL_BUFFER_SIZE];                /* buffer */
        !            31:     char *             write;                          /* Last byte written */
        !            32:     char *             read;                              /* Last byte read */
        !            33:     HTChannelMode      mode;
        !            34:     BOOL               active;
2.2       frystyk    35: };
                     36: 
2.1       frystyk    37: struct _HTStream {
2.25      frystyk    38:     const HTStreamClass *      isa;
2.1       frystyk    39: };
                     40: 
2.27    ! frystyk    41: #define PRIME_TABLE_SIZE       67
        !            42: #define HASH(s)                        ((s) % PRIME_TABLE_SIZE) 
        !            43: 
        !            44: PRIVATE HTChannel * channels [PRIME_TABLE_SIZE];
        !            45: 
2.1       frystyk    46: /* ------------------------------------------------------------------------- */
2.27    ! frystyk    47: /*                             CHANNEL CONTROL                              */
2.1       frystyk    48: /* ------------------------------------------------------------------------- */
2.27    ! frystyk    49: 
        !            50: /*
        !            51: **     Look for a channel object
        !            52: */
        !            53: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
        !            54: {
        !            55:     if (sockfd != INVSOC) {
        !            56:        int hash = HASH(sockfd);
        !            57:        HTChannel *ch=NULL;
        !            58:        for (ch = channels[hash]; ch; ch=ch->next) {
        !            59:            if (ch->sockfd == sockfd) {
        !            60:                if (PROT_TRACE) HTTrace("Channel..... Found %p\n", ch);
        !            61:                return ch;
        !            62:            }
        !            63:        }
        !            64:     }
        !            65:     return NULL;
        !            66: }
        !            67: 
        !            68: /*
        !            69: **     A channel is uniquely identified by a socket.
        !            70: **     If we are not using mux then a channel is simply a normal TCP socket.
        !            71: **     Before creating a new channel, we check to see if it already exists.
        !            72: **     You may get back an already existing channel - you're not promised a
        !            73: **     new one each time.
2.1       frystyk    74: */
2.27    ! frystyk    75: PUBLIC HTChannel * HTChannel_new (SOCKET sockfd, HTChannelMode mode,
        !            76:                                  BOOL active)
        !            77: {
        !            78:     if (sockfd != INVSOC) {
        !            79:        int hash = HASH(sockfd);
        !            80:        HTChannel *ch=NULL, **chp=NULL;
        !            81:        for (chp = &channels[hash]; (ch = *chp) != NULL ; chp = &ch->next) {
        !            82:            if (ch->sockfd == sockfd) break;
        !            83:        }
        !            84:        if (!ch) {
        !            85:            if ((*chp=ch=(HTChannel *) HT_CALLOC(1, sizeof(HTChannel)))==NULL)
        !            86:                HT_OUTOFMEM("HTChannel_new");       
        !            87:            ch->sockfd = sockfd;
        !            88:            ch->write = ch->read = ch->data;
        !            89:            ch->mode = mode;
        !            90:            ch->active = active;
        !            91:            if (PROT_TRACE)
        !            92:                HTTrace("Channel..... Created %p with id %d\n", ch,ch->sockfd);
        !            93:        } else {
        !            94:            if (PROT_TRACE)
        !            95:                HTTrace("Channel..... Found %p with id %d\n", ch, ch->sockfd);
        !            96:            ch->write = ch->read = ch->data;
        !            97:        }
        !            98:        return ch;
        !            99:     }
        !           100:     return NULL;
        !           101: }
        !           102: 
        !           103: PUBLIC BOOL HTChannel_delete (SOCKET sockfd)
        !           104: {
        !           105:     if (sockfd != INVSOC) {
        !           106:        int hash = HASH(sockfd);
        !           107:        HTChannel *ch=NULL, **chp=NULL;
        !           108:        for (chp = &channels[hash]; (ch = *chp) != NULL ; chp = &ch->next) {
        !           109:            if (ch->sockfd == sockfd) {
        !           110: 
        !           111:                /* Walk through and ABORT all remaining sessions */
        !           112: 
        !           113:                if (PROT_TRACE) HTTrace("Channel..... Deleted %p with id %d\n",
        !           114:                                        ch, ch->sockfd);
        !           115:                *chp = ch->next;
        !           116:                HT_FREE(ch);
        !           117:                return YES;
        !           118:            }
        !           119:        }
        !           120:     }
        !           121:     return NO;
        !           122: }
        !           123: 
        !           124: PUBLIC BOOL HTChannel_deleteAll (void)
        !           125: {
        !           126: 
        !           127:     /* @@@ */
2.1       frystyk   128: 
2.27    ! frystyk   129:     return NO;
        !           130: }
2.1       frystyk   131: 
2.27    ! frystyk   132: /*
        !           133: **     Set and Get the mode of a channel. A channel may change mode in the 
        !           134: **     middle of a connection.
2.1       frystyk   135: */
2.27    ! frystyk   136: PUBLIC HTChannelMode HTChannel_mode (SOCKET sockfd, BOOL *active)
        !           137: {
        !           138:     if (sockfd != INVSOC) {
        !           139:        int hash = HASH(sockfd);
        !           140:        HTChannel *ch=NULL, **chp=NULL;
        !           141:        for (chp = &channels[hash]; (ch = *chp) != NULL ; chp = &ch->next) {
        !           142:            if (ch->sockfd == sockfd) {
        !           143:                if (active) *active = ch->active;
        !           144:                return ch->mode;
        !           145:            }
        !           146:        }
        !           147:     }
        !           148:     return HT_CH_UNKNOWN;
        !           149: }
        !           150: 
        !           151: PUBLIC BOOL HTChannel_setMode (SOCKET sockfd, HTChannelMode mode)
2.1       frystyk   152: {
2.27    ! frystyk   153:     if (sockfd != INVSOC) {
        !           154:        int hash = HASH(sockfd);
        !           155:        HTChannel *ch=NULL, **chp=NULL;
        !           156:        for (chp = &channels[hash]; (ch = *chp) != NULL ; chp = &ch->next) {
        !           157:            if (ch->sockfd == sockfd) {
        !           158:                ch->mode = mode;
        !           159:                return YES;
        !           160:            }
        !           161:        }
        !           162:     }
        !           163:     return NO;
2.1       frystyk   164: }
                    165: 
2.27    ! frystyk   166: PUBLIC BOOL HTChannel_addMode (SOCKET sockfd, HTChannelMode mode)
2.12      frystyk   167: {
2.27    ! frystyk   168:     if (sockfd != INVSOC) {
        !           169:        int hash = HASH(sockfd);
        !           170:        HTChannel *ch=NULL, **chp=NULL;
        !           171:        for (chp = &channels[hash]; (ch = *chp) != NULL ; chp = &ch->next) {
        !           172:            if (ch->sockfd == sockfd) {
        !           173:                ch->mode |= mode;
        !           174:                return YES;
        !           175:            }
        !           176:        }
        !           177:     }
        !           178:     return NO;
2.12      frystyk   179: }
                    180: 
2.27    ! frystyk   181: /* ------------------------------------------------------------------------- */
        !           182: /*                             READ ROUTINES                                */
        !           183: /* ------------------------------------------------------------------------- */
        !           184: 
2.1       frystyk   185: /*     Push data from a socket down a stream
                    186: **     -------------------------------------
                    187: **
                    188: **   This routine is responsible for creating and PRESENTING any
                    189: **   graphic (or other) objects described by the file. As this function
2.27    ! frystyk   190: **   max reads a chunk of data on size CHANNEL_BUFFER_SIZE, it can be used
2.1       frystyk   191: **   with both blocking or non-blocking sockets. It will always return to
                    192: **   the event loop, however if we are using blocking I/O then we get a full
                    193: **   buffer read, otherwise we get what's available.
                    194: **
                    195: ** Returns      HT_LOADED      if finished reading
2.3       frystyk   196: **             HT_OK           if OK, but more to read
2.1       frystyk   197: **             HT_ERROR        if error,
2.21      frystyk   198: **                     HT_WOULD_BLOCK  if read or write would block
                    199: **             HT_PAUSE        if stream is paused
2.1       frystyk   200: */
2.27    ! frystyk   201: PUBLIC int HTChannel_readSocket (HTRequest * request, HTNet * net)
2.1       frystyk   202: {
2.27    ! frystyk   203:     HTChannel * ch = HTChannel_find(net->sockfd);
        !           204:     int b_read = ch->read - ch->data;
2.1       frystyk   205:     int status;
                    206: 
2.3       frystyk   207:     /* Read from socket if we got rid of all the data previously read */
2.4       frystyk   208:     do {
2.27    ! frystyk   209:        if (ch->write >= ch->read) {
        !           210:            if ((b_read = NETREAD(net->sockfd, ch->data,
        !           211:                                  CHANNEL_BUFFER_SIZE)) < 0) {
2.1       frystyk   212: #ifdef EAGAIN
2.4       frystyk   213:                if (socerrno==EAGAIN || socerrno==EWOULDBLOCK)      /* POSIX */
2.1       frystyk   214: #else
2.11      frystyk   215:                if (socerrno==EWOULDBLOCK)                            /* BSD */
                    216: #endif 
                    217:                {
                    218:                    if (PROT_TRACE)
2.27    ! frystyk   219:                        HTTrace("Read Socket. WOULD BLOCK soc %d\n",net->sockfd);
        !           220:                    HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
2.11      frystyk   221:                                     net->cbf, net->priority);
                    222:                    return HT_WOULD_BLOCK;
2.21      frystyk   223: #ifdef __svr4__
                    224:     /* 
                    225:     ** In Solaris envirnoment, SIGPOLL is used to signal end of buffer for
                    226:     ** /dev/audio.  If your process is also doing a socket read, it will cause
                    227:     ** an EINTR error.  This error will cause the www library request to 
                    228:     ** terminate prematurly.
                    229:     */
                    230:                 } else if (socerrno == EINTR) {
                    231:                     continue;
                    232: #endif
2.11      frystyk   233:                } else { /* We have a real error */
2.20      frystyk   234:                    HTRequest_addSystemError(request,  ERR_FATAL, socerrno, NO,
                    235:                                             "NETREAD");
2.11      frystyk   236:                    return HT_ERROR;
                    237:                }
2.4       frystyk   238:            } else if (!b_read) {
2.16      frystyk   239:                HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
2.3       frystyk   240:                if (PROT_TRACE)
2.24      eric      241:                    HTTrace("Read Socket. Finished loading socket %d\n",
2.27    ! frystyk   242:                             net->sockfd);
2.16      frystyk   243:                if(cbf)(*cbf)(request,HT_PROG_DONE,HT_MSG_NULL,NULL,NULL,NULL);
2.27    ! frystyk   244:                HTEvent_UnRegister(net->sockfd, FD_READ);
2.21      frystyk   245:                return HT_CLOSED;
2.1       frystyk   246:            }
                    247: 
2.4       frystyk   248:            /* Remember how much we have read from the input socket */
2.27    ! frystyk   249:            ch->write = ch->data;
        !           250:            ch->read = ch->data + b_read;
2.1       frystyk   251: 
                    252: #ifdef NOT_ASCII
2.4       frystyk   253:            {
2.27    ! frystyk   254:                char *p = ch->data;
        !           255:                while (p < ch->read) {
2.4       frystyk   256:                    *p = FROMASCII(*p);
                    257:                    p++;
                    258:                }
2.1       frystyk   259:            }
                    260: #endif
2.27    ! frystyk   261: 
2.3       frystyk   262:            if (PROT_TRACE)
2.24      eric      263:                HTTrace("Read Socket. %d bytes read from socket %d\n",
2.27    ! frystyk   264:                        b_read, net->sockfd);
2.16      frystyk   265: 
2.27    ! frystyk   266:            if (!(ch->mode & HT_CH_INTERLEAVED)) {
        !           267:                HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
        !           268:                net->bytes_read += b_read;
2.16      frystyk   269:                if (cbf)
                    270:                    (*cbf)(request, HT_PROG_READ, HT_MSG_NULL,NULL,NULL,NULL);
                    271:            }
2.4       frystyk   272:        }
2.27    ! frystyk   273: 
2.4       frystyk   274:        /* Now push the data down the stream */
2.27    ! frystyk   275:        if ((status = (*net->target->isa->put_block)(net->target, ch->data,
        !           276:                                                     b_read)) != HT_OK) {
2.4       frystyk   277:            if (status==HT_WOULD_BLOCK) {
                    278:                if (PROT_TRACE)
2.24      eric      279:                    HTTrace("Read Socket. Target WOULD BLOCK\n");
2.27    ! frystyk   280:                HTEvent_UnRegister(net->sockfd, FD_READ);
2.4       frystyk   281:                return HT_WOULD_BLOCK;
2.21      frystyk   282:            } else if (status == HT_PAUSE) {
2.24      eric      283:                if (PROT_TRACE) HTTrace("Read Socket. Target PAUSED\n");
2.27    ! frystyk   284:                HTEvent_UnRegister(net->sockfd, FD_READ);
2.21      frystyk   285:                return HT_PAUSE;
2.5       frystyk   286:            } else if (status>0) {            /* Stream specific return code */
                    287:                if (PROT_TRACE)
2.24      eric      288:                    HTTrace("Read Socket. Target returns %d\n",status);
2.27    ! frystyk   289:                ch->write = ch->data + b_read;
2.5       frystyk   290:                return status;
                    291:            } else {                                 /* We have a real error */
2.4       frystyk   292:                if (PROT_TRACE)
2.24      eric      293:                    HTTrace("Read Socket. Target ERROR\n");
2.4       frystyk   294:                return status;
                    295:            }
2.1       frystyk   296:        }
2.27    ! frystyk   297:        ch->write = ch->data + b_read;
2.20      frystyk   298:     } while (net->preemptive);
2.27    ! frystyk   299:     HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
2.10      frystyk   300:                     net->cbf, net->priority);
2.1       frystyk   301:     return HT_WOULD_BLOCK;
                    302: }
2.2       frystyk   303: 
2.26      eric      304: /*     HTSocket_DLLHackFopen and close
                    305: **     -------------------------------
2.19      frystyk   306: **     Work around the problem that an app can't open a file and have a dll
                    307: **     read from it!
                    308: */
                    309: #ifdef WWW_WIN_DLL
                    310: PUBLIC FILE * HTSocket_DLLHackFopen (const char * filename, const char * mode)
                    311: {
                    312:     return (fopen(filename, mode));
2.26      eric      313: }
                    314: 
                    315: PUBLIC int HTSocket_DLLHackFclose (FILE * file)
                    316: {
                    317:     return (fclose(file));
2.19      frystyk   318: }
                    319: #endif /* WWW_WIN_DLL */
                    320: 
2.2       frystyk   321: /*     Push data from an ANSI file descriptor down a stream
                    322: **     ----------------------------------------------------
                    323: **
                    324: **   This routine is responsible for creating and PRESENTING any
                    325: **   graphic (or other) objects described by the file.
                    326: **
                    327: **   Bugs: When we can wait on a file then this should also check interrupts!
                    328: **
                    329: **   Returns    HT_LOADED      if finished reading
                    330: **             HT_ERROR        if error,
                    331: */
2.27    ! frystyk   332: PUBLIC int HTChannel_readFile (HTRequest * request, HTNet * net, FILE * fp)
2.2       frystyk   333: {
2.27    ! frystyk   334:     HTChannel * ch = HTChannel_find(net->sockfd);
2.2       frystyk   335:     int b_read;
                    336:     int status;
                    337:     if (!fp) {
2.24      eric      338:        if (PROT_TRACE) HTTrace("Read File... Bad argument\n");
2.2       frystyk   339:        return HT_ERROR;
                    340:     }
                    341: 
                    342:     while(1) {
2.27    ! frystyk   343:        if ((b_read = fread(ch->data, 1, CHANNEL_BUFFER_SIZE, fp))==0){
2.2       frystyk   344:            if (ferror(fp)) {
                    345:                if (PROT_TRACE)
2.24      eric      346:                    HTTrace("Read File... READ ERROR\n");
2.2       frystyk   347:            } else
                    348:                return HT_LOADED;
                    349:        }
2.27    ! frystyk   350:        ch->write = ch->data;
        !           351:        ch->read = ch->data + b_read;
2.2       frystyk   352:        if (PROT_TRACE)
2.24      eric      353:            HTTrace("Read File... %d bytes read from file %p\n",
2.2       frystyk   354:                    b_read, fp);
                    355: 
                    356:        /* Now push the data down the stream (we use blocking I/O) */
2.27    ! frystyk   357:        if ((status = (*net->target->isa->put_block)(net->target, ch->data,
        !           358:                                                     b_read)) != HT_OK) {
2.2       frystyk   359:            if (PROT_TRACE)
2.24      eric      360:                HTTrace("Read File... Target ERROR\n");
2.2       frystyk   361:            return status;
                    362:        }
2.27    ! frystyk   363:        ch->write = ch->data + b_read;
2.2       frystyk   364:     }
                    365: }
                    366: 
2.17      frystyk   367: /*     HTLoadSocket
                    368: **     ------------
                    369: **     Given an open socket, this routine loads what ever is on the socket
                    370: **
                    371: ** On entry,
                    372: **      request                This is the request structure
                    373: ** On Exit
                    374: **     returns         HT_ERROR        Error has occured in call back
                    375: **                     HT_OK           Call back was OK
                    376: */
                    377: PUBLIC int HTLoadSocket (SOCKET soc, HTRequest * request, SockOps ops)
                    378: {
2.18      frystyk   379:     HTNet * net = NULL;
                    380:     if (!request) return HT_ERROR;
2.17      frystyk   381:     if (ops == FD_NONE) {
2.18      frystyk   382:        HTNet * me;
2.17      frystyk   383:        if (soc==INVSOC) {
2.24      eric      384:            if (PROT_TRACE) HTTrace("Load Socket. invalid socket\n");
2.17      frystyk   385:            return HT_ERROR;
                    386:        }
2.24      eric      387:        if (PROT_TRACE) HTTrace("Load Socket. Loading socket %d\n",soc);
2.18      frystyk   388:        me = HTNet_new(request, soc);
                    389:        me->sockfd = soc;
                    390:        me->target = request->output_stream;
2.27    ! frystyk   391:        HTChannel_new(net->sockfd, HT_CH_PLAIN, NO);
2.18      frystyk   392:        net = me;
2.17      frystyk   393:     } else if (ops == FD_CLOSE) {                            /* Interrupted */
                    394:        HTNet_delete(request->net, HT_INTERRUPTED);
                    395:        return HT_OK;
2.18      frystyk   396:     } else
                    397:        net = request->net;
                    398:     if (!net) {
2.24      eric      399:        if (PROT_TRACE) HTTrace("Load Socket. invalid argument\n");
2.18      frystyk   400:        return HT_ERROR;
2.17      frystyk   401:     }
                    402: 
                    403:     /* In this load function we only have one state: READ */
                    404:     {
2.27    ! frystyk   405:        int status = HTChannel_readSocket(request, net);
2.17      frystyk   406:        if (status == HT_WOULD_BLOCK)
                    407:            return HT_OK;
2.22      frystyk   408:        else if (status == HT_CLOSED)
2.17      frystyk   409:            HTNet_delete(request->net, HT_LOADED);
                    410:        else
                    411:            HTNet_delete(request->net, HT_ERROR);
                    412:     }
                    413:     return HT_OK;
                    414: }
2.27    ! frystyk   415: 

Webmaster